Handle m.login.email.identity auth type in /register endpoint

This commit is contained in:
Piotr Kozimor 2021-04-13 21:12:31 +02:00
parent 080ae6a829
commit e8161a9f39
2 changed files with 93 additions and 0 deletions

View file

@ -10,4 +10,5 @@ const (
LoginTypeSharedSecret = "org.matrix.login.shared_secret"
LoginTypeRecaptcha = "m.login.recaptcha"
LoginTypeApplicationService = "m.login.application_service"
LoginTypeEmailIdentity = "m.login.email.identity"
)

View file

@ -150,9 +150,34 @@ type authDict struct {
// Recaptcha
Response string `json:"response"`
// m.login.email.identity and m.login.msisdn
ThreePidCreds *threepidCreds `json:"threepidCreds"`
// TODO: Lots of custom keys depending on the type
}
type threepidCreds struct {
Sid string `json:"sid"`
ClientSecret string `json:"client_secret"`
IdServer string `json:"id_server"`
IdAccessToken string `json:"id_access_token"`
}
func (c *threepidCreds) validate() *jsonerror.MatrixError {
if c.Sid == "" {
return jsonerror.BadJSON("sid field in threepidCreds is required")
}
if c.ClientSecret == "" {
return jsonerror.BadJSON("client_secret in threepidCreds is required")
}
if c.IdServer == "" {
return jsonerror.BadJSON("id_server in threepidCreds is required")
}
if c.IdAccessToken == "" {
return jsonerror.BadJSON("id_access_token in threepidCreds is required")
}
return nil
}
// http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#user-interactive-authentication-api
type userInteractiveResponse struct {
Flows []authtypes.Flow `json:"flows"`
@ -310,6 +335,55 @@ func validateRecaptcha(
return nil
}
func validateEmailIdentity(
ctx context.Context,
cred *threepidCreds,
// cfg *config.ClientAPI,
) *util.JSONResponse {
url := strings.Join([]string{
cred.IdServer,
"_matrix/identity/api/v1/3pid/getValidated3pid",
}, "/")
req, err := http.NewRequestWithContext(ctx, "POST", url, nil)
if err != nil {
return &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: jsonerror.InternalServerError(),
}
}
q := req.URL.Query()
q.Add("client_secret", cred.ClientSecret)
q.Add("sid", cred.Sid)
req.URL.RawQuery = q.Encode()
resp, err := http.DefaultClient.Do(req)
if err != nil {
return &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: jsonerror.Unknown("validate 3pid on indentity server failed"),
}
}
defer resp.Body.Close()
switch resp.StatusCode {
case 404:
return &util.JSONResponse{
Code: http.StatusForbidden,
JSON: jsonerror.Forbidden("provided sid or client_secret not found on identity server"),
}
case 400:
return &util.JSONResponse{
Code: http.StatusForbidden,
JSON: jsonerror.Forbidden("session has not been validated"),
}
case 200:
return nil
default:
return &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: jsonerror.InternalServerError(),
}
}
}
// UserIDIsWithinApplicationServiceNamespace checks to see if a given userID
// 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
@ -659,6 +733,24 @@ func handleRegistrationFlow(
// Add Dummy to the list of completed registration stages
AddCompletedSessionStage(sessionID, authtypes.LoginTypeDummy)
case authtypes.LoginTypeEmailIdentity:
if r.Auth.ThreePidCreds == nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: jsonerror.BadJSON("threepidCreds not found in auth field"),
}
}
if err := r.Auth.ThreePidCreds.validate(); err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: err,
}
}
if err := validateEmailIdentity(req.Context(), r.Auth.ThreePidCreds); err != nil {
return *err
}
AddCompletedSessionStage(sessionID, authtypes.LoginTypeApplicationService)
case "":
// An empty auth type means that we want to fetch the available
// flows. It can also mean that we want to register as an appservice