github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/app/plugin_requests.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "bytes" 8 "fmt" 9 "io/ioutil" 10 "net/http" 11 "path" 12 "path/filepath" 13 "strings" 14 15 "github.com/gorilla/mux" 16 17 "github.com/mattermost/mattermost-server/v5/mlog" 18 "github.com/mattermost/mattermost-server/v5/model" 19 "github.com/mattermost/mattermost-server/v5/plugin" 20 "github.com/mattermost/mattermost-server/v5/utils" 21 ) 22 23 func (a *App) ServePluginRequest(w http.ResponseWriter, r *http.Request) { 24 pluginsEnvironment := a.GetPluginsEnvironment() 25 if pluginsEnvironment == nil { 26 err := model.NewAppError("ServePluginRequest", "app.plugin.disabled.app_error", nil, "Enable plugins to serve plugin requests", http.StatusNotImplemented) 27 a.Log().Error(err.Error()) 28 w.WriteHeader(err.StatusCode) 29 w.Header().Set("Content-Type", "application/json") 30 w.Write([]byte(err.ToJson())) 31 return 32 } 33 34 params := mux.Vars(r) 35 hooks, err := pluginsEnvironment.HooksForPlugin(params["plugin_id"]) 36 if err != nil { 37 a.Log().Error("Access to route for non-existent plugin", 38 mlog.String("missing_plugin_id", params["plugin_id"]), 39 mlog.String("url", r.URL.String()), 40 mlog.Err(err)) 41 http.NotFound(w, r) 42 return 43 } 44 45 a.servePluginRequest(w, r, hooks.ServeHTTP) 46 } 47 48 func (a *App) ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId, destinationPluginId string) { 49 pluginsEnvironment := a.GetPluginsEnvironment() 50 if pluginsEnvironment == nil { 51 err := model.NewAppError("ServeInterPluginRequest", "app.plugin.disabled.app_error", nil, "Plugin environment not found.", http.StatusNotImplemented) 52 a.Log().Error(err.Error()) 53 w.WriteHeader(err.StatusCode) 54 w.Header().Set("Content-Type", "application/json") 55 w.Write([]byte(err.ToJson())) 56 return 57 } 58 59 hooks, err := pluginsEnvironment.HooksForPlugin(destinationPluginId) 60 if err != nil { 61 a.Log().Error("Access to route for non-existent plugin in inter plugin request", 62 mlog.String("source_plugin_id", sourcePluginId), 63 mlog.String("destination_plugin_id", destinationPluginId), 64 mlog.String("url", r.URL.String()), 65 mlog.Err(err), 66 ) 67 http.NotFound(w, r) 68 return 69 } 70 71 context := &plugin.Context{ 72 RequestId: model.NewId(), 73 UserAgent: r.UserAgent(), 74 SourcePluginId: sourcePluginId, 75 } 76 77 hooks.ServeHTTP(context, w, r) 78 } 79 80 // ServePluginPublicRequest serves public plugin files 81 // at the URL http(s)://$SITE_URL/plugins/$PLUGIN_ID/public/{anything} 82 func (a *App) ServePluginPublicRequest(w http.ResponseWriter, r *http.Request) { 83 if strings.HasSuffix(r.URL.Path, "/") { 84 http.NotFound(w, r) 85 return 86 } 87 88 // Should be in the form of /$PLUGIN_ID/public/{anything} by the time we get here 89 vars := mux.Vars(r) 90 pluginID := vars["plugin_id"] 91 92 publicFilesPath, err := a.GetPluginsEnvironment().PublicFilesPath(pluginID) 93 if err != nil { 94 http.NotFound(w, r) 95 return 96 } 97 98 publicFilePath := path.Clean(r.URL.Path) 99 prefix := fmt.Sprintf("/plugins/%s/public/", pluginID) 100 if !strings.HasPrefix(publicFilePath, prefix) { 101 http.NotFound(w, r) 102 return 103 } 104 publicFile := filepath.Join(publicFilesPath, strings.TrimPrefix(publicFilePath, prefix)) 105 http.ServeFile(w, r, publicFile) 106 } 107 108 func (a *App) servePluginRequest(w http.ResponseWriter, r *http.Request, handler func(*plugin.Context, http.ResponseWriter, *http.Request)) { 109 token := "" 110 context := &plugin.Context{ 111 RequestId: model.NewId(), 112 IpAddress: utils.GetIpAddress(r, a.Config().ServiceSettings.TrustedProxyIPHeader), 113 AcceptLanguage: r.Header.Get("Accept-Language"), 114 UserAgent: r.UserAgent(), 115 } 116 cookieAuth := false 117 118 authHeader := r.Header.Get(model.HEADER_AUTH) 119 if strings.HasPrefix(strings.ToUpper(authHeader), model.HEADER_BEARER+" ") { 120 token = authHeader[len(model.HEADER_BEARER)+1:] 121 } else if strings.HasPrefix(strings.ToLower(authHeader), model.HEADER_TOKEN+" ") { 122 token = authHeader[len(model.HEADER_TOKEN)+1:] 123 } else if cookie, _ := r.Cookie(model.SESSION_COOKIE_TOKEN); cookie != nil { 124 token = cookie.Value 125 cookieAuth = true 126 } else { 127 token = r.URL.Query().Get("access_token") 128 } 129 130 r.Header.Del("Mattermost-User-Id") 131 if token != "" { 132 session, err := a.GetSession(token) 133 defer ReturnSessionToPool(session) 134 135 csrfCheckPassed := false 136 137 if err == nil && cookieAuth && r.Method != "GET" { 138 sentToken := "" 139 140 if r.Header.Get(model.HEADER_CSRF_TOKEN) == "" { 141 bodyBytes, _ := ioutil.ReadAll(r.Body) 142 r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) 143 r.ParseForm() 144 sentToken = r.FormValue("csrf") 145 r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) 146 } else { 147 sentToken = r.Header.Get(model.HEADER_CSRF_TOKEN) 148 } 149 150 expectedToken := session.GetCSRF() 151 152 if sentToken == expectedToken { 153 csrfCheckPassed = true 154 } 155 156 // ToDo(DSchalla) 2019/01/04: Remove after deprecation period and only allow CSRF Header (MM-13657) 157 if r.Header.Get(model.HEADER_REQUESTED_WITH) == model.HEADER_REQUESTED_WITH_XML && !csrfCheckPassed { 158 csrfErrorMessage := "CSRF Check failed for request - Please migrate your plugin to either send a CSRF Header or Form Field, XMLHttpRequest is deprecated" 159 sid := "" 160 userID := "" 161 162 if session != nil { 163 sid = session.Id 164 userID = session.UserId 165 } 166 167 fields := []mlog.Field{ 168 mlog.String("path", r.URL.Path), 169 mlog.String("ip", r.RemoteAddr), 170 mlog.String("session_id", sid), 171 mlog.String("user_id", userID), 172 } 173 174 if *a.Config().ServiceSettings.ExperimentalStrictCSRFEnforcement { 175 a.Log().Warn(csrfErrorMessage, fields...) 176 } else { 177 a.Log().Debug(csrfErrorMessage, fields...) 178 csrfCheckPassed = true 179 } 180 } 181 } else { 182 csrfCheckPassed = true 183 } 184 185 if (session != nil && session.Id != "") && err == nil && csrfCheckPassed { 186 r.Header.Set("Mattermost-User-Id", session.UserId) 187 context.SessionId = session.Id 188 } 189 } 190 191 cookies := r.Cookies() 192 r.Header.Del("Cookie") 193 for _, c := range cookies { 194 if c.Name != model.SESSION_COOKIE_TOKEN { 195 r.AddCookie(c) 196 } 197 } 198 r.Header.Del(model.HEADER_AUTH) 199 r.Header.Del("Referer") 200 201 params := mux.Vars(r) 202 203 subpath, _ := utils.GetSubpathFromConfig(a.Config()) 204 205 newQuery := r.URL.Query() 206 newQuery.Del("access_token") 207 r.URL.RawQuery = newQuery.Encode() 208 r.URL.Path = strings.TrimPrefix(r.URL.Path, path.Join(subpath, "plugins", params["plugin_id"])) 209 210 handler(context, w, r) 211 }