Server is responding to Recaptcha requests.

* We now send back the correct params for each registration stage

Signed-off-by: Andrew (anoa) <anoa@openmailbox.org>
This commit is contained in:
Andrew (anoa) 2017-11-22 17:22:48 -08:00
parent 98aa6e5421
commit 4cc6b9f8de
No known key found for this signature in database
GPG key ID: 174BEAB009FD176D
3 changed files with 45 additions and 18 deletions

View file

@ -14,7 +14,7 @@
package authtypes package authtypes
// AuthFlow represents one possible way that the client can authenticate a request. // Flow represents one possible way that the client can authenticate a request.
// http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#user-interactive-authentication-api // http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#user-interactive-authentication-api
type Flow struct { type Flow struct {
Stages []LoginType `json:"stages"` Stages []LoginType `json:"stages"`

View file

@ -101,9 +101,13 @@ type legacyRegisterRequest struct {
Mac gomatrixserverlib.HexString `json:"mac"` Mac gomatrixserverlib.HexString `json:"mac"`
} }
func newUserInteractiveResponse(sessionID string, fs []authtypes.Flow) userInteractiveResponse { func newUserInteractiveResponse(
sessionID string,
fs []authtypes.Flow,
params map[string]interface{},
) userInteractiveResponse {
return userInteractiveResponse{ return userInteractiveResponse{
fs, sessions[sessionID], make(map[string]interface{}), sessionID, fs, sessions[sessionID], params, sessionID,
} }
} }
@ -164,7 +168,6 @@ func validatePassword(password string) *util.JSONResponse {
// validateRecaptcha returns an error response if the captcha response is invalid // validateRecaptcha returns an error response if the captcha response is invalid
func validateRecaptcha( func validateRecaptcha(
req *http.Request,
cfg *config.Dendrite, cfg *config.Dendrite,
response string, response string,
clientip string, clientip string,
@ -193,7 +196,7 @@ func validateRecaptcha(
} }
// Close the request once we're finishing reading from it // Close the request once we're finishing reading from it
defer resp.Body.Close() // noline: errcheck defer resp.Body.Close() // nolint: errcheck
// Grab the body of the response from the captcha server // Grab the body of the response from the captcha server
var r recaptchaResponse var r recaptchaResponse
@ -250,7 +253,8 @@ func Register(
if r.Auth.Type == "" { if r.Auth.Type == "" {
return util.JSONResponse{ return util.JSONResponse{
Code: 401, Code: 401,
JSON: newUserInteractiveResponse(sessionID, cfg.Derived.Flows), JSON: newUserInteractiveResponse(sessionID,
cfg.Derived.Flows, cfg.Derived.Params),
} }
} }
@ -268,6 +272,19 @@ func Register(
"session_id": r.Auth.Session, "session_id": r.Auth.Session,
}).Info("Processing registration request") }).Info("Processing registration request")
return handleRegistrationFlow(req, r, sessionID, cfg, accountDB, deviceDB)
}
// handleRegistrationFlow will direct and complete registration flow stages
// that the client has requested.
func handleRegistrationFlow(
req *http.Request,
r registerRequest,
sessionID string,
cfg *config.Dendrite,
accountDB *accounts.Database,
deviceDB *devices.Database,
) util.JSONResponse {
// TODO: Shared secret registration (create new user scripts) // TODO: Shared secret registration (create new user scripts)
// TODO: AS API registration // TODO: AS API registration
// TODO: Enable registration config flag // TODO: Enable registration config flag
@ -290,7 +307,8 @@ func Register(
}).Info("Submitting recaptcha response") }).Info("Submitting recaptcha response")
// Check given captcha response // Check given captcha response
if resErr = validateRecaptcha(req, cfg, r.Auth.Response, req.RemoteAddr); resErr != nil { resErr := validateRecaptcha(cfg, r.Auth.Response, req.RemoteAddr)
if resErr != nil {
return *resErr return *resErr
} }
@ -340,7 +358,8 @@ func Register(
// Return the flows and those that have been completed. // Return the flows and those that have been completed.
return util.JSONResponse{ return util.JSONResponse{
Code: 401, Code: 401,
JSON: newUserInteractiveResponse(sessionID, cfg.Derived.Flows), JSON: newUserInteractiveResponse(sessionID,
cfg.Derived.Flows, cfg.Derived.Params),
} }
} }
@ -503,11 +522,11 @@ const (
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
) )
var src = rand.NewSource(time.Now().UnixNano())
// RandString returns a random string of characters with a given length. // RandString returns a random string of characters with a given length.
// Do note that it is not thread-safe in its current form. // Do note that it is not thread-safe in its current form.
// https://stackoverflow.com/a/31832326 // https://stackoverflow.com/a/31832326
var src = rand.NewSource(time.Now().UnixNano())
func RandString(n int) string { func RandString(n int) string {
b := make([]byte, n) b := make([]byte, n)
@ -536,20 +555,20 @@ func checkFlowsEqual(aFlow, bFlow authtypes.Flow) bool {
return false return false
} }
a_copy := make([]string, len(a)) aCopy := make([]string, len(a))
b_copy := make([]string, len(b)) bCopy := make([]string, len(b))
for loginType := range a { for loginType := range a {
a_copy = append(a_copy, string(loginType)) aCopy = append(aCopy, string(loginType))
} }
for loginType := range b { for loginType := range b {
b_copy = append(b_copy, string(loginType)) bCopy = append(bCopy, string(loginType))
} }
sort.Strings(a_copy) sort.Strings(aCopy)
sort.Strings(b_copy) sort.Strings(bCopy)
return reflect.DeepEqual(a_copy, b_copy) return reflect.DeepEqual(aCopy, bCopy)
} }
type availableResponse struct { type availableResponse struct {

View file

@ -208,6 +208,10 @@ type Dendrite struct {
// Flows for registration. As long as they given flows only relies on config file options, // Flows for registration. As long as they given flows only relies on config file options,
// we can generate them on startup and store them until needed // we can generate them on startup and store them until needed
Flows []authtypes.Flow `json:"flows"` Flows []authtypes.Flow `json:"flows"`
// Params for registration. Data that is returned to the client while registering and
// that which is necessary to complete certain registration flow stages
Params map[string]interface{} `json:"params"`
} }
} }
@ -335,10 +339,14 @@ func loadConfig(
// the config file // the config file
func (config *Dendrite) derive() { func (config *Dendrite) derive() {
// Determine registrations flows based off config values // Determine registrations flows based off config values
config.Derived.Params = make(map[string]interface{})
// TODO: Add email auth type // TODO: Add email auth type
// TODO: Add MSISDN auth type // TODO: Add MSISDN auth type
if config.Matrix.RecaptchaEnabled { if config.Matrix.RecaptchaEnabled {
config.Derived.Params[authtypes.LoginTypeRecaptcha] = map[string]string{"public_key": config.Matrix.RecaptchaPublicKey}
config.Derived.Flows = append(config.Derived.Flows, config.Derived.Flows = append(config.Derived.Flows,
authtypes.Flow{[]authtypes.LoginType{authtypes.LoginTypeRecaptcha}}) authtypes.Flow{[]authtypes.LoginType{authtypes.LoginTypeRecaptcha}})
} else { } else {