aboutsummaryrefslogtreecommitdiff
path: root/userapi
diff options
context:
space:
mode:
authorKegsay <kegan@matrix.org>2020-07-31 14:40:45 +0100
committerGitHub <noreply@github.com>2020-07-31 14:40:45 +0100
commitb5cb1d153458ad83abdfbebed7405dd9da159cb8 (patch)
tree5b5a35ff4805c2f2f071c6c51d095492406db750 /userapi
parenta7e67e65a8662387f1a5ba6860698743f9dbd60f (diff)
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
Diffstat (limited to 'userapi')
-rw-r--r--userapi/api/api.go11
-rw-r--r--userapi/internal/api.go42
-rw-r--r--userapi/inthttp/client.go9
-rw-r--r--userapi/inthttp/server.go13
-rw-r--r--userapi/storage/devices/sqlite3/devices_table.go3
5 files changed, 72 insertions, 6 deletions
diff --git a/userapi/api/api.go b/userapi/api/api.go
index 5c964c4f..84338dbf 100644
--- a/userapi/api/api.go
+++ b/userapi/api/api.go
@@ -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
diff --git a/userapi/internal/api.go b/userapi/internal/api.go
index 738023dd..b9d18822 100644
--- a/userapi/internal/api.go
+++ b/userapi/internal/api.go
@@ -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 {
diff --git a/userapi/inthttp/client.go b/userapi/inthttp/client.go
index 47e2110f..5f4df0eb 100644
--- a/userapi/inthttp/client.go
+++ b/userapi/inthttp/client.go
@@ -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,
diff --git a/userapi/inthttp/server.go b/userapi/inthttp/server.go
index ebb9bf4e..47d68ff2 100644
--- a/userapi/inthttp/server.go
+++ b/userapi/inthttp/server.go
@@ -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{}
diff --git a/userapi/storage/devices/sqlite3/devices_table.go b/userapi/storage/devices/sqlite3/devices_table.go
index efe6f927..9b535aab 100644
--- a/userapi/storage/devices/sqlite3/devices_table.go
+++ b/userapi/storage/devices/sqlite3/devices_table.go
@@ -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
})