mirror of
https://github.com/hoernschen/dendrite.git
synced 2025-07-30 04:52:46 +00:00
Fix edge cases around device lists (#1234)
* Fix New users appear in /keys/changes * Create blank device keys when logging in on a new device * Add PerformDeviceUpdate and fix a few bugs - Correct device deletion query on sqlite - Return no keys on /keys/query rather than an empty key * Unbreak sqlite properly * Use a real DB for currentstateserver integration tests * Race fix
This commit is contained in:
parent
a7e67e65a8
commit
b5cb1d1534
13 changed files with 167 additions and 52 deletions
|
@ -28,6 +28,7 @@ type UserInternalAPI interface {
|
|||
PerformAccountCreation(ctx context.Context, req *PerformAccountCreationRequest, res *PerformAccountCreationResponse) error
|
||||
PerformDeviceCreation(ctx context.Context, req *PerformDeviceCreationRequest, res *PerformDeviceCreationResponse) error
|
||||
PerformDeviceDeletion(ctx context.Context, req *PerformDeviceDeletionRequest, res *PerformDeviceDeletionResponse) error
|
||||
PerformDeviceUpdate(ctx context.Context, req *PerformDeviceUpdateRequest, res *PerformDeviceUpdateResponse) error
|
||||
QueryProfile(ctx context.Context, req *QueryProfileRequest, res *QueryProfileResponse) error
|
||||
QueryAccessToken(ctx context.Context, req *QueryAccessTokenRequest, res *QueryAccessTokenResponse) error
|
||||
QueryDevices(ctx context.Context, req *QueryDevicesRequest, res *QueryDevicesResponse) error
|
||||
|
@ -48,6 +49,16 @@ type InputAccountDataRequest struct {
|
|||
type InputAccountDataResponse struct {
|
||||
}
|
||||
|
||||
type PerformDeviceUpdateRequest struct {
|
||||
RequestingUserID string
|
||||
DeviceID string
|
||||
DisplayName *string
|
||||
}
|
||||
type PerformDeviceUpdateResponse struct {
|
||||
DeviceExists bool
|
||||
Forbidden bool
|
||||
}
|
||||
|
||||
type PerformDeviceDeletionRequest struct {
|
||||
UserID string
|
||||
// The devices to delete
|
||||
|
|
|
@ -104,7 +104,8 @@ func (a *UserInternalAPI) PerformDeviceCreation(ctx context.Context, req *api.Pe
|
|||
}
|
||||
res.DeviceCreated = true
|
||||
res.Device = dev
|
||||
return nil
|
||||
// create empty device keys and upload them to trigger device list changes
|
||||
return a.deviceListUpdate(dev.UserID, []string{dev.ID})
|
||||
}
|
||||
|
||||
func (a *UserInternalAPI) PerformDeviceDeletion(ctx context.Context, req *api.PerformDeviceDeletionRequest, res *api.PerformDeviceDeletionResponse) error {
|
||||
|
@ -121,10 +122,14 @@ func (a *UserInternalAPI) PerformDeviceDeletion(ctx context.Context, req *api.Pe
|
|||
return err
|
||||
}
|
||||
// create empty device keys and upload them to delete what was once there and trigger device list changes
|
||||
deviceKeys := make([]keyapi.DeviceKeys, len(req.DeviceIDs))
|
||||
for i, did := range req.DeviceIDs {
|
||||
return a.deviceListUpdate(req.UserID, req.DeviceIDs)
|
||||
}
|
||||
|
||||
func (a *UserInternalAPI) deviceListUpdate(userID string, deviceIDs []string) error {
|
||||
deviceKeys := make([]keyapi.DeviceKeys, len(deviceIDs))
|
||||
for i, did := range deviceIDs {
|
||||
deviceKeys[i] = keyapi.DeviceKeys{
|
||||
UserID: req.UserID,
|
||||
UserID: userID,
|
||||
DeviceID: did,
|
||||
KeyJSON: nil,
|
||||
}
|
||||
|
@ -143,6 +148,35 @@ func (a *UserInternalAPI) PerformDeviceDeletion(ctx context.Context, req *api.Pe
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *UserInternalAPI) PerformDeviceUpdate(ctx context.Context, req *api.PerformDeviceUpdateRequest, res *api.PerformDeviceUpdateResponse) error {
|
||||
localpart, _, err := gomatrixserverlib.SplitID('@', req.RequestingUserID)
|
||||
if err != nil {
|
||||
util.GetLogger(ctx).WithError(err).Error("gomatrixserverlib.SplitID failed")
|
||||
return err
|
||||
}
|
||||
dev, err := a.DeviceDB.GetDeviceByID(ctx, localpart, req.DeviceID)
|
||||
if err == sql.ErrNoRows {
|
||||
res.DeviceExists = false
|
||||
return nil
|
||||
} else if err != nil {
|
||||
util.GetLogger(ctx).WithError(err).Error("deviceDB.GetDeviceByID failed")
|
||||
return err
|
||||
}
|
||||
res.DeviceExists = true
|
||||
|
||||
if dev.UserID != req.RequestingUserID {
|
||||
res.Forbidden = true
|
||||
return nil
|
||||
}
|
||||
|
||||
err = a.DeviceDB.UpdateDevice(ctx, localpart, req.DeviceID, req.DisplayName)
|
||||
if err != nil {
|
||||
util.GetLogger(ctx).WithError(err).Error("deviceDB.UpdateDevice failed")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *UserInternalAPI) QueryProfile(ctx context.Context, req *api.QueryProfileRequest, res *api.QueryProfileResponse) error {
|
||||
local, domain, err := gomatrixserverlib.SplitID('@', req.UserID)
|
||||
if err != nil {
|
||||
|
|
|
@ -31,6 +31,7 @@ const (
|
|||
PerformDeviceCreationPath = "/userapi/performDeviceCreation"
|
||||
PerformAccountCreationPath = "/userapi/performAccountCreation"
|
||||
PerformDeviceDeletionPath = "/userapi/performDeviceDeletion"
|
||||
PerformDeviceUpdatePath = "/userapi/performDeviceUpdate"
|
||||
|
||||
QueryProfilePath = "/userapi/queryProfile"
|
||||
QueryAccessTokenPath = "/userapi/queryAccessToken"
|
||||
|
@ -104,6 +105,14 @@ func (h *httpUserInternalAPI) PerformDeviceDeletion(
|
|||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
}
|
||||
|
||||
func (h *httpUserInternalAPI) PerformDeviceUpdate(ctx context.Context, req *api.PerformDeviceUpdateRequest, res *api.PerformDeviceUpdateResponse) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformDeviceUpdate")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.apiURL + PerformDeviceUpdatePath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res)
|
||||
}
|
||||
|
||||
func (h *httpUserInternalAPI) QueryProfile(
|
||||
ctx context.Context,
|
||||
request *api.QueryProfileRequest,
|
||||
|
|
|
@ -52,6 +52,19 @@ func AddRoutes(internalAPIMux *mux.Router, s api.UserInternalAPI) {
|
|||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
)
|
||||
internalAPIMux.Handle(PerformDeviceUpdatePath,
|
||||
httputil.MakeInternalAPI("performDeviceUpdate", func(req *http.Request) util.JSONResponse {
|
||||
request := api.PerformDeviceUpdateRequest{}
|
||||
response := api.PerformDeviceUpdateResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
if err := s.PerformDeviceUpdate(req.Context(), &request, &response); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
)
|
||||
internalAPIMux.Handle(PerformDeviceDeletionPath,
|
||||
httputil.MakeInternalAPI("performDeviceDeletion", func(req *http.Request) util.JSONResponse {
|
||||
request := api.PerformDeviceDeletionRequest{}
|
||||
|
|
|
@ -174,7 +174,7 @@ func (s *devicesStatements) deleteDevice(
|
|||
func (s *devicesStatements) deleteDevices(
|
||||
ctx context.Context, txn *sql.Tx, localpart string, devices []string,
|
||||
) error {
|
||||
orig := strings.Replace(deleteDevicesSQL, "($1)", sqlutil.QueryVariadic(len(devices)), 1)
|
||||
orig := strings.Replace(deleteDevicesSQL, "($2)", sqlutil.QueryVariadicOffset(len(devices), 1), 1)
|
||||
prep, err := s.db.Prepare(orig)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -186,7 +186,6 @@ func (s *devicesStatements) deleteDevices(
|
|||
for i, v := range devices {
|
||||
params[i+1] = v
|
||||
}
|
||||
params = append(params, params...)
|
||||
_, err = stmt.ExecContext(ctx, params...)
|
||||
return err
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue