WIP: Handle /register/email/requestToken

This commit is contained in:
Piotr Kozimor 2021-04-16 08:49:12 +02:00
parent 02efc3eed2
commit f6456468c0
3 changed files with 133 additions and 6 deletions

View file

@ -16,9 +16,11 @@
package routing
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha1"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
@ -143,6 +145,15 @@ type registerRequest struct {
Type authtypes.LoginType `json:"type"`
}
type registerEmailRequestTokenRequest struct {
ClientSecret string `json:"client_secret"`
Email string `json:"email"`
IdAccessToken string `json:"id_access_token,omitempty"`
IdServer string `json:"id_server,omitempty"`
NextLink string `json:"next_link"`
SendAttempt int `json:"send_attempt"`
}
type authDict struct {
Type authtypes.LoginType `json:"type"`
Session string `json:"session"`
@ -214,6 +225,11 @@ type recaptchaResponse struct {
ErrorCodes []int `json:"error-codes"`
}
// server response for
type registerEmailRequestTokenResponse struct {
Sid string `json:"sid"`
}
// validateUsername returns an error response if the username is invalid
func validateUsername(username string) *util.JSONResponse {
// https://github.com/matrix-org/synapse/blob/v0.20.0/synapse/rest/client/v2_alpha/register.py#L161
@ -340,10 +356,13 @@ func validateEmailIdentity(
cred *threepidCreds,
// cfg *config.ClientAPI,
) *util.JSONResponse {
url := strings.Join([]string{
cred.IdServer,
"_matrix/identity/api/v1/3pid/getValidated3pid",
}, "/")
url := fmt.Sprintf(
"https://%s/_matrix/identity/v2/3pid/getValidated3pid",
cred.IdServer)
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
req, err := http.NewRequestWithContext(ctx, "POST", url, nil)
if err != nil {
return &util.JSONResponse{
@ -355,11 +374,13 @@ func validateEmailIdentity(
q.Add("client_secret", cred.ClientSecret)
q.Add("sid", cred.Sid)
req.URL.RawQuery = q.Encode()
resp, err := http.DefaultClient.Do(req)
req.Header.Add("Authorization", "Bearer swordfish")
resp, err := client.Do(req)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("failed conecting to identity server")
return &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: jsonerror.Unknown("validate 3pid on indentity server failed"),
JSON: jsonerror.Unknown("failed conecting to identity server"),
}
}
defer resp.Body.Close()
@ -1084,3 +1105,101 @@ func RegisterAvailable(
},
}
}
func RegisterEmailRequestToken(
req *http.Request,
cfg *config.ClientAPI,
) util.JSONResponse {
var r registerEmailRequestTokenRequest
resErr := httputil.UnmarshalJSONRequest(req, &r)
if resErr != nil {
return *resErr
}
idServer := r.IdServer
idAccessToken := r.IdAccessToken
// if !isServerTrusted(idServer, cfg.Matrix.TrustedIDServers) {
// return util.JSONResponse{
// Code: http.StatusForbidden,
// JSON: jsonerror.NotTrusted(fmt.Sprintf("identity server %s is not trusted.", idServer)),
// }
// }
r.IdServer = ""
r.IdAccessToken = ""
return requestEmailTokenFromIdServer(req.Context(), idServer, idAccessToken, &r)
}
func isServerTrusted(s string, trusted []string) bool {
for _, t := range trusted {
if s == t {
return true
}
}
return false
}
func requestEmailTokenFromIdServer(
ctx context.Context,
idServer, idAccessToken string,
r *registerEmailRequestTokenRequest,
) util.JSONResponse {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
b := bytes.Buffer{}
enc := json.NewEncoder(&b)
err := enc.Encode(r)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("enc.Encode failed")
return jsonerror.InternalServerError()
}
idReq, err := http.NewRequest(
// ctx,
"POST",
fmt.Sprintf(
"https://%s/_matrix/identity/v2/validate/email/requestToken",
idServer),
&b)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("http.NewRequestWithContext failed")
return jsonerror.InternalServerError()
}
idReq.Header.Add("Authentication", "Bearer "+idAccessToken)
idReq.Header.Add("Content-Type", "application/json")
// util.GetLogger(ctx).WithError(err).Warnf("buffer %s")
// io.Copy(os.Stdout, &b)
idResp, err := client.Do(idReq)
if err != nil {
util.GetLogger(ctx).WithError(err).Errorf("failed to connect to identity server %s", idServer)
return jsonerror.InternalServerError()
}
defer idResp.Body.Close()
decoder := json.NewDecoder(idResp.Body)
if idResp.StatusCode < 300 {
var resp registerEmailRequestTokenResponse
decoder.Decode(&resp)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("failed to decode identity server response body")
return jsonerror.InternalServerError()
}
return util.JSONResponse{
Code: idResp.StatusCode,
JSON: resp,
}
}
if idResp.StatusCode < 500 {
var resp jsonerror.MatrixError
decoder.Decode(&resp)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("failed to decode identity server response body")
return jsonerror.InternalServerError()
}
return util.JSONResponse{
Code: idResp.StatusCode,
JSON: resp,
}
}
// We got 500 status code from indentity server
util.GetLogger(ctx).WithError(err).Error("identity server internal server error")
return jsonerror.InternalServerError()
}

View file

@ -312,6 +312,13 @@ func Setup(
return RegisterAvailable(req, cfg, accountDB)
})).Methods(http.MethodGet, http.MethodOptions)
r0mux.Handle("/register/email/requestToken", httputil.MakeExternalAPI("registerEmailRequestToken", func(req *http.Request) util.JSONResponse {
if r := rateLimits.rateLimit(req); r != nil {
return *r
}
return RegisterEmailRequestToken(req, cfg)
})).Methods(http.MethodPost, http.MethodOptions)
r0mux.Handle("/directory/room/{roomAlias}",
httputil.MakeExternalAPI("directory_room", func(req *http.Request) util.JSONResponse {
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))

View file

@ -71,6 +71,7 @@ GET /rooms/:room_id/joined_members fetches my membership
Both GET and PUT work
POST /rooms/:room_id/read_markers can create read marker
User signups are forbidden from starting with '_'
Can register using an email address via identity server
Request to logout with invalid an access token is rejected
Request to logout without an access token is rejected
Room creation reports m.room.create to myself