From f290e722c30aaf88484a952ad79da0ea1a3584e7 Mon Sep 17 00:00:00 2001 From: PiotrKozimor <37144818+PiotrKozimor@users.noreply.github.com> Date: Mon, 24 May 2021 12:02:04 +0200 Subject: [PATCH] Cherry-pick Feature/login with email (#2) --- clientapi/auth/password.go | 38 +++++++++++++++++++++++++++----- clientapi/routing/login.go | 1 + clientapi/threepid/threepid.go | 6 +++-- dendrite-config.yaml | 3 +++ setup/config/config_clientapi.go | 2 ++ 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/clientapi/auth/password.go b/clientapi/auth/password.go index a66e2fe76..7882804dd 100644 --- a/clientapi/auth/password.go +++ b/clientapi/auth/password.go @@ -22,6 +22,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/userutil" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/userapi/api" + "github.com/matrix-org/dendrite/userapi/storage/accounts" "github.com/matrix-org/util" ) @@ -29,13 +30,16 @@ type GetAccountByPassword func(ctx context.Context, localpart, password string) type PasswordRequest struct { Login + Address string `json:"address"` Password string `json:"password"` + Medium string `json:"medium"` } // LoginTypePassword implements https://matrix.org/docs/spec/client_server/r0.6.1#password-based type LoginTypePassword struct { GetAccountByPassword GetAccountByPassword Config *config.ClientAPI + AccountDB accounts.Database } func (t *LoginTypePassword) Name() string { @@ -48,14 +52,36 @@ func (t *LoginTypePassword) Request() interface{} { func (t *LoginTypePassword) Login(ctx context.Context, req interface{}) (*Login, *util.JSONResponse) { r := req.(*PasswordRequest) - username := r.Username() - if username == "" { - return nil, &util.JSONResponse{ - Code: http.StatusUnauthorized, - JSON: jsonerror.BadJSON("A username must be supplied."), + var username string + var localpart string + var err error + username = r.Username() + if username != "" { + localpart, err = userutil.ParseUsernameParam(username, &t.Config.Matrix.ServerName) + } else { + if r.Medium == "email" { + if r.Address != "" { + localpart, err = t.AccountDB.GetLocalpartForThreePID(ctx, r.Address, "email") + if localpart == "" { + return nil, &util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden("email or password was incorrect, or the account does not exist"), + } + } + r.Login.User = localpart + } else { + return nil, &util.JSONResponse{ + Code: http.StatusUnauthorized, + JSON: jsonerror.BadJSON("'address' must be supplied."), + } + } + } else { + return nil, &util.JSONResponse{ + Code: http.StatusUnauthorized, + JSON: jsonerror.BadJSON("'user' must be supplied."), + } } } - localpart, err := userutil.ParseUsernameParam(username, &t.Config.Matrix.ServerName) if err != nil { return nil, &util.JSONResponse{ Code: http.StatusUnauthorized, diff --git a/clientapi/routing/login.go b/clientapi/routing/login.go index 589efe0b2..79d63e4db 100644 --- a/clientapi/routing/login.go +++ b/clientapi/routing/login.go @@ -68,6 +68,7 @@ func Login( typePassword := auth.LoginTypePassword{ GetAccountByPassword: accountDB.GetAccountByPassword, Config: cfg, + AccountDB: accountDB, } r := typePassword.Request() resErr := httputil.UnmarshalJSONRequest(req, r) diff --git a/clientapi/threepid/threepid.go b/clientapi/threepid/threepid.go index 1e64e3034..2d51dae38 100644 --- a/clientapi/threepid/threepid.go +++ b/clientapi/threepid/threepid.go @@ -33,11 +33,12 @@ type EmailAssociationRequest struct { Secret string `json:"client_secret"` Email string `json:"email"` SendAttempt int `json:"send_attempt"` + NextLink string `json:"next_link"` } // EmailAssociationCheckRequest represents the request defined at https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-account-3pid type EmailAssociationCheckRequest struct { - Creds Credentials `json:"threePidCreds"` + Creds Credentials `json:"three_pid_creds"` Bind bool `json:"bind"` } @@ -66,6 +67,7 @@ func CreateSession( data.Add("client_secret", req.Secret) data.Add("email", req.Email) data.Add("send_attempt", strconv.Itoa(req.SendAttempt)) + data.Add("next_link", req.NextLink) request, err := http.NewRequest(http.MethodPost, postURL, strings.NewReader(data.Encode())) if err != nil { @@ -81,7 +83,7 @@ func CreateSession( // Error if the status isn't OK if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("could not create a session on the server %s", req.IDServer) + return "", fmt.Errorf("Could not create a session on the server %s, got status code: %d", req.IDServer, resp.StatusCode) } // Extract the SID from the response and return it diff --git a/dendrite-config.yaml b/dendrite-config.yaml index 5aaf0fac5..f8880fdba 100644 --- a/dendrite-config.yaml +++ b/dendrite-config.yaml @@ -170,6 +170,9 @@ client_api: turn_username: "" turn_password: "" + # Whether login by email is enabled . + email_login: true + # Settings for rate-limited endpoints. Rate limiting will kick in after the # threshold number of "slots" have been taken by requests from a specific # host. Each "slot" will be released after the cooloff time in milliseconds. diff --git a/setup/config/config_clientapi.go b/setup/config/config_clientapi.go index c7cb9c33e..f9bdbbd64 100644 --- a/setup/config/config_clientapi.go +++ b/setup/config/config_clientapi.go @@ -12,6 +12,8 @@ type ClientAPI struct { InternalAPI InternalAPIOptions `yaml:"internal_api"` ExternalAPI ExternalAPIOptions `yaml:"external_api"` + EmailLogin bool `yaml:"email_login"` + // If set disables new users from registering (except via shared // secrets) RegistrationDisabled bool `yaml:"registration_disabled"`