// 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
`
// 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"),
}
}