mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-16 11:23:11 -06:00
Merge branch 'add-register-fallback' of github.com:Trion129/dendrite into add-register-fallback
This commit is contained in:
commit
f852c99eee
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 Vector Creations Ltd
|
// Copyright 2019 Parminder Singh <parmsingh129@gmail.com>
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
|
@ -25,8 +25,8 @@ import (
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RecaptchaTemplate is template for recaptcha auth
|
// recaptchaTemplate is an HTML webpage template for recaptcha auth
|
||||||
const RecaptchaTemplate = `
|
const recaptchaTemplate = `
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Authentication</title>
|
<title>Authentication</title>
|
||||||
|
|
@ -35,7 +35,6 @@ const RecaptchaTemplate = `
|
||||||
<script src="https://www.google.com/recaptcha/api.js"
|
<script src="https://www.google.com/recaptcha/api.js"
|
||||||
async defer></script>
|
async defer></script>
|
||||||
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
|
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
|
||||||
<link rel="stylesheet" href="/_matrix/static/client/register/style.css">
|
|
||||||
<script>
|
<script>
|
||||||
function captchaDone() {
|
function captchaDone() {
|
||||||
$('#registrationForm').submit();
|
$('#registrationForm').submit();
|
||||||
|
|
@ -43,7 +42,7 @@ function captchaDone() {
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<form id="registrationForm" method="post" action="{{.MyUrl}}">
|
<form id="registrationForm" method="post" action="{{.myUrl}}">
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
Hello! We need to prevent computer programs and other automated
|
Hello! We need to prevent computer programs and other automated
|
||||||
|
|
@ -52,9 +51,9 @@ function captchaDone() {
|
||||||
<p>
|
<p>
|
||||||
Please verify that you're not a robot.
|
Please verify that you're not a robot.
|
||||||
</p>
|
</p>
|
||||||
<input type="hidden" name="session" value="{{.Session}}" />
|
<input type="hidden" name="session" value="{{.session}}" />
|
||||||
<div class="g-recaptcha"
|
<div class="g-recaptcha"
|
||||||
data-sitekey="{{.SiteKey}}"
|
data-sitekey="{{.siteKey}}"
|
||||||
data-callback="captchaDone">
|
data-callback="captchaDone">
|
||||||
</div>
|
</div>
|
||||||
<noscript>
|
<noscript>
|
||||||
|
|
@ -67,8 +66,9 @@ function captchaDone() {
|
||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
|
|
||||||
// SuccessTemplate is template for success page after auth flow ends
|
// successTemplate is an HTML template presented to the user after successful
|
||||||
const SuccessTemplate = `
|
// recaptcha completion
|
||||||
|
const successTemplate = `
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Success!</title>
|
<title>Success!</title>
|
||||||
|
|
@ -79,7 +79,7 @@ const SuccessTemplate = `
|
||||||
if (window.onAuthDone) {
|
if (window.onAuthDone) {
|
||||||
window.onAuthDone();
|
window.onAuthDone();
|
||||||
} else if (window.opener && window.opener.postMessage) {
|
} else if (window.opener && window.opener.postMessage) {
|
||||||
window.opener.postMessage("authDone", "*");
|
window.opener.postMessage("authDone", "*");
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
@ -92,8 +92,8 @@ if (window.onAuthDone) {
|
||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
|
|
||||||
// ServeTemplate fills data in template and serves it in http.ResponseWriter
|
// serveTemplate fills template data and serves it using http.ResponseWriter
|
||||||
func ServeTemplate(w http.ResponseWriter, templateHTML string, data map[string]string) {
|
func serveTemplate(w http.ResponseWriter, templateHTML string, data map[string]string) {
|
||||||
t := template.Must(template.New("response").Parse(templateHTML))
|
t := template.Must(template.New("response").Parse(templateHTML))
|
||||||
if err := t.Execute(w, data); err != nil {
|
if err := t.Execute(w, data); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
@ -108,48 +108,51 @@ func AuthFallback(
|
||||||
sessionID := req.URL.Query().Get("session")
|
sessionID := req.URL.Query().Get("session")
|
||||||
|
|
||||||
if sessionID == "" {
|
if sessionID == "" {
|
||||||
_, err := w.Write([]byte("Session ID not provided"))
|
return writeErrorMessage(w, req,
|
||||||
if err != nil {
|
"Session ID not provided",
|
||||||
res := httputil.LogThenError(req, err)
|
http.StatusBadRequest,
|
||||||
return &res
|
)
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ServeRecaptcha := func() {
|
serveRecaptcha := func() {
|
||||||
data := map[string]string{
|
data := map[string]string{
|
||||||
"MyUrl": req.URL.String(),
|
"myUrl": req.URL.String(),
|
||||||
"Session": sessionID,
|
"session": sessionID,
|
||||||
"SiteKey": cfg.Matrix.RecaptchaPublicKey,
|
"siteKey": cfg.Matrix.RecaptchaPublicKey,
|
||||||
}
|
}
|
||||||
ServeTemplate(w, RecaptchaTemplate, data)
|
serveTemplate(w, recaptchaTemplate, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
ServeSuccess := func() {
|
serveSuccess := func() {
|
||||||
data := map[string]string{}
|
data := map[string]string{}
|
||||||
ServeTemplate(w, SuccessTemplate, data)
|
serveTemplate(w, successTemplate, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Method == "GET" {
|
if req.Method == http.MethodGet {
|
||||||
// Handle Recaptcha
|
// Handle Recaptcha
|
||||||
if authType == authtypes.LoginTypeRecaptcha {
|
if authType == authtypes.LoginTypeRecaptcha {
|
||||||
if cfg.Matrix.RecaptchaPublicKey == "" {
|
if cfg.Matrix.RecaptchaEnabled {
|
||||||
_, err := w.Write([]byte("This Homeserver doesn't have a recaptcha public key"))
|
if cfg.Matrix.RecaptchaPublicKey == "" {
|
||||||
if err != nil {
|
return writeErrorMessage(w, req,
|
||||||
res := httputil.LogThenError(req, err)
|
"This Homeserver doesn't have a recaptcha public key",
|
||||||
return &res
|
http.StatusInternalServerError,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return nil
|
} else {
|
||||||
|
return writeErrorMessage(w, req,
|
||||||
|
"Recaptcha login is disabled on this Homeserver",
|
||||||
|
http.StatusBadRequest,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ServeRecaptcha()
|
serveRecaptcha()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &util.JSONResponse{
|
return &util.JSONResponse{
|
||||||
Code: 404,
|
Code: http.StatusNotFound,
|
||||||
JSON: jsonerror.NotFound("Unknown auth stage type"),
|
JSON: jsonerror.NotFound("Unknown auth stage type"),
|
||||||
}
|
}
|
||||||
} else if req.Method == "POST" {
|
} else if req.Method == http.MethodPost {
|
||||||
clientIP := req.RemoteAddr
|
clientIP := req.RemoteAddr
|
||||||
err := req.ParseForm()
|
err := req.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -159,18 +162,32 @@ func AuthFallback(
|
||||||
|
|
||||||
response := req.Form.Get("g-recaptcha-response")
|
response := req.Form.Get("g-recaptcha-response")
|
||||||
if err := validateRecaptcha(&cfg, response, clientIP); err != nil {
|
if err := validateRecaptcha(&cfg, response, clientIP); err != nil {
|
||||||
ServeRecaptcha()
|
util.GetLogger(req.Context()).Error(err)
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success. Add recaptcha as a completed login flow
|
// Success. Add recaptcha as a completed login flow
|
||||||
AddCompletedSessionStage(sessionID, authtypes.LoginTypeRecaptcha)
|
AddCompletedSessionStage(sessionID, authtypes.LoginTypeRecaptcha)
|
||||||
|
|
||||||
ServeSuccess()
|
serveSuccess()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &util.JSONResponse{
|
return &util.JSONResponse{
|
||||||
Code: 405,
|
Code: http.StatusMethodNotAllowed,
|
||||||
JSON: jsonerror.NotFound("Bad method"),
|
JSON: jsonerror.NotFound("Bad method"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteErrorMessage writes an error response with the given header and message
|
||||||
|
func writeErrorMessage(
|
||||||
|
w http.ResponseWriter, req *http.Request,
|
||||||
|
message string, header int,
|
||||||
|
) *util.JSONResponse {
|
||||||
|
w.WriteHeader(header)
|
||||||
|
_, err := w.Write([]byte(message))
|
||||||
|
if err != nil {
|
||||||
|
res := httputil.LogThenError(req, err)
|
||||||
|
return &res
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,17 +83,6 @@ func (d sessionsDict) GetCompletedStages(sessionID string) []authtypes.LoginType
|
||||||
return make([]authtypes.LoginType, 0)
|
return make([]authtypes.LoginType, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCompletedStage records that a session has completed an auth stage.
|
|
||||||
func (d *sessionsDict) AddCompletedStage(sessionID string, stage authtypes.LoginType) {
|
|
||||||
// Return if the stage is already present
|
|
||||||
for _, completedStage := range d.GetCompletedStages(sessionID) {
|
|
||||||
if completedStage == stage {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.sessions[sessionID] = append(d.GetCompletedStages(sessionID), stage)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSessionsDict() *sessionsDict {
|
func newSessionsDict() *sessionsDict {
|
||||||
return &sessionsDict{
|
return &sessionsDict{
|
||||||
sessions: make(map[string][]authtypes.LoginType),
|
sessions: make(map[string][]authtypes.LoginType),
|
||||||
|
|
|
||||||
|
|
@ -246,11 +246,11 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
r0mux.Handle("/auth/{authType}/fallback/web",
|
r0mux.Handle("/auth/{authType}/fallback/web",
|
||||||
common.MakeHTMLAPI("authfallback", func(w http.ResponseWriter, req *http.Request) *util.JSONResponse {
|
common.MakeHTMLAPI("auth_fallback", func(w http.ResponseWriter, req *http.Request) *util.JSONResponse {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
return AuthFallback(w, req, vars["authType"], cfg)
|
return AuthFallback(w, req, vars["authType"], cfg)
|
||||||
}),
|
}),
|
||||||
).Methods("GET", "POST", "OPTIONS")
|
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
r0mux.Handle("/pushrules/",
|
r0mux.Handle("/pushrules/",
|
||||||
common.MakeExternalAPI("push_rules", func(req *http.Request) util.JSONResponse {
|
common.MakeExternalAPI("push_rules", func(req *http.Request) util.JSONResponse {
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func MakeExternalAPI(metricsName string, f func(*http.Request) util.JSONResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeHTMLAPI adds Span metrics to the HTML Handler function
|
// MakeHTMLAPI adds Span metrics to the HTML Handler function
|
||||||
// This is used to serve HTML template
|
// This is used to serve HTML alongside JSON error messages
|
||||||
func MakeHTMLAPI(metricsName string, f func(http.ResponseWriter, *http.Request) *util.JSONResponse) http.Handler {
|
func MakeHTMLAPI(metricsName string, f func(http.ResponseWriter, *http.Request) *util.JSONResponse) http.Handler {
|
||||||
withSpan := func(w http.ResponseWriter, req *http.Request) {
|
withSpan := func(w http.ResponseWriter, req *http.Request) {
|
||||||
span := opentracing.StartSpan(metricsName)
|
span := opentracing.StartSpan(metricsName)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue