Add handlers for 3PIDs management

This commit is contained in:
Brendan Abolivier 2017-08-31 15:43:21 +01:00
parent 8b85932d87
commit de8411d3fd
No known key found for this signature in database
GPG key ID: 8EF1500759F70623
2 changed files with 183 additions and 8 deletions

View file

@ -0,0 +1,162 @@
// Copyright 2017 Vector Creations Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readers
import (
"net/http"
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
"github.com/matrix-org/dendrite/clientapi/httputil"
"github.com/matrix-org/dendrite/clientapi/jsonerror"
"github.com/matrix-org/dendrite/clientapi/threepid"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util"
)
type reqTokenResponse struct {
SID string `json:"sid"`
}
type threePIDsResponse struct {
ThreePIDs []threePID `json:"threepids"`
}
type threePID struct {
Medium string `json:"medium"`
Address string `json:"address"`
}
// Request3PIDToken implements:
// POST /account/3pid/email/requestToken
// POST /register/email/requestToken
func Request3PIDToken(req *http.Request, accountDB *accounts.Database) util.JSONResponse {
var body threepid.EmailAssociationRequest
if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil {
return *reqErr
}
var resp reqTokenResponse
var err error
// Check if the 3PID is already in use locally
localpart, err := accountDB.GetLocalpartForThreePID(body.Email)
if err != nil {
return httputil.LogThenError(req, err)
}
if len(localpart) > 0 {
return util.JSONResponse{
Code: 400,
JSON: jsonerror.MatrixError{
ErrCode: "M_THREEPID_IN_USE",
Err: accounts.Err3PIDInUse.Error(),
},
}
}
resp.SID, err = threepid.CreateSession(body)
if err != nil {
return httputil.LogThenError(req, err)
}
return util.JSONResponse{
Code: 200,
JSON: resp,
}
}
// CheckAndSave3PIDAssociation implements POST /account/3pid
func CheckAndSave3PIDAssociation(
req *http.Request, accountDB *accounts.Database, device *authtypes.Device,
) util.JSONResponse {
var body threepid.EmailAssociationCheckRequest
if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil {
return *reqErr
}
verified, address, err := threepid.CheckAssociation(body.Creds)
if err != nil {
return httputil.LogThenError(req, err)
}
if !verified {
return util.JSONResponse{
Code: 400,
JSON: jsonerror.MatrixError{
ErrCode: "M_THREEPID_AUTH_FAILED",
Err: "Failed to auth 3pid",
},
}
}
localpart, _, err := gomatrixserverlib.SplitID('@', device.UserID)
if err != nil {
return httputil.LogThenError(req, err)
}
if err = accountDB.SaveThreePIDAssociation(address, localpart); err != nil {
return httputil.LogThenError(req, err)
}
return util.JSONResponse{
Code: 200,
JSON: struct{}{},
}
}
// GetAssociated3PIDs implements GET /account/3pid
func GetAssociated3PIDs(
req *http.Request, accountDB *accounts.Database, device *authtypes.Device,
) util.JSONResponse {
localpart, _, err := gomatrixserverlib.SplitID('@', device.UserID)
if err != nil {
return httputil.LogThenError(req, err)
}
threepids, err := accountDB.GetThreePIDsForLocalpart(localpart)
if err != nil {
return httputil.LogThenError(req, err)
}
var resp threePIDsResponse
for address, medium := range threepids {
tpid := threePID{Medium: medium, Address: address}
resp.ThreePIDs = append(resp.ThreePIDs, tpid)
}
return util.JSONResponse{
Code: 200,
JSON: resp,
}
}
// Forget3PID implements POST /account/3pid/delete
func Forget3PID(req *http.Request, accountDB *accounts.Database) util.JSONResponse {
var body threePID
if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil {
return *reqErr
}
if err := accountDB.RemoveThreePIDAssociation(body.Address); err != nil {
return httputil.LogThenError(req, err)
}
return util.JSONResponse{
Code: 200,
JSON: struct{}{},
}
}

View file

@ -234,15 +234,28 @@ func Setup(
// PUT requests, so we need to allow this method
r0mux.Handle("/account/3pid",
common.MakeAPI("account_3pid", func(req *http.Request) util.JSONResponse {
// TODO: Get 3pid data for user ID
res := json.RawMessage(`{"threepids":[]}`)
return util.JSONResponse{
Code: 200,
JSON: &res,
}
common.MakeAuthAPI("account_3pid", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
return readers.GetAssociated3PIDs(req, accountDB, device)
}),
)
).Methods("GET")
r0mux.Handle("/account/3pid",
common.MakeAuthAPI("account_3pid", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
return readers.CheckAndSave3PIDAssociation(req, accountDB, device)
}),
).Methods("POST", "OPTIONS")
unstableMux.Handle("/account/3pid/delete",
common.MakeAuthAPI("account_3pid", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
return readers.Forget3PID(req, accountDB)
}),
).Methods("POST", "OPTIONS")
r0mux.Handle("/{path:(?:account/3pid|register)}/email/requestToken",
common.MakeAPI("account_3pid_request_token", func(req *http.Request) util.JSONResponse {
return readers.Request3PIDToken(req, accountDB)
}),
).Methods("POST", "OPTIONS")
// Riot logs get flooded unless this is handled
r0mux.Handle("/presence/{userID}/status",