// Copyright 2017 Vector Creations Ltd // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package routing import ( "html/template" "net/http" "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/common/config" "github.com/matrix-org/util" ) // RecaptchaTemplate is template for recaptcha auth const RecaptchaTemplate = ` Authentication

Hello! We need to prevent computer programs and other automated things from creating accounts on this server.

Please verify that you're not a robot.

` // SuccessTemplate is template for success page after auth flow ends const SuccessTemplate = ` Success!

Thank you!

You may now close this window and return to the application.

` // ServeTemplate fills data in template and serves it in http.ResponseWriter func ServeTemplate(w http.ResponseWriter, templateHTML string, data map[string]string) { t := template.Must(template.New("response").Parse(templateHTML)) if err := t.Execute(w, data); err != nil { panic(err) } } // AuthFallback implements GET on /auth/{authType}/fallback/web?session={sessionID} func AuthFallback( w http.ResponseWriter, req *http.Request, authType string, cfg config.Dendrite, ) *util.JSONResponse { sessionID := req.URL.Query().Get("session") if sessionID == "" { _, err := w.Write([]byte("Session ID not provided")) if err != nil { res := httputil.LogThenError(req, err) return &res } return nil } ServeRecaptcha := func() { data := map[string]string{ "MyUrl": req.URL.String(), "Session": sessionID, "SiteKey": cfg.Matrix.RecaptchaPublicKey, } ServeTemplate(w, RecaptchaTemplate, data) } ServeSuccess := func() { data := map[string]string{} ServeTemplate(w, SuccessTemplate, data) } if req.Method == "GET" { // Handle Recaptcha if authType == authtypes.LoginTypeRecaptcha { if cfg.Matrix.RecaptchaPublicKey == "" { _, err := w.Write([]byte("This Homeserver doesn't have a recaptcha public key")) if err != nil { res := httputil.LogThenError(req, err) return &res } return nil } ServeRecaptcha() return nil } return &util.JSONResponse{ Code: 404, JSON: jsonerror.NotFound("Unknown auth stage type"), } } else if req.Method == "POST" { clientIP := req.RemoteAddr err := req.ParseForm() if err != nil { res := httputil.LogThenError(req, err) return &res } response := req.Form.Get("g-recaptcha-response") if err := validateRecaptcha(&cfg, response, clientIP); err != nil { ServeRecaptcha() return nil } // Success. Add recaptcha as a completed login flow AddCompletedSessionStage(sessionID, authtypes.LoginTypeRecaptcha) ServeSuccess() return nil } return &util.JSONResponse{ Code: 405, JSON: jsonerror.NotFound("Bad method"), } }