mirror of
https://github.com/matrix-org/dendrite.git
synced 2024-11-26 08:11:55 -06:00
added token-authorized registration
This commit is contained in:
parent
3e62b986d1
commit
618f3eaff6
|
@ -11,4 +11,5 @@ const (
|
||||||
LoginTypeRecaptcha = "m.login.recaptcha"
|
LoginTypeRecaptcha = "m.login.recaptcha"
|
||||||
LoginTypeApplicationService = "m.login.application_service"
|
LoginTypeApplicationService = "m.login.application_service"
|
||||||
LoginTypeToken = "m.login.token"
|
LoginTypeToken = "m.login.token"
|
||||||
|
LoginTypeRegistrationToken = "m.login.registration_token"
|
||||||
)
|
)
|
||||||
|
|
|
@ -233,6 +233,9 @@ type authDict struct {
|
||||||
|
|
||||||
// Recaptcha
|
// Recaptcha
|
||||||
Response string `json:"response"`
|
Response string `json:"response"`
|
||||||
|
|
||||||
|
// Registration token
|
||||||
|
Token string `json:"token"`
|
||||||
// TODO: Lots of custom keys depending on the type
|
// TODO: Lots of custom keys depending on the type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,9 +275,12 @@ type recaptchaResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidCaptcha = errors.New("invalid captcha response")
|
ErrInvalidCaptcha = errors.New("invalid captcha response")
|
||||||
ErrMissingResponse = errors.New("captcha response is required")
|
ErrMissingResponse = errors.New("captcha response is required")
|
||||||
ErrCaptchaDisabled = errors.New("captcha registration is disabled")
|
ErrCaptchaDisabled = errors.New("captcha registration is disabled")
|
||||||
|
ErrRegistrationTokenDisabled = errors.New("token registration is disabled")
|
||||||
|
ErrMissingToken = errors.New("registration token is required")
|
||||||
|
ErrInvalidToken = errors.New("invalid registration token")
|
||||||
)
|
)
|
||||||
|
|
||||||
// validateRecaptcha returns an error response if the captcha response is invalid
|
// validateRecaptcha returns an error response if the captcha response is invalid
|
||||||
|
@ -326,6 +332,34 @@ func validateRecaptcha(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateToken returns an error response if the token is invalid
|
||||||
|
func validateToken(
|
||||||
|
req *http.Request,
|
||||||
|
userAPI userapi.ClientUserAPI,
|
||||||
|
cfg *config.ClientAPI,
|
||||||
|
token string,
|
||||||
|
) error {
|
||||||
|
if !cfg.RegistrationRequiresToken {
|
||||||
|
return ErrRegistrationTokenDisabled
|
||||||
|
}
|
||||||
|
|
||||||
|
if token == "" {
|
||||||
|
return ErrMissingToken
|
||||||
|
}
|
||||||
|
|
||||||
|
exists, err := userAPI.ValidateRegistrationToken(req.Context(), token)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return ErrInvalidToken
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// UserIDIsWithinApplicationServiceNamespace checks to see if a given userID
|
// UserIDIsWithinApplicationServiceNamespace checks to see if a given userID
|
||||||
// falls within any of the namespaces of a given Application Service. If no
|
// falls within any of the namespaces of a given Application Service. If no
|
||||||
// Application Service is given, it will check to see if it matches any
|
// Application Service is given, it will check to see if it matches any
|
||||||
|
@ -733,6 +767,25 @@ func handleRegistrationFlow(
|
||||||
// Add Recaptcha to the list of completed registration stages
|
// Add Recaptcha to the list of completed registration stages
|
||||||
sessions.addCompletedSessionStage(sessionID, authtypes.LoginTypeRecaptcha)
|
sessions.addCompletedSessionStage(sessionID, authtypes.LoginTypeRecaptcha)
|
||||||
|
|
||||||
|
case authtypes.LoginTypeRegistrationToken:
|
||||||
|
// Check given token response
|
||||||
|
err := validateToken(req, userAPI, cfg, r.Auth.Token)
|
||||||
|
switch err {
|
||||||
|
case ErrRegistrationTokenDisabled:
|
||||||
|
return util.JSONResponse{Code: http.StatusForbidden, JSON: spec.Unknown(err.Error())}
|
||||||
|
case ErrMissingToken:
|
||||||
|
return util.JSONResponse{Code: http.StatusBadRequest, JSON: spec.BadJSON(err.Error())}
|
||||||
|
case ErrInvalidToken:
|
||||||
|
return util.JSONResponse{Code: http.StatusUnauthorized, JSON: spec.BadJSON(err.Error())}
|
||||||
|
case nil:
|
||||||
|
default:
|
||||||
|
util.GetLogger(req.Context()).WithError(err).Error("failed to validate token")
|
||||||
|
return util.JSONResponse{Code: http.StatusInternalServerError, JSON: spec.InternalServerError{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add RegistrationToken to the list of completed registration stages
|
||||||
|
sessions.addCompletedSessionStage(sessionID, authtypes.LoginTypeRegistrationToken)
|
||||||
|
|
||||||
case authtypes.LoginTypeDummy:
|
case authtypes.LoginTypeDummy:
|
||||||
// there is nothing to do
|
// there is nothing to do
|
||||||
// Add Dummy to the list of completed registration stages
|
// Add Dummy to the list of completed registration stages
|
||||||
|
|
|
@ -291,6 +291,10 @@ func (config *Dendrite) Derive() error {
|
||||||
config.Derived.Registration.Flows = []authtypes.Flow{
|
config.Derived.Registration.Flows = []authtypes.Flow{
|
||||||
{Stages: []authtypes.LoginType{authtypes.LoginTypeRecaptcha}},
|
{Stages: []authtypes.LoginType{authtypes.LoginTypeRecaptcha}},
|
||||||
}
|
}
|
||||||
|
} else if config.ClientAPI.RegistrationRequiresToken {
|
||||||
|
config.Derived.Registration.Flows = []authtypes.Flow{
|
||||||
|
{Stages: []authtypes.LoginType{authtypes.LoginTypeRegistrationToken}},
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
config.Derived.Registration.Flows = []authtypes.Flow{
|
config.Derived.Registration.Flows = []authtypes.Flow{
|
||||||
{Stages: []authtypes.LoginType{authtypes.LoginTypeDummy}},
|
{Stages: []authtypes.LoginType{authtypes.LoginTypeDummy}},
|
||||||
|
|
|
@ -117,6 +117,7 @@ type ClientUserAPI interface {
|
||||||
QueryLocalpartForThreePID(ctx context.Context, req *QueryLocalpartForThreePIDRequest, res *QueryLocalpartForThreePIDResponse) error
|
QueryLocalpartForThreePID(ctx context.Context, req *QueryLocalpartForThreePIDRequest, res *QueryLocalpartForThreePIDResponse) error
|
||||||
PerformForgetThreePID(ctx context.Context, req *PerformForgetThreePIDRequest, res *struct{}) error
|
PerformForgetThreePID(ctx context.Context, req *PerformForgetThreePIDRequest, res *struct{}) error
|
||||||
PerformSaveThreePIDAssociation(ctx context.Context, req *PerformSaveThreePIDAssociationRequest, res *struct{}) error
|
PerformSaveThreePIDAssociation(ctx context.Context, req *PerformSaveThreePIDAssociationRequest, res *struct{}) error
|
||||||
|
ValidateRegistrationToken(ctx context.Context, registrationToken string) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeyBackupAPI interface {
|
type KeyBackupAPI interface {
|
||||||
|
|
|
@ -978,3 +978,11 @@ func (a *UserInternalAPI) PerformSaveThreePIDAssociation(ctx context.Context, re
|
||||||
}
|
}
|
||||||
|
|
||||||
const pushRulesAccountDataType = "m.push_rules"
|
const pushRulesAccountDataType = "m.push_rules"
|
||||||
|
|
||||||
|
func (a *UserInternalAPI) ValidateRegistrationToken(ctx context.Context, registrationToken string) (bool, error) {
|
||||||
|
exists, err := a.DB.RegistrationTokenExists(ctx, registrationToken)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return exists, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue