Cherry-pick Feature/login with email (#2)

This commit is contained in:
PiotrKozimor 2021-05-24 12:02:04 +02:00 committed by Piotr Kozimor
parent 1fbed4194a
commit f290e722c3
5 changed files with 42 additions and 8 deletions

View file

@ -22,6 +22,7 @@ import (
"github.com/matrix-org/dendrite/clientapi/userutil" "github.com/matrix-org/dendrite/clientapi/userutil"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/dendrite/userapi/storage/accounts"
"github.com/matrix-org/util" "github.com/matrix-org/util"
) )
@ -29,13 +30,16 @@ type GetAccountByPassword func(ctx context.Context, localpart, password string)
type PasswordRequest struct { type PasswordRequest struct {
Login Login
Address string `json:"address"`
Password string `json:"password"` Password string `json:"password"`
Medium string `json:"medium"`
} }
// LoginTypePassword implements https://matrix.org/docs/spec/client_server/r0.6.1#password-based // LoginTypePassword implements https://matrix.org/docs/spec/client_server/r0.6.1#password-based
type LoginTypePassword struct { type LoginTypePassword struct {
GetAccountByPassword GetAccountByPassword GetAccountByPassword GetAccountByPassword
Config *config.ClientAPI Config *config.ClientAPI
AccountDB accounts.Database
} }
func (t *LoginTypePassword) Name() string { 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) { func (t *LoginTypePassword) Login(ctx context.Context, req interface{}) (*Login, *util.JSONResponse) {
r := req.(*PasswordRequest) r := req.(*PasswordRequest)
username := r.Username() var username string
if username == "" { 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{ return nil, &util.JSONResponse{
Code: http.StatusUnauthorized, Code: http.StatusUnauthorized,
JSON: jsonerror.BadJSON("A username must be supplied."), 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 { if err != nil {
return nil, &util.JSONResponse{ return nil, &util.JSONResponse{
Code: http.StatusUnauthorized, Code: http.StatusUnauthorized,

View file

@ -68,6 +68,7 @@ func Login(
typePassword := auth.LoginTypePassword{ typePassword := auth.LoginTypePassword{
GetAccountByPassword: accountDB.GetAccountByPassword, GetAccountByPassword: accountDB.GetAccountByPassword,
Config: cfg, Config: cfg,
AccountDB: accountDB,
} }
r := typePassword.Request() r := typePassword.Request()
resErr := httputil.UnmarshalJSONRequest(req, r) resErr := httputil.UnmarshalJSONRequest(req, r)

View file

@ -33,11 +33,12 @@ type EmailAssociationRequest struct {
Secret string `json:"client_secret"` Secret string `json:"client_secret"`
Email string `json:"email"` Email string `json:"email"`
SendAttempt int `json:"send_attempt"` 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 // 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 { type EmailAssociationCheckRequest struct {
Creds Credentials `json:"threePidCreds"` Creds Credentials `json:"three_pid_creds"`
Bind bool `json:"bind"` Bind bool `json:"bind"`
} }
@ -66,6 +67,7 @@ func CreateSession(
data.Add("client_secret", req.Secret) data.Add("client_secret", req.Secret)
data.Add("email", req.Email) data.Add("email", req.Email)
data.Add("send_attempt", strconv.Itoa(req.SendAttempt)) 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())) request, err := http.NewRequest(http.MethodPost, postURL, strings.NewReader(data.Encode()))
if err != nil { if err != nil {
@ -81,7 +83,7 @@ func CreateSession(
// Error if the status isn't OK // Error if the status isn't OK
if resp.StatusCode != http.StatusOK { 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 // Extract the SID from the response and return it

View file

@ -170,6 +170,9 @@ client_api:
turn_username: "" turn_username: ""
turn_password: "" turn_password: ""
# Whether login by email is enabled .
email_login: true
# Settings for rate-limited endpoints. Rate limiting will kick in after the # Settings for rate-limited endpoints. Rate limiting will kick in after the
# threshold number of "slots" have been taken by requests from a specific # threshold number of "slots" have been taken by requests from a specific
# host. Each "slot" will be released after the cooloff time in milliseconds. # host. Each "slot" will be released after the cooloff time in milliseconds.

View file

@ -12,6 +12,8 @@ type ClientAPI struct {
InternalAPI InternalAPIOptions `yaml:"internal_api"` InternalAPI InternalAPIOptions `yaml:"internal_api"`
ExternalAPI ExternalAPIOptions `yaml:"external_api"` ExternalAPI ExternalAPIOptions `yaml:"external_api"`
EmailLogin bool `yaml:"email_login"`
// If set disables new users from registering (except via shared // If set disables new users from registering (except via shared
// secrets) // secrets)
RegistrationDisabled bool `yaml:"registration_disabled"` RegistrationDisabled bool `yaml:"registration_disabled"`