aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTill <2353100+S7evinK@users.noreply.github.com>2022-09-30 10:32:31 +0200
committerGitHub <noreply@github.com>2022-09-30 09:32:31 +0100
commit9005e5b4a87c0bdd4f19b1dbf46f3093ac07e727 (patch)
tree9c0d1d4b22b2bed21ca6f839c688512c55cad7b4
parente45ba35e979f2f8af1e75f5f16158973b790436b (diff)
Add `/_dendrite/admin/refreshDevices/{userID}` (#2746)
Allows to immediately query `/devices/{userID}` over federation to (hopefully) resolve E2EE issues.
-rw-r--r--clientapi/routing/admin.go51
-rw-r--r--clientapi/routing/routing.go8
-rw-r--r--docs/administration/4_adminapi.md5
-rw-r--r--keyserver/api/api.go1
-rw-r--r--keyserver/internal/internal.go13
5 files changed, 64 insertions, 14 deletions
diff --git a/clientapi/routing/admin.go b/clientapi/routing/admin.go
index 5089d7c3..89c269f1 100644
--- a/clientapi/routing/admin.go
+++ b/clientapi/routing/admin.go
@@ -2,20 +2,23 @@ package routing
import (
"encoding/json"
+ "fmt"
"net/http"
"time"
"github.com/gorilla/mux"
+ "github.com/matrix-org/gomatrixserverlib"
+ "github.com/matrix-org/util"
+ "github.com/nats-io/nats.go"
+ "github.com/sirupsen/logrus"
+
"github.com/matrix-org/dendrite/clientapi/jsonerror"
"github.com/matrix-org/dendrite/internal/httputil"
+ "github.com/matrix-org/dendrite/keyserver/api"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/jetstream"
userapi "github.com/matrix-org/dendrite/userapi/api"
- "github.com/matrix-org/gomatrixserverlib"
- "github.com/matrix-org/util"
- "github.com/nats-io/nats.go"
- "github.com/sirupsen/logrus"
)
func AdminEvacuateRoom(req *http.Request, cfg *config.ClientAPI, device *userapi.Device, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse {
@@ -144,12 +147,6 @@ func AdminResetPassword(req *http.Request, cfg *config.ClientAPI, device *userap
}
func AdminReindex(req *http.Request, cfg *config.ClientAPI, device *userapi.Device, natsClient *nats.Conn) util.JSONResponse {
- if device.AccountType != userapi.AccountTypeAdmin {
- return util.JSONResponse{
- Code: http.StatusForbidden,
- JSON: jsonerror.Forbidden("This API can only be used by admin users."),
- }
- }
_, err := natsClient.RequestMsg(nats.NewMsg(cfg.Matrix.JetStream.Prefixed(jetstream.InputFulltextReindex)), time.Second*10)
if err != nil {
logrus.WithError(err).Error("failed to publish nats message")
@@ -160,3 +157,37 @@ func AdminReindex(req *http.Request, cfg *config.ClientAPI, device *userapi.Devi
JSON: struct{}{},
}
}
+
+func AdminMarkAsStale(req *http.Request, cfg *config.ClientAPI, keyAPI api.ClientKeyAPI) util.JSONResponse {
+ vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
+ if err != nil {
+ return util.ErrorResponse(err)
+ }
+ userID := vars["userID"]
+
+ _, domain, err := gomatrixserverlib.SplitID('@', userID)
+ if err != nil {
+ return util.MessageResponse(http.StatusBadRequest, err.Error())
+ }
+ if domain == cfg.Matrix.ServerName {
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: jsonerror.InvalidParam("Can not mark local device list as stale"),
+ }
+ }
+
+ err = keyAPI.PerformMarkAsStaleIfNeeded(req.Context(), &api.PerformMarkAsStaleRequest{
+ UserID: userID,
+ Domain: domain,
+ }, &struct{}{})
+ if err != nil {
+ return util.JSONResponse{
+ Code: http.StatusInternalServerError,
+ JSON: jsonerror.Unknown(fmt.Sprintf("Failed to mark device list as stale: %s", err)),
+ }
+ }
+ return util.JSONResponse{
+ Code: http.StatusOK,
+ JSON: struct{}{},
+ }
+}
diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go
index 9c1f8f72..7d1c434c 100644
--- a/clientapi/routing/routing.go
+++ b/clientapi/routing/routing.go
@@ -163,11 +163,17 @@ func Setup(
).Methods(http.MethodPost, http.MethodOptions)
dendriteAdminRouter.Handle("/admin/fulltext/reindex",
- httputil.MakeAuthAPI("admin_fultext_reindex", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
+ httputil.MakeAdminAPI("admin_fultext_reindex", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return AdminReindex(req, cfg, device, natsClient)
}),
).Methods(http.MethodGet, http.MethodOptions)
+ dendriteAdminRouter.Handle("/admin/refreshDevices/{userID}",
+ httputil.MakeAdminAPI("admin_refresh_devices", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
+ return AdminMarkAsStale(req, cfg, keyAPI)
+ }),
+ ).Methods(http.MethodPost, http.MethodOptions)
+
// server notifications
if cfg.Matrix.ServerNotices.Enabled {
logrus.Info("Enabling server notices at /_synapse/admin/v1/send_server_notice")
diff --git a/docs/administration/4_adminapi.md b/docs/administration/4_adminapi.md
index 1712bb1b..56e19a8b 100644
--- a/docs/administration/4_adminapi.md
+++ b/docs/administration/4_adminapi.md
@@ -62,6 +62,11 @@ the full user ID is `@alice:domain.com` then the local part is `alice`.
This endpoint instructs Dendrite to reindex all searchable events (`m.room.message`, `m.room.topic` and `m.room.name`). An empty JSON body will be returned immediately.
Indexing is done in the background, the server logs every 1000 events (or below) when they are being indexed. Once reindexing is done, you'll see something along the lines `Indexed 69586 events in 53.68223182s` in your debug logs.
+## POST `/_dendrite/admin/refreshDevices/{userID}`
+
+This endpoint instructs Dendrite to immediately query `/devices/{userID}` on a federated server. An empty JSON body will be returned on success, updating all locally stored user devices/keys. This can be used to possibly resolve E2EE issues, where the remote user can't decrypt messages.
+
+
## POST `/_synapse/admin/v1/send_server_notice`
Request body format:
diff --git a/keyserver/api/api.go b/keyserver/api/api.go
index c9ec59a7..14fced3e 100644
--- a/keyserver/api/api.go
+++ b/keyserver/api/api.go
@@ -45,6 +45,7 @@ type ClientKeyAPI interface {
PerformUploadDeviceSignatures(ctx context.Context, req *PerformUploadDeviceSignaturesRequest, res *PerformUploadDeviceSignaturesResponse) error
// PerformClaimKeys claims one-time keys for use in pre-key messages
PerformClaimKeys(ctx context.Context, req *PerformClaimKeysRequest, res *PerformClaimKeysResponse) error
+ PerformMarkAsStaleIfNeeded(ctx context.Context, req *PerformMarkAsStaleRequest, res *struct{}) error
}
// API functions required by the userapi
diff --git a/keyserver/internal/internal.go b/keyserver/internal/internal.go
index a8d1128c..6309066d 100644
--- a/keyserver/internal/internal.go
+++ b/keyserver/internal/internal.go
@@ -228,14 +228,21 @@ func (a *KeyInternalAPI) QueryDeviceMessages(ctx context.Context, req *api.Query
// PerformMarkAsStaleIfNeeded marks the users device list as stale, if the given deviceID is not present
// in our database.
func (a *KeyInternalAPI) PerformMarkAsStaleIfNeeded(ctx context.Context, req *api.PerformMarkAsStaleRequest, res *struct{}) error {
- knownDevices, err := a.DB.DeviceKeysForUser(ctx, req.UserID, []string{req.DeviceID}, true)
+ knownDevices, err := a.DB.DeviceKeysForUser(ctx, req.UserID, []string{}, true)
if err != nil {
return err
}
if len(knownDevices) == 0 {
- return a.Updater.ManualUpdate(ctx, req.Domain, req.UserID)
+ return fmt.Errorf("unknown user %s", req.UserID)
}
- return nil
+
+ for i := range knownDevices {
+ if knownDevices[i].DeviceID == req.DeviceID {
+ return nil // we already know about this device
+ }
+ }
+
+ return a.Updater.ManualUpdate(ctx, req.Domain, req.UserID)
}
// nolint:gocyclo