diff --git a/.github/workflows/dendrite.yml b/.github/workflows/dendrite.yml index 17f02b09e..85fd355f2 100644 --- a/.github/workflows/dendrite.yml +++ b/.github/workflows/dendrite.yml @@ -67,6 +67,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + - name: Install libolm + run: sudo apt-get install libolm-dev libolm3 - name: Install Go uses: actions/setup-go@v3 with: @@ -101,6 +103,8 @@ jobs: --health-retries 5 steps: - uses: actions/checkout@v3 + - name: Install libolm + run: sudo apt-get install libolm-dev libolm3 - name: Setup go uses: actions/setup-go@v3 with: @@ -232,6 +236,8 @@ jobs: --health-retries 5 steps: - uses: actions/checkout@v3 + - name: Install libolm + run: sudo apt-get install libolm-dev libolm3 - name: Setup go uses: actions/setup-go@v3 with: diff --git a/appservice/consumers/roomserver.go b/appservice/consumers/roomserver.go index 8ca8220d0..d81123345 100644 --- a/appservice/consumers/roomserver.go +++ b/appservice/consumers/roomserver.go @@ -30,6 +30,7 @@ import ( "github.com/nats-io/nats.go" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/process" @@ -104,7 +105,7 @@ func (s *OutputRoomEventConsumer) onMessage( ctx context.Context, state *appserviceState, msgs []*nats.Msg, ) bool { log.WithField("appservice", state.ID).Tracef("Appservice worker received %d message(s) from roomserver", len(msgs)) - events := make([]*gomatrixserverlib.HeaderedEvent, 0, len(msgs)) + events := make([]*types.HeaderedEvent, 0, len(msgs)) for _, msg := range msgs { // Only handle events we care about receivedType := api.OutputType(msg.Header.Get(jetstream.RoomEventType)) @@ -174,13 +175,13 @@ func (s *OutputRoomEventConsumer) onMessage( // endpoint. It will block for the backoff period if necessary. func (s *OutputRoomEventConsumer) sendEvents( ctx context.Context, state *appserviceState, - events []*gomatrixserverlib.HeaderedEvent, + events []*types.HeaderedEvent, txnID string, ) error { // Create the transaction body. transaction, err := json.Marshal( ApplicationServiceTransaction{ - Events: synctypes.HeaderedToClientEvents(events, synctypes.FormatAll), + Events: synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), synctypes.FormatAll), }, ) if err != nil { @@ -231,7 +232,7 @@ func (s *appserviceState) backoffAndPause(err error) error { // event falls within one of a given application service's namespaces. // // TODO: This should be cached, see https://github.com/matrix-org/dendrite/issues/1682 -func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, appservice *config.ApplicationService) bool { +func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Context, event *types.HeaderedEvent, appservice *config.ApplicationService) bool { switch { case appservice.URL == "": return false @@ -269,7 +270,7 @@ func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Cont // appserviceJoinedAtEvent returns a boolean depending on whether a given // appservice has membership at the time a given event was created. -func (s *OutputRoomEventConsumer) appserviceJoinedAtEvent(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, appservice *config.ApplicationService) bool { +func (s *OutputRoomEventConsumer) appserviceJoinedAtEvent(ctx context.Context, event *types.HeaderedEvent, appservice *config.ApplicationService) bool { // TODO: This is only checking the current room state, not the state at // the event in question. Pretty sure this is what Synapse does too, but // until we have a lighter way of checking the state before the event that diff --git a/clientapi/admin_test.go b/clientapi/admin_test.go index cf1c4ef30..69a815321 100644 --- a/clientapi/admin_test.go +++ b/clientapi/admin_test.go @@ -142,8 +142,8 @@ func TestPurgeRoom(t *testing.T) { // this starts the JetStream consumers syncapi.AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, userAPI, rsAPI, caches, caching.DisableMetrics) - federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, nil, rsAPI, caches, nil, true) - rsAPI.SetFederationAPI(nil, nil) + fsAPI := federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, nil, rsAPI, caches, nil, true) + rsAPI.SetFederationAPI(fsAPI, nil) // Create the room if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil { diff --git a/clientapi/clientapi_test.go b/clientapi/clientapi_test.go index b6fb42a7b..2c34c1098 100644 --- a/clientapi/clientapi_test.go +++ b/clientapi/clientapi_test.go @@ -13,19 +13,13 @@ import ( "testing" "time" - "github.com/matrix-org/dendrite/internal/pushrules" - "github.com/matrix-org/gomatrix" - "github.com/matrix-org/gomatrixserverlib" - "github.com/matrix-org/util" - "github.com/stretchr/testify/assert" - "github.com/tidwall/gjson" - "github.com/matrix-org/dendrite/appservice" "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/routing" "github.com/matrix-org/dendrite/clientapi/threepid" "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/httputil" + "github.com/matrix-org/dendrite/internal/pushrules" "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver/api" @@ -37,6 +31,15 @@ import ( "github.com/matrix-org/dendrite/test/testrig" "github.com/matrix-org/dendrite/userapi" uapi "github.com/matrix-org/dendrite/userapi/api" + "github.com/matrix-org/gomatrix" + "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/util" + "github.com/stretchr/testify/assert" + "github.com/tidwall/gjson" + "maunium.net/go/mautrix" + "maunium.net/go/mautrix/crypto" + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" ) type userDevice struct { @@ -1630,3 +1633,502 @@ func TestPushRules(t *testing.T) { } }) } + +// Tests the `/keys` endpoints. +// Note that this only tests the happy path. +func TestKeys(t *testing.T) { + alice := test.NewUser(t) + + ctx := context.Background() + test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { + cfg, processCtx, close := testrig.CreateConfig(t, dbType) + cfg.ClientAPI.RateLimiting.Enabled = false + caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics) + natsInstance := jetstream.NATSInstance{} + defer close() + + routers := httputil.NewRouters() + cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions) + rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics) + userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil) + + // We mostly need the rsAPI for this test, so nil for other APIs/caches etc. + AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics) + + accessTokens := map[*test.User]userDevice{ + alice: {}, + } + createAccessTokens(t, accessTokens, userAPI, processCtx.Context(), routers) + + // Start a TLSServer with our client mux + srv := httptest.NewTLSServer(routers.Client) + defer srv.Close() + + cl, err := mautrix.NewClient(srv.URL, id.UserID(alice.ID), accessTokens[alice].accessToken) + if err != nil { + t.Fatal(err) + } + // Set the client so the self-signed certificate is trusted + cl.Client = srv.Client() + cl.DeviceID = id.DeviceID(accessTokens[alice].deviceID) + + cs := crypto.NewMemoryStore(nil) + oc := crypto.NewOlmMachine(cl, nil, cs, dummyStore{}) + if err = oc.Load(); err != nil { + t.Fatal(err) + } + + // tests `/keys/upload` + if err = oc.ShareKeys(ctx, 0); err != nil { + t.Fatal(err) + } + + // tests `/keys/device_signing/upload` + _, err = oc.GenerateAndUploadCrossSigningKeys(accessTokens[alice].password, "passphrase") + if err != nil { + t.Fatal(err) + } + + // tests `/keys/query` + dev, err := oc.GetOrFetchDevice(ctx, id.UserID(alice.ID), id.DeviceID(accessTokens[alice].deviceID)) + if err != nil { + t.Fatal(err) + } + + // Validate that the keys returned from the server are what the client has stored + oi := oc.OwnIdentity() + if oi.SigningKey != dev.SigningKey { + t.Fatalf("expected signing key '%s', got '%s'", oi.SigningKey, dev.SigningKey) + } + if oi.IdentityKey != dev.IdentityKey { + t.Fatalf("expected identity '%s', got '%s'", oi.IdentityKey, dev.IdentityKey) + } + + // tests `/keys/signatures/upload` + if err = oc.SignOwnMasterKey(); err != nil { + t.Fatal(err) + } + + // tests `/keys/claim` + otks := make(map[string]map[string]string) + otks[alice.ID] = map[string]string{ + accessTokens[alice].deviceID: string(id.KeyAlgorithmSignedCurve25519), + } + + data, err := json.Marshal(claimKeysRequest{OneTimeKeys: otks}) + if err != nil { + t.Fatal(err) + } + req, err := http.NewRequest(http.MethodPost, srv.URL+"/_matrix/client/v3/keys/claim", bytes.NewBuffer(data)) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Authorization", "Bearer "+accessTokens[alice].accessToken) + resp, err := srv.Client().Do(req) + if err != nil { + t.Fatal(err) + } + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + if !gjson.GetBytes(respBody, "one_time_keys."+alice.ID+"."+string(dev.DeviceID)).Exists() { + t.Fatalf("expected one time keys for alice, but didn't find any: %s", string(respBody)) + } + }) +} + +type claimKeysRequest struct { + // The keys to be claimed. A map from user ID, to a map from device ID to algorithm name. + OneTimeKeys map[string]map[string]string `json:"one_time_keys"` +} + +type dummyStore struct{} + +func (d dummyStore) IsEncrypted(roomID id.RoomID) bool { + return true +} + +func (d dummyStore) GetEncryptionEvent(roomID id.RoomID) *event.EncryptionEventContent { + return &event.EncryptionEventContent{} +} + +func (d dummyStore) FindSharedRooms(userID id.UserID) []id.RoomID { + return []id.RoomID{} +} + +func TestKeyBackup(t *testing.T) { + alice := test.NewUser(t) + + handleResponseCode := func(t *testing.T, rec *httptest.ResponseRecorder, expectedCode int) { + t.Helper() + if rec.Code != expectedCode { + t.Fatalf("expected HTTP %d, but got %d: %s", expectedCode, rec.Code, rec.Body.String()) + } + } + + testCases := []struct { + name string + request func(t *testing.T) *http.Request + validate func(t *testing.T, rec *httptest.ResponseRecorder) + }{ + { + name: "can not create backup with invalid JSON", + request: func(t *testing.T) *http.Request { + reqBody := strings.NewReader(`{"algorithm":"m.megolm_backup.v1"`) // missing closing braces + return httptest.NewRequest(http.MethodPost, "/_matrix/client/v3/room_keys/version", reqBody) + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusBadRequest) + }, + }, + { + name: "can not create backup with missing auth_data", // as this would result in MarshalJSON errors when querying again + request: func(t *testing.T) *http.Request { + reqBody := strings.NewReader(`{"algorithm":"m.megolm_backup.v1"}`) + return httptest.NewRequest(http.MethodPost, "/_matrix/client/v3/room_keys/version", reqBody) + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusBadRequest) + }, + }, + { + name: "can create backup", + request: func(t *testing.T) *http.Request { + reqBody := strings.NewReader(`{"algorithm":"m.megolm_backup.v1","auth_data":{"data":"random"}}`) + return httptest.NewRequest(http.MethodPost, "/_matrix/client/v3/room_keys/version", reqBody) + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + wantVersion := "1" + if gotVersion := gjson.GetBytes(rec.Body.Bytes(), "version").Str; gotVersion != wantVersion { + t.Fatalf("expected version '%s', got '%s'", wantVersion, gotVersion) + } + }, + }, + { + name: "can not query backup for invalid version", + request: func(t *testing.T) *http.Request { + return httptest.NewRequest(http.MethodGet, "/_matrix/client/v3/room_keys/version/1337", nil) + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusNotFound) + }, + }, + { + name: "can not query backup for invalid version string", + request: func(t *testing.T) *http.Request { + return httptest.NewRequest(http.MethodGet, "/_matrix/client/v3/room_keys/version/notanumber", nil) + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusNotFound) + }, + }, + { + name: "can query backup", + request: func(t *testing.T) *http.Request { + return httptest.NewRequest(http.MethodGet, "/_matrix/client/v3/room_keys/version", nil) + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + wantVersion := "1" + if gotVersion := gjson.GetBytes(rec.Body.Bytes(), "version").Str; gotVersion != wantVersion { + t.Fatalf("expected version '%s', got '%s'", wantVersion, gotVersion) + } + }, + }, + { + name: "can query backup without returning rooms", + request: func(t *testing.T) *http.Request { + req := test.NewRequest(t, http.MethodGet, "/_matrix/client/v3/room_keys/keys", test.WithQueryParams(map[string]string{ + "version": "1", + })) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + if gotRooms := gjson.GetBytes(rec.Body.Bytes(), "rooms").Map(); len(gotRooms) > 0 { + t.Fatalf("expected no rooms in version, but got %#v", gotRooms) + } + }, + }, + { + name: "can query backup for invalid room", + request: func(t *testing.T) *http.Request { + req := test.NewRequest(t, http.MethodGet, "/_matrix/client/v3/room_keys/keys/!abc:test", test.WithQueryParams(map[string]string{ + "version": "1", + })) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + if gotSessions := gjson.GetBytes(rec.Body.Bytes(), "sessions").Map(); len(gotSessions) > 0 { + t.Fatalf("expected no sessions in version, but got %#v", gotSessions) + } + }, + }, + { + name: "can not query backup for invalid session", + request: func(t *testing.T) *http.Request { + req := test.NewRequest(t, http.MethodGet, "/_matrix/client/v3/room_keys/keys/!abc:test/doesnotexist", test.WithQueryParams(map[string]string{ + "version": "1", + })) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusNotFound) + }, + }, + { + name: "can not update backup with missing version", + request: func(t *testing.T) *http.Request { + return test.NewRequest(t, http.MethodPut, "/_matrix/client/v3/room_keys/keys") + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusBadRequest) + }, + }, + { + name: "can not update backup with invalid data", + request: func(t *testing.T) *http.Request { + reqBody := test.WithJSONBody(t, "") + req := test.NewRequest(t, http.MethodPut, "/_matrix/client/v3/room_keys/keys", reqBody, test.WithQueryParams(map[string]string{ + "version": "0", + })) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusBadRequest) + }, + }, + { + name: "can not update backup with wrong version", + request: func(t *testing.T) *http.Request { + reqBody := test.WithJSONBody(t, map[string]interface{}{ + "rooms": map[string]interface{}{ + "!testroom:test": map[string]interface{}{ + "sessions": map[string]uapi.KeyBackupSession{}, + }, + }, + }) + req := test.NewRequest(t, http.MethodPut, "/_matrix/client/v3/room_keys/keys", reqBody, test.WithQueryParams(map[string]string{ + "version": "5", + })) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusForbidden) + }, + }, + { + name: "can update backup with correct version", + request: func(t *testing.T) *http.Request { + reqBody := test.WithJSONBody(t, map[string]interface{}{ + "rooms": map[string]interface{}{ + "!testroom:test": map[string]interface{}{ + "sessions": map[string]uapi.KeyBackupSession{ + "dummySession": { + FirstMessageIndex: 1, + }, + }, + }, + }, + }) + req := test.NewRequest(t, http.MethodPut, "/_matrix/client/v3/room_keys/keys", reqBody, test.WithQueryParams(map[string]string{ + "version": "1", + })) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + }, + }, + { + name: "can update backup with correct version for specific room", + request: func(t *testing.T) *http.Request { + reqBody := test.WithJSONBody(t, map[string]interface{}{ + "sessions": map[string]uapi.KeyBackupSession{ + "dummySession": { + FirstMessageIndex: 1, + IsVerified: true, + SessionData: json.RawMessage("{}"), + }, + }, + }) + req := test.NewRequest(t, http.MethodPut, "/_matrix/client/v3/room_keys/keys/!testroom:test", reqBody, test.WithQueryParams(map[string]string{ + "version": "1", + })) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + t.Logf("%#v", rec.Body.String()) + }, + }, + { + name: "can update backup with correct version for specific room and session", + request: func(t *testing.T) *http.Request { + reqBody := test.WithJSONBody(t, uapi.KeyBackupSession{ + FirstMessageIndex: 1, + SessionData: json.RawMessage("{}"), + IsVerified: true, + ForwardedCount: 0, + }) + req := test.NewRequest(t, http.MethodPut, "/_matrix/client/v3/room_keys/keys/!testroom:test/dummySession", reqBody, test.WithQueryParams(map[string]string{ + "version": "1", + })) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + }, + }, + { + name: "can update backup by version", + request: func(t *testing.T) *http.Request { + reqBody := test.WithJSONBody(t, uapi.KeyBackupSession{ + FirstMessageIndex: 1, + SessionData: json.RawMessage("{}"), + IsVerified: true, + ForwardedCount: 0, + }) + req := test.NewRequest(t, http.MethodPut, "/_matrix/client/v3/room_keys/version/1", reqBody, test.WithQueryParams(map[string]string{"version": "1"})) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + t.Logf("%#v", rec.Body.String()) + }, + }, + { + name: "can not update backup by version for invalid version", + request: func(t *testing.T) *http.Request { + reqBody := test.WithJSONBody(t, uapi.KeyBackupSession{ + FirstMessageIndex: 1, + SessionData: json.RawMessage("{}"), + IsVerified: true, + ForwardedCount: 0, + }) + req := test.NewRequest(t, http.MethodPut, "/_matrix/client/v3/room_keys/version/2", reqBody, test.WithQueryParams(map[string]string{"version": "1"})) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + }, + }, + { + name: "can query backup sessions", + request: func(t *testing.T) *http.Request { + req := test.NewRequest(t, http.MethodGet, "/_matrix/client/v3/room_keys/keys", test.WithQueryParams(map[string]string{ + "version": "1", + })) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + if gotRooms := gjson.GetBytes(rec.Body.Bytes(), "rooms").Map(); len(gotRooms) != 1 { + t.Fatalf("expected one room in response, but got %#v", rec.Body.String()) + } + }, + }, + { + name: "can query backup sessions by room", + request: func(t *testing.T) *http.Request { + req := test.NewRequest(t, http.MethodGet, "/_matrix/client/v3/room_keys/keys/!testroom:test", test.WithQueryParams(map[string]string{ + "version": "1", + })) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + if gotRooms := gjson.GetBytes(rec.Body.Bytes(), "sessions").Map(); len(gotRooms) != 1 { + t.Fatalf("expected one session in response, but got %#v", rec.Body.String()) + } + }, + }, + { + name: "can query backup sessions by room and sessionID", + request: func(t *testing.T) *http.Request { + req := test.NewRequest(t, http.MethodGet, "/_matrix/client/v3/room_keys/keys/!testroom:test/dummySession", test.WithQueryParams(map[string]string{ + "version": "1", + })) + return req + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + if !gjson.GetBytes(rec.Body.Bytes(), "is_verified").Bool() { + t.Fatalf("expected session to be verified, but wasn't: %#v", rec.Body.String()) + } + }, + }, + { + name: "can not delete invalid version backup", + request: func(t *testing.T) *http.Request { + return httptest.NewRequest(http.MethodDelete, "/_matrix/client/v3/room_keys/version/2", nil) + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusNotFound) + }, + }, + { + name: "can delete version backup", + request: func(t *testing.T) *http.Request { + return httptest.NewRequest(http.MethodDelete, "/_matrix/client/v3/room_keys/version/1", nil) + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + }, + }, + { + name: "deleting the same backup version twice doesn't error", + request: func(t *testing.T) *http.Request { + return httptest.NewRequest(http.MethodDelete, "/_matrix/client/v3/room_keys/version/1", nil) + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusOK) + }, + }, + { + name: "deleting an empty version doesn't work", // make sure we can't delete an empty backup version. Handled at the router level + request: func(t *testing.T) *http.Request { + return httptest.NewRequest(http.MethodDelete, "/_matrix/client/v3/room_keys/version/", nil) + }, + validate: func(t *testing.T, rec *httptest.ResponseRecorder) { + handleResponseCode(t, rec, http.StatusNotFound) + }, + }, + } + + test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { + cfg, processCtx, close := testrig.CreateConfig(t, dbType) + cfg.ClientAPI.RateLimiting.Enabled = false + caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics) + natsInstance := jetstream.NATSInstance{} + defer close() + + routers := httputil.NewRouters() + cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions) + rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics) + userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil) + + // We mostly need the rsAPI for this test, so nil for other APIs/caches etc. + AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics) + + accessTokens := map[*test.User]userDevice{ + alice: {}, + } + createAccessTokens(t, accessTokens, userAPI, processCtx.Context(), routers) + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + rec := httptest.NewRecorder() + req := tc.request(t) + req.Header.Set("Authorization", "Bearer "+accessTokens[alice].accessToken) + routers.Client.ServeHTTP(rec, req) + tc.validate(t, rec) + }) + } + }) +} diff --git a/clientapi/jsonerror/jsonerror.go b/clientapi/jsonerror/jsonerror.go index be7d13a96..436e168ab 100644 --- a/clientapi/jsonerror/jsonerror.go +++ b/clientapi/jsonerror/jsonerror.go @@ -171,6 +171,23 @@ func LeaveServerNoticeError() *MatrixError { } } +// ErrRoomKeysVersion is an error returned by `PUT /room_keys/keys` +type ErrRoomKeysVersion struct { + MatrixError + CurrentVersion string `json:"current_version"` +} + +// WrongBackupVersionError is an error returned by `PUT /room_keys/keys` +func WrongBackupVersionError(currentVersion string) *ErrRoomKeysVersion { + return &ErrRoomKeysVersion{ + MatrixError: MatrixError{ + ErrCode: "M_WRONG_ROOM_KEYS_VERSION", + Err: "Wrong backup version.", + }, + CurrentVersion: currentVersion, + } +} + type IncompatibleRoomVersionError struct { RoomVersion string `json:"room_version"` Error string `json:"error"` diff --git a/clientapi/routing/admin.go b/clientapi/routing/admin.go index 809d486d2..a5fc4ec48 100644 --- a/clientapi/routing/admin.go +++ b/clientapi/routing/admin.go @@ -3,12 +3,14 @@ package routing import ( "context" "encoding/json" + "errors" "fmt" "net/http" "time" "github.com/gorilla/mux" "github.com/matrix-org/dendrite/internal" + "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/util" @@ -28,88 +30,60 @@ func AdminEvacuateRoom(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAP if err != nil { return util.ErrorResponse(err) } - res := &roomserverAPI.PerformAdminEvacuateRoomResponse{} - if err := rsAPI.PerformAdminEvacuateRoom( - req.Context(), - &roomserverAPI.PerformAdminEvacuateRoomRequest{ - RoomID: vars["roomID"], - }, - res, - ); err != nil { + + affected, err := rsAPI.PerformAdminEvacuateRoom(req.Context(), vars["roomID"]) + switch err { + case nil: + case eventutil.ErrRoomNoExists: + return util.JSONResponse{ + Code: http.StatusNotFound, + JSON: jsonerror.NotFound(err.Error()), + } + default: + logrus.WithError(err).WithField("roomID", vars["roomID"]).Error("Failed to evacuate room") return util.ErrorResponse(err) } - if err := res.Error; err != nil { - return err.JSONResponse() - } return util.JSONResponse{ Code: 200, JSON: map[string]interface{}{ - "affected": res.Affected, + "affected": affected, }, } } -func AdminEvacuateUser(req *http.Request, cfg *config.ClientAPI, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse { +func AdminEvacuateUser(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse { vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) if err != nil { return util.ErrorResponse(err) } - userID := vars["userID"] - _, domain, err := gomatrixserverlib.SplitID('@', userID) + affected, err := rsAPI.PerformAdminEvacuateUser(req.Context(), vars["userID"]) if err != nil { + logrus.WithError(err).WithField("userID", vars["userID"]).Error("Failed to evacuate user") return util.MessageResponse(http.StatusBadRequest, err.Error()) } - if !cfg.Matrix.IsLocalServerName(domain) { - return util.JSONResponse{ - Code: http.StatusBadRequest, - JSON: jsonerror.MissingArgument("User ID must belong to this server."), - } - } - res := &roomserverAPI.PerformAdminEvacuateUserResponse{} - if err := rsAPI.PerformAdminEvacuateUser( - req.Context(), - &roomserverAPI.PerformAdminEvacuateUserRequest{ - UserID: userID, - }, - res, - ); err != nil { - return jsonerror.InternalAPIError(req.Context(), err) - } - if err := res.Error; err != nil { - return err.JSONResponse() - } + return util.JSONResponse{ Code: 200, JSON: map[string]interface{}{ - "affected": res.Affected, + "affected": affected, }, } } -func AdminPurgeRoom(req *http.Request, cfg *config.ClientAPI, device *api.Device, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse { +func AdminPurgeRoom(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse { vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) if err != nil { return util.ErrorResponse(err) } - roomID := vars["roomID"] - res := &roomserverAPI.PerformAdminPurgeRoomResponse{} - if err := rsAPI.PerformAdminPurgeRoom( - context.Background(), - &roomserverAPI.PerformAdminPurgeRoomRequest{ - RoomID: roomID, - }, - res, - ); err != nil { + if err = rsAPI.PerformAdminPurgeRoom(context.Background(), vars["roomID"]); err != nil { return util.ErrorResponse(err) } - if err := res.Error; err != nil { - return err.JSONResponse() - } + return util.JSONResponse{ Code: 200, - JSON: res, + JSON: struct{}{}, } } @@ -238,7 +212,7 @@ func AdminMarkAsStale(req *http.Request, cfg *config.ClientAPI, keyAPI api.Clien } } -func AdminDownloadState(req *http.Request, cfg *config.ClientAPI, device *api.Device, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse { +func AdminDownloadState(req *http.Request, device *api.Device, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse { vars, err := httputil.URLDecodeMapValues(mux.Vars(req)) if err != nil { return util.ErrorResponse(err) @@ -257,23 +231,22 @@ func AdminDownloadState(req *http.Request, cfg *config.ClientAPI, device *api.De JSON: jsonerror.MissingArgument("Expecting remote server name."), } } - res := &roomserverAPI.PerformAdminDownloadStateResponse{} - if err := rsAPI.PerformAdminDownloadState( - req.Context(), - &roomserverAPI.PerformAdminDownloadStateRequest{ - UserID: device.UserID, - RoomID: roomID, - ServerName: spec.ServerName(serverName), - }, - res, - ); err != nil { - return jsonerror.InternalAPIError(req.Context(), err) - } - if err := res.Error; err != nil { - return err.JSONResponse() + if err = rsAPI.PerformAdminDownloadState(req.Context(), roomID, device.UserID, spec.ServerName(serverName)); err != nil { + if errors.Is(err, eventutil.ErrRoomNoExists) { + return util.JSONResponse{ + Code: 200, + JSON: jsonerror.NotFound(eventutil.ErrRoomNoExists.Error()), + } + } + logrus.WithError(err).WithFields(logrus.Fields{ + "userID": device.UserID, + "serverName": serverName, + "roomID": roomID, + }).Error("failed to download state") + return util.ErrorResponse(err) } return util.JSONResponse{ Code: 200, - JSON: map[string]interface{}{}, + JSON: struct{}{}, } } diff --git a/clientapi/routing/createroom.go b/clientapi/routing/createroom.go index a07ef2f50..518daece3 100644 --- a/clientapi/routing/createroom.go +++ b/clientapi/routing/createroom.go @@ -22,8 +22,10 @@ import ( "strings" "time" + "github.com/getsentry/sentry-go" appserviceAPI "github.com/matrix-org/dendrite/appservice/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" roomserverVersion "github.com/matrix-org/dendrite/roomserver/version" "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib/fclient" @@ -48,7 +50,6 @@ type createRoomRequest struct { CreationContent json.RawMessage `json:"creation_content"` InitialState []fledglingEvent `json:"initial_state"` RoomAliasName string `json:"room_alias_name"` - GuestCanJoin bool `json:"guest_can_join"` RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"` PowerLevelContentOverride json.RawMessage `json:"power_level_content_override"` IsDirect bool `json:"is_direct"` @@ -253,16 +254,19 @@ func createRoom( } } + var guestsCanJoin bool switch r.Preset { case presetPrivateChat: joinRuleContent.JoinRule = spec.Invite historyVisibilityContent.HistoryVisibility = historyVisibilityShared + guestsCanJoin = true case presetTrustedPrivateChat: joinRuleContent.JoinRule = spec.Invite historyVisibilityContent.HistoryVisibility = historyVisibilityShared for _, invitee := range r.Invite { powerLevelContent.Users[invitee] = 100 } + guestsCanJoin = true case presetPublicChat: joinRuleContent.JoinRule = spec.Public historyVisibilityContent.HistoryVisibility = historyVisibilityShared @@ -317,7 +321,7 @@ func createRoom( } } - if r.GuestCanJoin { + if guestsCanJoin { guestAccessEvent = &fledglingEvent{ Type: spec.MRoomGuestAccess, Content: eventutil.GuestAccessContent{ @@ -429,7 +433,7 @@ func createRoom( // TODO: invite events // TODO: 3pid invite events - var builtEvents []*gomatrixserverlib.HeaderedEvent + var builtEvents []*types.HeaderedEvent authEvents := gomatrixserverlib.NewAuthEvents(nil) for i, e := range eventsToMake { depth := i + 1 // depth starts at 1 @@ -462,7 +466,7 @@ func createRoom( } // Add the event to the list of auth events - builtEvents = append(builtEvents, ev.Headered(roomVersion)) + builtEvents = append(builtEvents, &types.HeaderedEvent{Event: ev}) err = authEvents.AddEvent(ev) if err != nil { util.GetLogger(ctx).WithError(err).Error("authEvents.AddEvent failed") @@ -541,9 +545,10 @@ func createRoom( } // Process the invites. + var inviteEvent *types.HeaderedEvent for _, invitee := range r.Invite { // Build the invite event. - inviteEvent, err := buildMembershipEvent( + inviteEvent, err = buildMembershipEvent( ctx, invitee, "", profileAPI, device, spec.Invite, roomID, r.IsDirect, cfg, evTime, rsAPI, asAPI, ) @@ -556,38 +561,44 @@ func createRoom( fclient.NewInviteV2StrippedState(inviteEvent.Event), ) // Send the invite event to the roomserver. - var inviteRes roomserverAPI.PerformInviteResponse - event := inviteEvent.Headered(roomVersion) - if err := rsAPI.PerformInvite(ctx, &roomserverAPI.PerformInviteRequest{ + event := inviteEvent + err = rsAPI.PerformInvite(ctx, &roomserverAPI.PerformInviteRequest{ Event: event, InviteRoomState: inviteStrippedState, - RoomVersion: event.RoomVersion, + RoomVersion: event.Version(), SendAsServer: string(userDomain), - }, &inviteRes); err != nil { + }) + switch e := err.(type) { + case roomserverAPI.ErrInvalidID: + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.Unknown(e.Error()), + } + case roomserverAPI.ErrNotAllowed: + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden(e.Error()), + } + case nil: + default: util.GetLogger(ctx).WithError(err).Error("PerformInvite failed") + sentry.CaptureException(err) return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: jsonerror.InternalServerError(), } } - if inviteRes.Error != nil { - return inviteRes.Error.JSONResponse() - } } } - if r.Visibility == "public" { + if r.Visibility == spec.Public { // expose this room in the published room list - var pubRes roomserverAPI.PerformPublishResponse - if err := rsAPI.PerformPublish(ctx, &roomserverAPI.PerformPublishRequest{ + if err = rsAPI.PerformPublish(ctx, &roomserverAPI.PerformPublishRequest{ RoomID: roomID, - Visibility: "public", - }, &pubRes); err != nil { - return jsonerror.InternalAPIError(ctx, err) - } - if pubRes.Error != nil { - // treat as non-fatal since the room is already made by this point - util.GetLogger(ctx).WithError(pubRes.Error).Error("failed to visibility:public") + Visibility: spec.Public, + }); err != nil { + util.GetLogger(ctx).WithError(err).Error("failed to publish room") + return jsonerror.InternalServerError() } } diff --git a/clientapi/routing/directory.go b/clientapi/routing/directory.go index 9dd2d7cdc..a8bf019b4 100644 --- a/clientapi/routing/directory.go +++ b/clientapi/routing/directory.go @@ -304,16 +304,12 @@ func SetVisibility( return *reqErr } - var publishRes roomserverAPI.PerformPublishResponse - if err := rsAPI.PerformPublish(req.Context(), &roomserverAPI.PerformPublishRequest{ + if err = rsAPI.PerformPublish(req.Context(), &roomserverAPI.PerformPublishRequest{ RoomID: roomID, Visibility: v.Visibility, - }, &publishRes); err != nil { - return jsonerror.InternalAPIError(req.Context(), err) - } - if publishRes.Error != nil { - util.GetLogger(req.Context()).WithError(publishRes.Error).Error("PerformPublish failed") - return publishRes.Error.JSONResponse() + }); err != nil { + util.GetLogger(req.Context()).WithError(err).Error("failed to publish room") + return jsonerror.InternalServerError() } return util.JSONResponse{ @@ -342,18 +338,14 @@ func SetVisibilityAS( return *reqErr } } - var publishRes roomserverAPI.PerformPublishResponse if err := rsAPI.PerformPublish(req.Context(), &roomserverAPI.PerformPublishRequest{ RoomID: roomID, Visibility: v.Visibility, NetworkID: networkID, AppserviceID: dev.AppserviceID, - }, &publishRes); err != nil { - return jsonerror.InternalAPIError(req.Context(), err) - } - if publishRes.Error != nil { - util.GetLogger(req.Context()).WithError(publishRes.Error).Error("PerformPublish failed") - return publishRes.Error.JSONResponse() + }); err != nil { + util.GetLogger(req.Context()).WithError(err).Error("failed to publish room") + return jsonerror.InternalServerError() } return util.JSONResponse{ diff --git a/clientapi/routing/joinroom.go b/clientapi/routing/joinroom.go index d736a9588..54a9aaa4b 100644 --- a/clientapi/routing/joinroom.go +++ b/clientapi/routing/joinroom.go @@ -15,14 +15,18 @@ package routing import ( + "encoding/json" + "errors" "net/http" "time" appserviceAPI "github.com/matrix-org/dendrite/appservice/api" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" + "github.com/matrix-org/dendrite/internal/eventutil" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/userapi/api" + "github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/util" ) @@ -41,7 +45,6 @@ func JoinRoomByIDOrAlias( IsGuest: device.AccountType == api.AccountTypeGuest, Content: map[string]interface{}{}, } - joinRes := roomserverAPI.PerformJoinResponse{} // Check to see if any ?server_name= query parameters were // given in the request. @@ -81,37 +84,66 @@ func JoinRoomByIDOrAlias( done := make(chan util.JSONResponse, 1) go func() { defer close(done) - if err := rsAPI.PerformJoin(req.Context(), &joinReq, &joinRes); err != nil { - done <- jsonerror.InternalAPIError(req.Context(), err) - } else if joinRes.Error != nil { - if joinRes.Error.Code == roomserverAPI.PerformErrorNotAllowed && device.AccountType == api.AccountTypeGuest { - done <- util.JSONResponse{ - Code: http.StatusForbidden, - JSON: jsonerror.GuestAccessForbidden(joinRes.Error.Msg), - } - } else { - done <- joinRes.Error.JSONResponse() - } - } else { - done <- util.JSONResponse{ + roomID, _, err := rsAPI.PerformJoin(req.Context(), &joinReq) + var response util.JSONResponse + + switch e := err.(type) { + case nil: // success case + response = util.JSONResponse{ Code: http.StatusOK, // TODO: Put the response struct somewhere internal. JSON: struct { RoomID string `json:"room_id"` - }{joinRes.RoomID}, + }{roomID}, + } + case roomserverAPI.ErrInvalidID: + response = util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.Unknown(e.Error()), + } + case roomserverAPI.ErrNotAllowed: + jsonErr := jsonerror.Forbidden(e.Error()) + if device.AccountType == api.AccountTypeGuest { + jsonErr = jsonerror.GuestAccessForbidden(e.Error()) + } + response = util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonErr, + } + case *gomatrix.HTTPError: // this ensures we proxy responses over federation to the client + response = util.JSONResponse{ + Code: e.Code, + JSON: json.RawMessage(e.Message), + } + default: + response = util.JSONResponse{ + Code: http.StatusInternalServerError, + JSON: jsonerror.InternalServerError(), + } + if errors.Is(err, eventutil.ErrRoomNoExists) { + response = util.JSONResponse{ + Code: http.StatusNotFound, + JSON: jsonerror.NotFound(e.Error()), + } } } + done <- response }() // Wait either for the join to finish, or for us to hit a reasonable // timeout, at which point we'll just return a 200 to placate clients. + timer := time.NewTimer(time.Second * 20) select { - case <-time.After(time.Second * 20): + case <-timer.C: return util.JSONResponse{ Code: http.StatusAccepted, JSON: jsonerror.Unknown("The room join will continue in the background."), } case result := <-done: + // Stop and drain the timer + if !timer.Stop() { + <-timer.C + } return result } } diff --git a/clientapi/routing/joinroom_test.go b/clientapi/routing/joinroom_test.go index fd58ff5d5..4b67b09f0 100644 --- a/clientapi/routing/joinroom_test.go +++ b/clientapi/routing/joinroom_test.go @@ -66,7 +66,6 @@ func TestJoinRoomByIDOrAlias(t *testing.T) { Preset: presetPublicChat, RoomAliasName: "alias", Invite: []string{bob.ID}, - GuestCanJoin: false, }, aliceDev, &cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now()) crResp, ok := resp.JSON.(createRoomResponse) if !ok { @@ -75,13 +74,12 @@ func TestJoinRoomByIDOrAlias(t *testing.T) { // create a room with guest access enabled and invite Charlie resp = createRoom(ctx, createRoomRequest{ - Name: "testing", - IsDirect: true, - Topic: "testing", - Visibility: "public", - Preset: presetPublicChat, - Invite: []string{charlie.ID}, - GuestCanJoin: true, + Name: "testing", + IsDirect: true, + Topic: "testing", + Visibility: "public", + Preset: presetPublicChat, + Invite: []string{charlie.ID}, }, aliceDev, &cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now()) crRespWithGuestAccess, ok := resp.JSON.(createRoomResponse) if !ok { diff --git a/clientapi/routing/key_backup.go b/clientapi/routing/key_backup.go index b6f8fe1b9..56b05db15 100644 --- a/clientapi/routing/key_backup.go +++ b/clientapi/routing/key_backup.go @@ -61,28 +61,26 @@ func CreateKeyBackupVersion(req *http.Request, userAPI userapi.ClientUserAPI, de if resErr != nil { return *resErr } - var performKeyBackupResp userapi.PerformKeyBackupResponse - if err := userAPI.PerformKeyBackup(req.Context(), &userapi.PerformKeyBackupRequest{ + if len(kb.AuthData) == 0 { + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.BadJSON("missing auth_data"), + } + } + version, err := userAPI.PerformKeyBackup(req.Context(), &userapi.PerformKeyBackupRequest{ UserID: device.UserID, Version: "", AuthData: kb.AuthData, Algorithm: kb.Algorithm, - }, &performKeyBackupResp); err != nil { - return jsonerror.InternalServerError() - } - if performKeyBackupResp.Error != "" { - if performKeyBackupResp.BadInput { - return util.JSONResponse{ - Code: 400, - JSON: jsonerror.InvalidArgumentValue(performKeyBackupResp.Error), - } - } - return util.ErrorResponse(fmt.Errorf("PerformKeyBackup: %s", performKeyBackupResp.Error)) + }) + if err != nil { + return util.ErrorResponse(fmt.Errorf("PerformKeyBackup: %w", err)) } + return util.JSONResponse{ Code: 200, JSON: keyBackupVersionCreateResponse{ - Version: performKeyBackupResp.Version, + Version: version, }, } } @@ -90,15 +88,12 @@ func CreateKeyBackupVersion(req *http.Request, userAPI userapi.ClientUserAPI, de // KeyBackupVersion returns the key backup version specified. If `version` is empty, the latest `keyBackupVersionResponse` is returned. // Implements GET /_matrix/client/r0/room_keys/version and GET /_matrix/client/r0/room_keys/version/{version} func KeyBackupVersion(req *http.Request, userAPI userapi.ClientUserAPI, device *userapi.Device, version string) util.JSONResponse { - var queryResp userapi.QueryKeyBackupResponse - if err := userAPI.QueryKeyBackup(req.Context(), &userapi.QueryKeyBackupRequest{ + queryResp, err := userAPI.QueryKeyBackup(req.Context(), &userapi.QueryKeyBackupRequest{ UserID: device.UserID, Version: version, - }, &queryResp); err != nil { - return jsonerror.InternalAPIError(req.Context(), err) - } - if queryResp.Error != "" { - return util.ErrorResponse(fmt.Errorf("QueryKeyBackup: %s", queryResp.Error)) + }) + if err != nil { + return util.ErrorResponse(fmt.Errorf("QueryKeyBackup: %s", err)) } if !queryResp.Exists { return util.JSONResponse{ @@ -126,31 +121,29 @@ func ModifyKeyBackupVersionAuthData(req *http.Request, userAPI userapi.ClientUse if resErr != nil { return *resErr } - var performKeyBackupResp userapi.PerformKeyBackupResponse - if err := userAPI.PerformKeyBackup(req.Context(), &userapi.PerformKeyBackupRequest{ + performKeyBackupResp, err := userAPI.UpdateBackupKeyAuthData(req.Context(), &userapi.PerformKeyBackupRequest{ UserID: device.UserID, Version: version, AuthData: kb.AuthData, Algorithm: kb.Algorithm, - }, &performKeyBackupResp); err != nil { - return jsonerror.InternalServerError() - } - if performKeyBackupResp.Error != "" { - if performKeyBackupResp.BadInput { - return util.JSONResponse{ - Code: 400, - JSON: jsonerror.InvalidArgumentValue(performKeyBackupResp.Error), - } + }) + switch e := err.(type) { + case *jsonerror.ErrRoomKeysVersion: + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: e, } - return util.ErrorResponse(fmt.Errorf("PerformKeyBackup: %s", performKeyBackupResp.Error)) + case nil: + default: + return util.ErrorResponse(fmt.Errorf("PerformKeyBackup: %w", e)) } + if !performKeyBackupResp.Exists { return util.JSONResponse{ Code: 404, JSON: jsonerror.NotFound("backup version not found"), } } - // Unclear what the 200 body should be return util.JSONResponse{ Code: 200, JSON: keyBackupVersionCreateResponse{ @@ -162,35 +155,19 @@ func ModifyKeyBackupVersionAuthData(req *http.Request, userAPI userapi.ClientUse // Delete a version of key backup. Version must not be empty. If the key backup was previously deleted, will return 200 OK. // Implements DELETE /_matrix/client/r0/room_keys/version/{version} func DeleteKeyBackupVersion(req *http.Request, userAPI userapi.ClientUserAPI, device *userapi.Device, version string) util.JSONResponse { - var performKeyBackupResp userapi.PerformKeyBackupResponse - if err := userAPI.PerformKeyBackup(req.Context(), &userapi.PerformKeyBackupRequest{ - UserID: device.UserID, - Version: version, - DeleteBackup: true, - }, &performKeyBackupResp); err != nil { - return jsonerror.InternalServerError() + exists, err := userAPI.DeleteKeyBackup(req.Context(), device.UserID, version) + if err != nil { + return util.ErrorResponse(fmt.Errorf("DeleteKeyBackup: %s", err)) } - if performKeyBackupResp.Error != "" { - if performKeyBackupResp.BadInput { - return util.JSONResponse{ - Code: 400, - JSON: jsonerror.InvalidArgumentValue(performKeyBackupResp.Error), - } - } - return util.ErrorResponse(fmt.Errorf("PerformKeyBackup: %s", performKeyBackupResp.Error)) - } - if !performKeyBackupResp.Exists { + if !exists { return util.JSONResponse{ Code: 404, JSON: jsonerror.NotFound("backup version not found"), } } - // Unclear what the 200 body should be return util.JSONResponse{ Code: 200, - JSON: keyBackupVersionCreateResponse{ - Version: performKeyBackupResp.Version, - }, + JSON: struct{}{}, } } @@ -198,22 +175,21 @@ func DeleteKeyBackupVersion(req *http.Request, userAPI userapi.ClientUserAPI, de func UploadBackupKeys( req *http.Request, userAPI userapi.ClientUserAPI, device *userapi.Device, version string, keys *keyBackupSessionRequest, ) util.JSONResponse { - var performKeyBackupResp userapi.PerformKeyBackupResponse - if err := userAPI.PerformKeyBackup(req.Context(), &userapi.PerformKeyBackupRequest{ + performKeyBackupResp, err := userAPI.UpdateBackupKeyAuthData(req.Context(), &userapi.PerformKeyBackupRequest{ UserID: device.UserID, Version: version, Keys: *keys, - }, &performKeyBackupResp); err != nil && performKeyBackupResp.Error == "" { - return jsonerror.InternalServerError() - } - if performKeyBackupResp.Error != "" { - if performKeyBackupResp.BadInput { - return util.JSONResponse{ - Code: 400, - JSON: jsonerror.InvalidArgumentValue(performKeyBackupResp.Error), - } + }) + + switch e := err.(type) { + case *jsonerror.ErrRoomKeysVersion: + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: e, } - return util.ErrorResponse(fmt.Errorf("PerformKeyBackup: %s", performKeyBackupResp.Error)) + case nil: + default: + return util.ErrorResponse(fmt.Errorf("PerformKeyBackup: %w", e)) } if !performKeyBackupResp.Exists { return util.JSONResponse{ @@ -234,18 +210,15 @@ func UploadBackupKeys( func GetBackupKeys( req *http.Request, userAPI userapi.ClientUserAPI, device *userapi.Device, version, roomID, sessionID string, ) util.JSONResponse { - var queryResp userapi.QueryKeyBackupResponse - if err := userAPI.QueryKeyBackup(req.Context(), &userapi.QueryKeyBackupRequest{ + queryResp, err := userAPI.QueryKeyBackup(req.Context(), &userapi.QueryKeyBackupRequest{ UserID: device.UserID, Version: version, ReturnKeys: true, KeysForRoomID: roomID, KeysForSessionID: sessionID, - }, &queryResp); err != nil { - return jsonerror.InternalAPIError(req.Context(), err) - } - if queryResp.Error != "" { - return util.ErrorResponse(fmt.Errorf("QueryKeyBackup: %s", queryResp.Error)) + }) + if err != nil { + return util.ErrorResponse(fmt.Errorf("QueryKeyBackup: %w", err)) } if !queryResp.Exists { return util.JSONResponse{ @@ -267,17 +240,20 @@ func GetBackupKeys( } } else if roomID != "" { roomData, ok := queryResp.Keys[roomID] - if ok { - // wrap response in "sessions" - return util.JSONResponse{ - Code: 200, - JSON: struct { - Sessions map[string]userapi.KeyBackupSession `json:"sessions"` - }{ - Sessions: roomData, - }, - } + if !ok { + // If no keys are found, then an object with an empty sessions property will be returned + roomData = make(map[string]userapi.KeyBackupSession) } + // wrap response in "sessions" + return util.JSONResponse{ + Code: 200, + JSON: struct { + Sessions map[string]userapi.KeyBackupSession `json:"sessions"` + }{ + Sessions: roomData, + }, + } + } else { // response is the same as the upload request var resp keyBackupSessionRequest diff --git a/clientapi/routing/membership.go b/clientapi/routing/membership.go index 13de4d008..a4aa963a7 100644 --- a/clientapi/routing/membership.go +++ b/clientapi/routing/membership.go @@ -20,6 +20,7 @@ import ( "net/http" "time" + "github.com/getsentry/sentry-go" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" @@ -31,6 +32,7 @@ import ( "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" userapi "github.com/matrix-org/dendrite/userapi/api" @@ -91,7 +93,7 @@ func sendMembership(ctx context.Context, profileAPI userapi.ClientUserAPI, devic if err = roomserverAPI.SendEvents( ctx, rsAPI, roomserverAPI.KindNew, - []*gomatrixserverlib.HeaderedEvent{event}, + []*types.HeaderedEvent{event}, device.UserDomain(), serverName, serverName, @@ -264,22 +266,33 @@ func sendInvite( return jsonerror.InternalServerError(), err } - var inviteRes api.PerformInviteResponse - if err := rsAPI.PerformInvite(ctx, &api.PerformInviteRequest{ + err = rsAPI.PerformInvite(ctx, &api.PerformInviteRequest{ Event: event, InviteRoomState: nil, // ask the roomserver to draw up invite room state for us - RoomVersion: event.RoomVersion, + RoomVersion: event.Version(), SendAsServer: string(device.UserDomain()), - }, &inviteRes); err != nil { + }) + + switch e := err.(type) { + case roomserverAPI.ErrInvalidID: + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.Unknown(e.Error()), + }, e + case roomserverAPI.ErrNotAllowed: + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden(e.Error()), + }, e + case nil: + default: util.GetLogger(ctx).WithError(err).Error("PerformInvite failed") + sentry.CaptureException(err) return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: jsonerror.InternalServerError(), }, err } - if inviteRes.Error != nil { - return inviteRes.Error.JSONResponse(), inviteRes.Error - } return util.JSONResponse{ Code: http.StatusOK, @@ -294,7 +307,7 @@ func buildMembershipEvent( membership, roomID string, isDirect bool, cfg *config.ClientAPI, evTime time.Time, rsAPI roomserverAPI.ClientRoomserverAPI, asAPI appserviceAPI.AppServiceInternalAPI, -) (*gomatrixserverlib.HeaderedEvent, error) { +) (*types.HeaderedEvent, error) { profile, err := loadProfile(ctx, targetUserID, cfg, profileAPI, asAPI) if err != nil { return nil, err diff --git a/clientapi/routing/peekroom.go b/clientapi/routing/peekroom.go index 9a8f4378a..3937b9ad2 100644 --- a/clientapi/routing/peekroom.go +++ b/clientapi/routing/peekroom.go @@ -15,13 +15,16 @@ package routing import ( + "encoding/json" "net/http" "github.com/matrix-org/dendrite/clientapi/jsonerror" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/userapi/api" + "github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/util" + "github.com/sirupsen/logrus" ) func PeekRoomByIDOrAlias( @@ -41,8 +44,6 @@ func PeekRoomByIDOrAlias( UserID: device.UserID, DeviceID: device.ID, } - peekRes := roomserverAPI.PerformPeekResponse{} - // Check to see if any ?server_name= query parameters were // given in the request. if serverNames, ok := req.URL.Query()["server_name"]; ok { @@ -55,11 +56,27 @@ func PeekRoomByIDOrAlias( } // Ask the roomserver to perform the peek. - if err := rsAPI.PerformPeek(req.Context(), &peekReq, &peekRes); err != nil { - return util.ErrorResponse(err) - } - if peekRes.Error != nil { - return peekRes.Error.JSONResponse() + roomID, err := rsAPI.PerformPeek(req.Context(), &peekReq) + switch e := err.(type) { + case roomserverAPI.ErrInvalidID: + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.Unknown(e.Error()), + } + case roomserverAPI.ErrNotAllowed: + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden(e.Error()), + } + case *gomatrix.HTTPError: + return util.JSONResponse{ + Code: e.Code, + JSON: json.RawMessage(e.Message), + } + case nil: + default: + logrus.WithError(err).WithField("roomID", roomIDOrAlias).Errorf("Failed to peek room") + return jsonerror.InternalServerError() } // if this user is already joined to the room, we let them peek anyway @@ -75,7 +92,7 @@ func PeekRoomByIDOrAlias( // TODO: Put the response struct somewhere internal. JSON: struct { RoomID string `json:"room_id"` - }{peekRes.RoomID}, + }{roomID}, } } @@ -85,18 +102,17 @@ func UnpeekRoomByID( rsAPI roomserverAPI.ClientRoomserverAPI, roomID string, ) util.JSONResponse { - unpeekReq := roomserverAPI.PerformUnpeekRequest{ - RoomID: roomID, - UserID: device.UserID, - DeviceID: device.ID, - } - unpeekRes := roomserverAPI.PerformUnpeekResponse{} - - if err := rsAPI.PerformUnpeek(req.Context(), &unpeekReq, &unpeekRes); err != nil { - return jsonerror.InternalAPIError(req.Context(), err) - } - if unpeekRes.Error != nil { - return unpeekRes.Error.JSONResponse() + err := rsAPI.PerformUnpeek(req.Context(), roomID, device.UserID, device.ID) + switch e := err.(type) { + case roomserverAPI.ErrInvalidID: + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.Unknown(e.Error()), + } + case nil: + default: + logrus.WithError(err).WithField("roomID", roomID).Errorf("Failed to un-peek room") + return jsonerror.InternalServerError() } return util.JSONResponse{ diff --git a/clientapi/routing/profile.go b/clientapi/routing/profile.go index 0652c9b0a..9ccd1be2c 100644 --- a/clientapi/routing/profile.go +++ b/clientapi/routing/profile.go @@ -29,6 +29,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" userapi "github.com/matrix-org/dendrite/userapi/api" @@ -334,16 +335,10 @@ func buildMembershipEvents( roomIDs []string, newProfile authtypes.Profile, userID string, cfg *config.ClientAPI, evTime time.Time, rsAPI api.ClientRoomserverAPI, -) ([]*gomatrixserverlib.HeaderedEvent, error) { - evs := []*gomatrixserverlib.HeaderedEvent{} +) ([]*types.HeaderedEvent, error) { + evs := []*types.HeaderedEvent{} for _, roomID := range roomIDs { - verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID} - verRes := api.QueryRoomVersionForRoomResponse{} - if err := rsAPI.QueryRoomVersionForRoom(ctx, &verReq, &verRes); err != nil { - return nil, err - } - builder := gomatrixserverlib.EventBuilder{ Sender: userID, RoomID: roomID, @@ -372,7 +367,7 @@ func buildMembershipEvents( return nil, err } - evs = append(evs, event.Headered(verRes.RoomVersion)) + evs = append(evs, event) } return evs, nil diff --git a/clientapi/routing/redaction.go b/clientapi/routing/redaction.go index 2bdf6705e..c433110e6 100644 --- a/clientapi/routing/redaction.go +++ b/clientapi/routing/redaction.go @@ -28,6 +28,7 @@ import ( "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/internal/transactions" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" userapi "github.com/matrix-org/dendrite/userapi/api" ) @@ -138,7 +139,7 @@ func SendRedaction( } } domain := device.UserDomain() - if err = roomserverAPI.SendEvents(context.Background(), rsAPI, roomserverAPI.KindNew, []*gomatrixserverlib.HeaderedEvent{e}, device.UserDomain(), domain, domain, nil, false); err != nil { + if err = roomserverAPI.SendEvents(context.Background(), rsAPI, roomserverAPI.KindNew, []*types.HeaderedEvent{e}, device.UserDomain(), domain, domain, nil, false); err != nil { util.GetLogger(req.Context()).WithError(err).Errorf("failed to SendEvents") return jsonerror.InternalServerError() } diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go index aa9b41fc5..70299e14d 100644 --- a/clientapi/routing/routing.go +++ b/clientapi/routing/routing.go @@ -162,13 +162,13 @@ func Setup( dendriteAdminRouter.Handle("/admin/evacuateUser/{userID}", httputil.MakeAdminAPI("admin_evacuate_user", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { - return AdminEvacuateUser(req, cfg, rsAPI) + return AdminEvacuateUser(req, rsAPI) }), ).Methods(http.MethodPost, http.MethodOptions) dendriteAdminRouter.Handle("/admin/purgeRoom/{roomID}", httputil.MakeAdminAPI("admin_purge_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { - return AdminPurgeRoom(req, cfg, device, rsAPI) + return AdminPurgeRoom(req, rsAPI) }), ).Methods(http.MethodPost, http.MethodOptions) @@ -180,7 +180,7 @@ func Setup( dendriteAdminRouter.Handle("/admin/downloadState/{serverName}/{roomID}", httputil.MakeAdminAPI("admin_download_state", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { - return AdminDownloadState(req, cfg, device, rsAPI) + return AdminDownloadState(req, device, rsAPI) }), ).Methods(http.MethodGet, http.MethodOptions) diff --git a/clientapi/routing/sendevent.go b/clientapi/routing/sendevent.go index b1f8fa039..0d01367d0 100644 --- a/clientapi/routing/sendevent.go +++ b/clientapi/routing/sendevent.go @@ -34,6 +34,7 @@ import ( "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/internal/transactions" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" userapi "github.com/matrix-org/dendrite/userapi/api" ) @@ -76,9 +77,8 @@ func SendEvent( rsAPI api.ClientRoomserverAPI, txnCache *transactions.Cache, ) util.JSONResponse { - verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID} - verRes := api.QueryRoomVersionForRoomResponse{} - if err := rsAPI.QueryRoomVersionForRoom(req.Context(), &verReq, &verRes); err != nil { + roomVersion, err := rsAPI.QueryRoomVersionForRoom(req.Context(), roomID) + if err != nil { return util.JSONResponse{ Code: http.StatusBadRequest, JSON: jsonerror.UnsupportedRoomVersion(err.Error()), @@ -184,8 +184,8 @@ func SendEvent( if err := api.SendEvents( req.Context(), rsAPI, api.KindNew, - []*gomatrixserverlib.HeaderedEvent{ - e.Headered(verRes.RoomVersion), + []*types.HeaderedEvent{ + &types.HeaderedEvent{Event: e}, }, device.UserDomain(), domain, @@ -200,7 +200,7 @@ func SendEvent( util.GetLogger(req.Context()).WithFields(logrus.Fields{ "event_id": e.EventID(), "room_id": roomID, - "room_version": verRes.RoomVersion, + "room_version": roomVersion, }).Info("Sent event to roomserver") res := util.JSONResponse{ @@ -317,7 +317,7 @@ func generateSendEvent( for i := range queryRes.StateEvents { stateEvents[i] = queryRes.StateEvents[i].Event } - provider := gomatrixserverlib.NewAuthEvents(stateEvents) + provider := gomatrixserverlib.NewAuthEvents(gomatrixserverlib.ToPDUs(stateEvents)) if err = gomatrixserverlib.Allowed(e.Event, &provider); err != nil { return nil, &util.JSONResponse{ Code: http.StatusForbidden, diff --git a/clientapi/routing/server_notices.go b/clientapi/routing/server_notices.go index d6191f3b4..c556ed269 100644 --- a/clientapi/routing/server_notices.go +++ b/clientapi/routing/server_notices.go @@ -22,12 +22,12 @@ import ( "time" "github.com/matrix-org/gomatrix" - "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/tokens" "github.com/matrix-org/util" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/roomserver/version" appserviceAPI "github.com/matrix-org/dendrite/appservice/api" @@ -157,7 +157,6 @@ func SendServerNotice( Visibility: "private", Preset: presetPrivateChat, CreationContent: cc, - GuestCanJoin: false, RoomVersion: roomVersion, PowerLevelContentOverride: pl, } @@ -228,8 +227,8 @@ func SendServerNotice( if err := api.SendEvents( ctx, rsAPI, api.KindNew, - []*gomatrixserverlib.HeaderedEvent{ - e.Headered(roomVersion), + []*types.HeaderedEvent{ + &types.HeaderedEvent{Event: e}, }, device.UserDomain(), cfgClient.Matrix.ServerName, diff --git a/clientapi/routing/state.go b/clientapi/routing/state.go index 3fb157660..705782e88 100644 --- a/clientapi/routing/state.go +++ b/clientapi/routing/state.go @@ -22,6 +22,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/synctypes" userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" @@ -133,7 +134,7 @@ func OnIncomingStateRequest(ctx context.Context, device *userapi.Device, rsAPI a for _, ev := range stateRes.StateEvents { stateEvents = append( stateEvents, - synctypes.HeaderedToClientEvent(ev, synctypes.FormatAll), + synctypes.ToClientEvent(ev, synctypes.FormatAll), ) } } else { @@ -152,7 +153,7 @@ func OnIncomingStateRequest(ctx context.Context, device *userapi.Device, rsAPI a for _, ev := range stateAfterRes.StateEvents { stateEvents = append( stateEvents, - synctypes.HeaderedToClientEvent(ev, synctypes.FormatAll), + synctypes.ToClientEvent(ev, synctypes.FormatAll), ) } } @@ -266,7 +267,7 @@ func OnIncomingStateTypeRequest( "state_at_event": !wantLatestState, }).Info("Fetching state") - var event *gomatrixserverlib.HeaderedEvent + var event *types.HeaderedEvent if wantLatestState { // If we are happy to use the latest state, either because the user is // still in the room, or because the room is world-readable, then just @@ -311,7 +312,7 @@ func OnIncomingStateTypeRequest( } stateEvent := stateEventInStateResp{ - ClientEvent: synctypes.HeaderedToClientEvent(event, synctypes.FormatAll), + ClientEvent: synctypes.ToClientEvent(event, synctypes.FormatAll), } var res interface{} diff --git a/clientapi/routing/upgrade_room.go b/clientapi/routing/upgrade_room.go index 34c7eb004..f0936db1f 100644 --- a/clientapi/routing/upgrade_room.go +++ b/clientapi/routing/upgrade_room.go @@ -15,11 +15,13 @@ package routing import ( + "errors" "net/http" appserviceAPI "github.com/matrix-org/dendrite/appservice/api" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" + "github.com/matrix-org/dendrite/internal/eventutil" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/version" "github.com/matrix-org/dendrite/setup/config" @@ -57,38 +59,28 @@ func UpgradeRoom( } } - upgradeReq := roomserverAPI.PerformRoomUpgradeRequest{ - UserID: device.UserID, - RoomID: roomID, - RoomVersion: gomatrixserverlib.RoomVersion(r.NewVersion), - } - upgradeResp := roomserverAPI.PerformRoomUpgradeResponse{} - - if err := rsAPI.PerformRoomUpgrade(req.Context(), &upgradeReq, &upgradeResp); err != nil { - return jsonerror.InternalAPIError(req.Context(), err) - } - - if upgradeResp.Error != nil { - if upgradeResp.Error.Code == roomserverAPI.PerformErrorNoRoom { + newRoomID, err := rsAPI.PerformRoomUpgrade(req.Context(), roomID, device.UserID, gomatrixserverlib.RoomVersion(r.NewVersion)) + switch e := err.(type) { + case nil: + case roomserverAPI.ErrNotAllowed: + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden(e.Error()), + } + default: + if errors.Is(err, eventutil.ErrRoomNoExists) { return util.JSONResponse{ Code: http.StatusNotFound, JSON: jsonerror.NotFound("Room does not exist"), } - } else if upgradeResp.Error.Code == roomserverAPI.PerformErrorNotAllowed { - return util.JSONResponse{ - Code: http.StatusForbidden, - JSON: jsonerror.Forbidden(upgradeResp.Error.Msg), - } - } else { - return jsonerror.InternalServerError() } - + return jsonerror.InternalServerError() } return util.JSONResponse{ Code: http.StatusOK, JSON: upgradeRoomResponse{ - ReplacementRoom: upgradeResp.NewRoomID, + ReplacementRoom: newRoomID, }, } } diff --git a/clientapi/threepid/invites.go b/clientapi/threepid/invites.go index 34fa54152..219405752 100644 --- a/clientapi/threepid/invites.go +++ b/clientapi/threepid/invites.go @@ -27,6 +27,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" @@ -367,8 +368,8 @@ func emit3PIDInviteEvent( return api.SendEvents( ctx, rsAPI, api.KindNew, - []*gomatrixserverlib.HeaderedEvent{ - event.Headered(queryRes.RoomVersion), + []*types.HeaderedEvent{ + event, }, device.UserDomain(), cfg.Matrix.ServerName, diff --git a/cmd/resolve-state/main.go b/cmd/resolve-state/main.go index 09c0e6907..b2f4afa84 100644 --- a/cmd/resolve-state/main.go +++ b/cmd/resolve-state/main.go @@ -183,8 +183,8 @@ func main() { var resolved Events resolved, err = gomatrixserverlib.ResolveConflicts( gomatrixserverlib.RoomVersion(*roomVersion), - events, - authEvents, + gomatrixserverlib.ToPDUs(events), + gomatrixserverlib.ToPDUs(authEvents), ) if err != nil { panic(err) @@ -208,7 +208,7 @@ func main() { fmt.Println("Returned", count, "state events after filtering") } -type Events []*gomatrixserverlib.Event +type Events []gomatrixserverlib.PDU func (e Events) Len() int { return len(e) diff --git a/federationapi/api/api.go b/federationapi/api/api.go index 0048b4b04..b53ec3dd8 100644 --- a/federationapi/api/api.go +++ b/federationapi/api/api.go @@ -11,11 +11,13 @@ import ( "github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/dendrite/federationapi/types" + rstypes "github.com/matrix-org/dendrite/roomserver/types" ) // FederationInternalAPI is used to query information from the federation sender. type FederationInternalAPI interface { gomatrixserverlib.FederatedStateClient + gomatrixserverlib.FederatedJoinClient KeyserverFederationAPI gomatrixserverlib.KeyDatabase ClientFederationAPI @@ -188,13 +190,13 @@ type PerformLeaveResponse struct { } type PerformInviteRequest struct { - RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"` - Event *gomatrixserverlib.HeaderedEvent `json:"event"` - InviteRoomState []fclient.InviteV2StrippedState `json:"invite_room_state"` + RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"` + Event *rstypes.HeaderedEvent `json:"event"` + InviteRoomState []fclient.InviteV2StrippedState `json:"invite_room_state"` } type PerformInviteResponse struct { - Event *gomatrixserverlib.HeaderedEvent `json:"event"` + Event *rstypes.HeaderedEvent `json:"event"` } // QueryJoinedHostServerNamesInRoomRequest is a request to QueryJoinedHostServerNames diff --git a/federationapi/consumers/roomserver.go b/federationapi/consumers/roomserver.go index 5ef65ee5b..d0aa06402 100644 --- a/federationapi/consumers/roomserver.go +++ b/federationapi/consumers/roomserver.go @@ -187,7 +187,12 @@ func (s *OutputRoomEventConsumer) processMessage(ore api.OutputNewRoomEvent, rew addsStateEvents = append(addsStateEvents, eventsRes.Events...) } - addsJoinedHosts, err := JoinedHostsFromEvents(gomatrixserverlib.UnwrapEventHeaders(addsStateEvents)) + evs := make([]*gomatrixserverlib.Event, len(addsStateEvents)) + for i := range evs { + evs[i] = addsStateEvents[i].Event + } + + addsJoinedHosts, err := JoinedHostsFromEvents(evs) if err != nil { return err } diff --git a/federationapi/federationapi_test.go b/federationapi/federationapi_test.go index ca1444917..de65f3489 100644 --- a/federationapi/federationapi_test.go +++ b/federationapi/federationapi_test.go @@ -23,6 +23,7 @@ import ( "github.com/matrix-org/dendrite/federationapi/api" "github.com/matrix-org/dendrite/federationapi/internal" rsapi "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test/testrig" @@ -106,7 +107,9 @@ func (f *fedClient) GetServerKeys(ctx context.Context, matrixServer spec.ServerN return keys, nil } -func (f *fedClient) MakeJoin(ctx context.Context, origin, s spec.ServerName, roomID, userID string, roomVersions []gomatrixserverlib.RoomVersion) (res fclient.RespMakeJoin, err error) { +func (f *fedClient) MakeJoin(ctx context.Context, origin, s spec.ServerName, roomID, userID string) (res fclient.RespMakeJoin, err error) { + f.fedClientMutex.Lock() + defer f.fedClientMutex.Unlock() for _, r := range f.allowJoins { if r.ID == roomID { res.RoomVersion = r.Version @@ -135,10 +138,10 @@ func (f *fedClient) SendJoin(ctx context.Context, origin, s spec.ServerName, eve defer f.fedClientMutex.Unlock() for _, r := range f.allowJoins { if r.ID == event.RoomID() { - r.InsertEvent(f.t, event.Headered(r.Version)) + r.InsertEvent(f.t, &types.HeaderedEvent{Event: event}) f.t.Logf("Join event: %v", event.EventID()) - res.StateEvents = gomatrixserverlib.NewEventJSONsFromHeaderedEvents(r.CurrentState()) - res.AuthEvents = gomatrixserverlib.NewEventJSONsFromHeaderedEvents(r.Events()) + res.StateEvents = types.NewEventJSONsFromHeaderedEvents(r.CurrentState()) + res.AuthEvents = types.NewEventJSONsFromHeaderedEvents(r.Events()) } } return @@ -325,8 +328,7 @@ func TestRoomsV3URLEscapeDoNot404(t *testing.T) { if err != nil { t.Errorf("failed to parse event: %s", err) } - he := ev.Headered(tc.roomVer) - invReq, err := fclient.NewInviteV2Request(he, nil) + invReq, err := fclient.NewInviteV2Request(ev, nil) if err != nil { t.Errorf("failed to create invite v2 request: %s", err) continue diff --git a/federationapi/internal/federationclient.go b/federationapi/internal/federationclient.go index e4288a20c..dd329057c 100644 --- a/federationapi/internal/federationclient.go +++ b/federationapi/internal/federationclient.go @@ -9,14 +9,40 @@ import ( "github.com/matrix-org/gomatrixserverlib/spec" ) +const defaultTimeout = time.Second * 30 + // Functions here are "proxying" calls to the gomatrixserverlib federation // client. +func (a *FederationInternalAPI) MakeJoin( + ctx context.Context, origin, s spec.ServerName, roomID, userID string, +) (res gomatrixserverlib.MakeJoinResponse, err error) { + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + ires, err := a.federation.MakeJoin(ctx, origin, s, roomID, userID) + if err != nil { + return &fclient.RespMakeJoin{}, err + } + return &ires, nil +} + +func (a *FederationInternalAPI) SendJoin( + ctx context.Context, origin, s spec.ServerName, event *gomatrixserverlib.Event, +) (res gomatrixserverlib.SendJoinResponse, err error) { + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) + defer cancel() + ires, err := a.federation.SendJoin(ctx, origin, s, event) + if err != nil { + return &fclient.RespSendJoin{}, err + } + return &ires, nil +} + func (a *FederationInternalAPI) GetEventAuth( ctx context.Context, origin, s spec.ServerName, roomVersion gomatrixserverlib.RoomVersion, roomID, eventID string, ) (res fclient.RespEventAuth, err error) { - ctx, cancel := context.WithTimeout(ctx, time.Second*30) + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) defer cancel() ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) { return a.federation.GetEventAuth(ctx, origin, s, roomVersion, roomID, eventID) @@ -30,7 +56,7 @@ func (a *FederationInternalAPI) GetEventAuth( func (a *FederationInternalAPI) GetUserDevices( ctx context.Context, origin, s spec.ServerName, userID string, ) (fclient.RespUserDevices, error) { - ctx, cancel := context.WithTimeout(ctx, time.Second*30) + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) defer cancel() ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) { return a.federation.GetUserDevices(ctx, origin, s, userID) @@ -44,7 +70,7 @@ func (a *FederationInternalAPI) GetUserDevices( func (a *FederationInternalAPI) ClaimKeys( ctx context.Context, origin, s spec.ServerName, oneTimeKeys map[string]map[string]string, ) (fclient.RespClaimKeys, error) { - ctx, cancel := context.WithTimeout(ctx, time.Second*30) + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) defer cancel() ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) { return a.federation.ClaimKeys(ctx, origin, s, oneTimeKeys) @@ -70,7 +96,7 @@ func (a *FederationInternalAPI) QueryKeys( func (a *FederationInternalAPI) Backfill( ctx context.Context, origin, s spec.ServerName, roomID string, limit int, eventIDs []string, ) (res gomatrixserverlib.Transaction, err error) { - ctx, cancel := context.WithTimeout(ctx, time.Second*30) + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) defer cancel() ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) { return a.federation.Backfill(ctx, origin, s, roomID, limit, eventIDs) @@ -84,7 +110,7 @@ func (a *FederationInternalAPI) Backfill( func (a *FederationInternalAPI) LookupState( ctx context.Context, origin, s spec.ServerName, roomID, eventID string, roomVersion gomatrixserverlib.RoomVersion, ) (res gomatrixserverlib.StateResponse, err error) { - ctx, cancel := context.WithTimeout(ctx, time.Second*30) + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) defer cancel() ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) { return a.federation.LookupState(ctx, origin, s, roomID, eventID, roomVersion) @@ -99,7 +125,7 @@ func (a *FederationInternalAPI) LookupState( func (a *FederationInternalAPI) LookupStateIDs( ctx context.Context, origin, s spec.ServerName, roomID, eventID string, ) (res gomatrixserverlib.StateIDResponse, err error) { - ctx, cancel := context.WithTimeout(ctx, time.Second*30) + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) defer cancel() ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) { return a.federation.LookupStateIDs(ctx, origin, s, roomID, eventID) @@ -114,7 +140,7 @@ func (a *FederationInternalAPI) LookupMissingEvents( ctx context.Context, origin, s spec.ServerName, roomID string, missing fclient.MissingEvents, roomVersion gomatrixserverlib.RoomVersion, ) (res fclient.RespMissingEvents, err error) { - ctx, cancel := context.WithTimeout(ctx, time.Second*30) + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) defer cancel() ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) { return a.federation.LookupMissingEvents(ctx, origin, s, roomID, missing, roomVersion) @@ -128,7 +154,7 @@ func (a *FederationInternalAPI) LookupMissingEvents( func (a *FederationInternalAPI) GetEvent( ctx context.Context, origin, s spec.ServerName, eventID string, ) (res gomatrixserverlib.Transaction, err error) { - ctx, cancel := context.WithTimeout(ctx, time.Second*30) + ctx, cancel := context.WithTimeout(ctx, defaultTimeout) defer cancel() ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) { return a.federation.GetEvent(ctx, origin, s, eventID) diff --git a/federationapi/internal/perform.go b/federationapi/internal/perform.go index c73b69d98..9dbc0e278 100644 --- a/federationapi/internal/perform.go +++ b/federationapi/internal/perform.go @@ -18,6 +18,7 @@ import ( "github.com/matrix-org/dendrite/federationapi/consumers" "github.com/matrix-org/dendrite/federationapi/statistics" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/roomserver/version" ) @@ -73,12 +74,6 @@ func (r *FederationInternalAPI) PerformJoin( r.joins.Store(j, nil) defer r.joins.Delete(j) - // Look up the supported room versions. - var supportedVersions []gomatrixserverlib.RoomVersion - for version := range version.SupportedRoomVersions() { - supportedVersions = append(supportedVersions, version) - } - // Deduplicate the server names we were provided but keep the ordering // as this encodes useful information about which servers are most likely // to respond. @@ -103,7 +98,6 @@ func (r *FederationInternalAPI) PerformJoin( request.UserID, request.Content, serverName, - supportedVersions, request.Unsigned, ); err != nil { logrus.WithError(err).WithFields(logrus.Fields{ @@ -146,128 +140,45 @@ func (r *FederationInternalAPI) performJoinUsingServer( roomID, userID string, content map[string]interface{}, serverName spec.ServerName, - supportedVersions []gomatrixserverlib.RoomVersion, unsigned map[string]interface{}, ) error { if !r.shouldAttemptDirectFederation(serverName) { return fmt.Errorf("relay servers have no meaningful response for join.") } - _, origin, err := r.cfg.Matrix.SplitLocalID('@', userID) + user, err := spec.NewUserID(userID, true) + if err != nil { + return err + } + room, err := spec.NewRoomID(roomID) if err != nil { return err } - // Try to perform a make_join using the information supplied in the - // request. - respMakeJoin, err := r.federation.MakeJoin( - ctx, - origin, - serverName, - roomID, - userID, - supportedVersions, - ) - if err != nil { - // TODO: Check if the user was not allowed to join the room. - r.statistics.ForServer(serverName).Failure() - return fmt.Errorf("r.federation.MakeJoin: %w", err) + joinInput := gomatrixserverlib.PerformJoinInput{ + UserID: user, + RoomID: room, + ServerName: serverName, + Content: content, + Unsigned: unsigned, + PrivateKey: r.cfg.Matrix.PrivateKey, + KeyID: r.cfg.Matrix.KeyID, + KeyRing: r.keyRing, + EventProvider: federatedEventProvider(ctx, r.federation, r.keyRing, user.Domain(), serverName), } - r.statistics.ForServer(serverName).Success(statistics.SendDirect) + response, joinErr := gomatrixserverlib.PerformJoin(ctx, r, joinInput) - // Set all the fields to be what they should be, this should be a no-op - // but it's possible that the remote server returned us something "odd" - respMakeJoin.JoinEvent.Type = spec.MRoomMember - respMakeJoin.JoinEvent.Sender = userID - respMakeJoin.JoinEvent.StateKey = &userID - respMakeJoin.JoinEvent.RoomID = roomID - respMakeJoin.JoinEvent.Redacts = "" - if content == nil { - content = map[string]interface{}{} - } - _ = json.Unmarshal(respMakeJoin.JoinEvent.Content, &content) - content["membership"] = spec.Join - if err = respMakeJoin.JoinEvent.SetContent(content); err != nil { - return fmt.Errorf("respMakeJoin.JoinEvent.SetContent: %w", err) - } - if err = respMakeJoin.JoinEvent.SetUnsigned(struct{}{}); err != nil { - return fmt.Errorf("respMakeJoin.JoinEvent.SetUnsigned: %w", err) - } - - // Work out if we support the room version that has been supplied in - // the make_join response. - // "If not provided, the room version is assumed to be either "1" or "2"." - // https://matrix.org/docs/spec/server_server/unstable#get-matrix-federation-v1-make-join-roomid-userid - if respMakeJoin.RoomVersion == "" { - respMakeJoin.RoomVersion = setDefaultRoomVersionFromJoinEvent(respMakeJoin.JoinEvent) - } - verImpl, err := gomatrixserverlib.GetRoomVersion(respMakeJoin.RoomVersion) - if err != nil { - return err - } - - // Build the join event. - event, err := respMakeJoin.JoinEvent.Build( - time.Now(), - origin, - r.cfg.Matrix.KeyID, - r.cfg.Matrix.PrivateKey, - respMakeJoin.RoomVersion, - ) - if err != nil { - return fmt.Errorf("respMakeJoin.JoinEvent.Build: %w", err) - } - - // Try to perform a send_join using the newly built event. - respSendJoin, err := r.federation.SendJoin( - context.Background(), - origin, - serverName, - event, - ) - if err != nil { - r.statistics.ForServer(serverName).Failure() - return fmt.Errorf("r.federation.SendJoin: %w", err) - } - r.statistics.ForServer(serverName).Success(statistics.SendDirect) - - // If the remote server returned an event in the "event" key of - // the send_join request then we should use that instead. It may - // contain signatures that we don't know about. - if len(respSendJoin.Event) > 0 { - var remoteEvent *gomatrixserverlib.Event - remoteEvent, err = verImpl.NewEventFromUntrustedJSON(respSendJoin.Event) - if err == nil && isWellFormedMembershipEvent( - remoteEvent, roomID, userID, - ) { - event = remoteEvent + if joinErr != nil { + if !joinErr.Reachable { + r.statistics.ForServer(joinErr.ServerName).Failure() + } else { + r.statistics.ForServer(joinErr.ServerName).Success(statistics.SendDirect) } + return joinErr.Err } - - // Sanity-check the join response to ensure that it has a create - // event, that the room version is known, etc. - authEvents := respSendJoin.AuthEvents.UntrustedEvents(respMakeJoin.RoomVersion) - if err = sanityCheckAuthChain(authEvents); err != nil { - return fmt.Errorf("sanityCheckAuthChain: %w", err) - } - - // Process the join response in a goroutine. The idea here is - // that we'll try and wait for as long as possible for the work - // to complete, but if the client does give up waiting, we'll - // still continue to process the join anyway so that we don't - // waste the effort. - // TODO: Can we expand Check here to return a list of missing auth - // events rather than failing one at a time? - var respState gomatrixserverlib.StateResponse - respState, err = gomatrixserverlib.CheckSendJoinResponse( - context.Background(), - respMakeJoin.RoomVersion, &respSendJoin, - r.keyRing, - event, - federatedAuthProvider(ctx, r.federation, r.keyRing, origin, serverName), - ) - if err != nil { - return fmt.Errorf("respSendJoin.Check: %w", err) + r.statistics.ForServer(serverName).Success(statistics.SendDirect) + if response == nil { + return fmt.Errorf("Received nil response from gomatrixserverlib.PerformJoin") } // We need to immediately update our list of joined hosts for this room now as we are technically @@ -276,60 +187,33 @@ func (r *FederationInternalAPI) performJoinUsingServer( // joining a room, waiting for 200 OK then changing device keys and have those keys not be sent // to other servers (this was a cause of a flakey sytest "Local device key changes get to remote servers") // The events are trusted now as we performed auth checks above. - joinedHosts, err := consumers.JoinedHostsFromEvents(respState.GetStateEvents().TrustedEvents(respMakeJoin.RoomVersion, false)) + joinedHosts, err := consumers.JoinedHostsFromEvents(response.StateSnapshot.GetStateEvents().TrustedEvents(response.JoinEvent.Version(), false)) if err != nil { return fmt.Errorf("JoinedHostsFromEvents: failed to get joined hosts: %s", err) } + logrus.WithField("room", roomID).Infof("Joined federated room with %d hosts", len(joinedHosts)) if _, err = r.db.UpdateRoom(context.Background(), roomID, joinedHosts, nil, true); err != nil { return fmt.Errorf("UpdatedRoom: failed to update room with joined hosts: %s", err) } - // If we successfully performed a send_join above then the other - // server now thinks we're a part of the room. Send the newly - // returned state to the roomserver to update our local view. - if unsigned != nil { - event, err = event.SetUnsigned(unsigned) - if err != nil { - // non-fatal, log and continue - logrus.WithError(err).Errorf("Failed to set unsigned content") - } - } - + // TODO: Can I change this to not take respState but instead just take an opaque list of events? if err = roomserverAPI.SendEventWithState( context.Background(), r.rsAPI, - origin, + user.Domain(), roomserverAPI.KindNew, - respState, - event.Headered(respMakeJoin.RoomVersion), + response.StateSnapshot, + &types.HeaderedEvent{Event: response.JoinEvent}, serverName, nil, false, ); err != nil { return fmt.Errorf("roomserverAPI.SendEventWithState: %w", err) } - return nil } -// isWellFormedMembershipEvent returns true if the event looks like a legitimate -// membership event. -func isWellFormedMembershipEvent(event *gomatrixserverlib.Event, roomID, userID string) bool { - if membership, err := event.Membership(); err != nil { - return false - } else if membership != spec.Join { - return false - } - if event.RoomID() != roomID { - return false - } - if !event.StateKeyEquals(userID) { - return false - } - return true -} - // PerformOutboundPeekRequest implements api.FederationInternalAPI func (r *FederationInternalAPI) PerformOutboundPeek( ctx context.Context, @@ -475,12 +359,12 @@ func (r *FederationInternalAPI) performOutboundPeekUsingServer( // authenticate the state returned (check its auth events etc) // the equivalent of CheckSendJoinResponse() authEvents, stateEvents, err := gomatrixserverlib.CheckStateResponse( - ctx, &respPeek, respPeek.RoomVersion, r.keyRing, federatedAuthProvider(ctx, r.federation, r.keyRing, r.cfg.Matrix.ServerName, serverName), + ctx, &respPeek, respPeek.RoomVersion, r.keyRing, federatedEventProvider(ctx, r.federation, r.keyRing, r.cfg.Matrix.ServerName, serverName), ) if err != nil { return fmt.Errorf("error checking state returned from peeking: %w", err) } - if err = sanityCheckAuthChain(authEvents); err != nil { + if err = checkEventsContainCreateEvent(authEvents); err != nil { return fmt.Errorf("sanityCheckAuthChain: %w", err) } @@ -505,7 +389,7 @@ func (r *FederationInternalAPI) performOutboundPeekUsingServer( StateEvents: gomatrixserverlib.NewEventJSONsFromEvents(stateEvents), AuthEvents: gomatrixserverlib.NewEventJSONsFromEvents(authEvents), }, - respPeek.LatestEvent.Headered(respPeek.RoomVersion), + &types.HeaderedEvent{Event: respPeek.LatestEvent}, serverName, nil, false, @@ -652,7 +536,7 @@ func (r *FederationInternalAPI) PerformInvite( "destination": destination, }).Info("Sending invite") - inviteReq, err := fclient.NewInviteV2Request(request.Event, request.InviteRoomState) + inviteReq, err := fclient.NewInviteV2Request(request.Event.Event, request.InviteRoomState) if err != nil { return fmt.Errorf("gomatrixserverlib.NewInviteV2Request: %w", err) } @@ -670,7 +554,7 @@ func (r *FederationInternalAPI) PerformInvite( if err != nil { return fmt.Errorf("r.federation.SendInviteV2 failed to decode event response: %w", err) } - response.Event = inviteEvent.Headered(request.RoomVersion) + response.Event = &types.HeaderedEvent{Event: inviteEvent} return nil } @@ -719,9 +603,9 @@ func (r *FederationInternalAPI) MarkServersAlive(destinations []spec.ServerName) } } -func sanityCheckAuthChain(authChain []*gomatrixserverlib.Event) error { +func checkEventsContainCreateEvent(events []*gomatrixserverlib.Event) error { // sanity check we have a create event and it has a known room version - for _, ev := range authChain { + for _, ev := range events { if ev.Type() == spec.MRoomCreate && ev.StateKeyEquals("") { // make sure the room version is known content := ev.Content() @@ -739,52 +623,28 @@ func sanityCheckAuthChain(authChain []*gomatrixserverlib.Event) error { } knownVersions := gomatrixserverlib.RoomVersions() if _, ok := knownVersions[gomatrixserverlib.RoomVersion(verBody.Version)]; !ok { - return fmt.Errorf("auth chain m.room.create event has an unknown room version: %s", verBody.Version) + return fmt.Errorf("m.room.create event has an unknown room version: %s", verBody.Version) } return nil } } - return fmt.Errorf("auth chain response is missing m.room.create event") + return fmt.Errorf("response is missing m.room.create event") } -func setDefaultRoomVersionFromJoinEvent( - joinEvent gomatrixserverlib.EventBuilder, -) gomatrixserverlib.RoomVersion { - // if auth events are not event references we know it must be v3+ - // we have to do these shenanigans to satisfy sytest, specifically for: - // "Outbound federation rejects m.room.create events with an unknown room version" - hasEventRefs := true - authEvents, ok := joinEvent.AuthEvents.([]interface{}) - if ok { - if len(authEvents) > 0 { - _, ok = authEvents[0].(string) - if ok { - // event refs are objects, not strings, so we know we must be dealing with a v3+ room. - hasEventRefs = false - } - } - } - - if hasEventRefs { - return gomatrixserverlib.RoomVersionV1 - } - return gomatrixserverlib.RoomVersionV4 -} - -// FederatedAuthProvider is an auth chain provider which fetches events from the server provided -func federatedAuthProvider( +// federatedEventProvider is an event provider which fetches events from the server provided +func federatedEventProvider( ctx context.Context, federation fclient.FederationClient, keyRing gomatrixserverlib.JSONVerifier, origin, server spec.ServerName, -) gomatrixserverlib.AuthChainProvider { +) gomatrixserverlib.EventProvider { // A list of events that we have retried, if they were not included in // the auth events supplied in the send_join. - retries := map[string][]*gomatrixserverlib.Event{} + retries := map[string][]gomatrixserverlib.PDU{} // Define a function which we can pass to Check to retrieve missing // auth events inline. This greatly increases our chances of not having // to repeat the entire set of checks just for a missing event or two. - return func(roomVersion gomatrixserverlib.RoomVersion, eventIDs []string) ([]*gomatrixserverlib.Event, error) { - returning := []*gomatrixserverlib.Event{} + return func(roomVersion gomatrixserverlib.RoomVersion, eventIDs []string) ([]gomatrixserverlib.PDU, error) { + returning := []gomatrixserverlib.PDU{} verImpl, err := gomatrixserverlib.GetRoomVersion(roomVersion) if err != nil { return nil, err @@ -824,7 +684,7 @@ func federatedAuthProvider( } // Check the signatures of the event. - if err := ev.VerifyEventSignatures(ctx, keyRing); err != nil { + if err := gomatrixserverlib.VerifyEventSignatures(ctx, ev, keyRing); err != nil { return nil, fmt.Errorf("missingAuth VerifyEventSignatures: %w", err) } diff --git a/federationapi/queue/destinationqueue.go b/federationapi/queue/destinationqueue.go index c00659ff0..880aee0d3 100644 --- a/federationapi/queue/destinationqueue.go +++ b/federationapi/queue/destinationqueue.go @@ -32,6 +32,7 @@ import ( "github.com/matrix-org/dendrite/federationapi/storage" "github.com/matrix-org/dendrite/federationapi/storage/shared/receipt" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/process" ) @@ -71,7 +72,7 @@ type destinationQueue struct { // Send event adds the event to the pending queue for the destination. // If the queue is empty then it starts a background goroutine to // start sending events to that destination. -func (oq *destinationQueue) sendEvent(event *gomatrixserverlib.HeaderedEvent, dbReceipt *receipt.Receipt) { +func (oq *destinationQueue) sendEvent(event *types.HeaderedEvent, dbReceipt *receipt.Receipt) { if event == nil { logrus.Errorf("attempt to send nil PDU with destination %q", oq.destination) return diff --git a/federationapi/queue/queue.go b/federationapi/queue/queue.go index a482e43e9..26305ed7a 100644 --- a/federationapi/queue/queue.go +++ b/federationapi/queue/queue.go @@ -33,6 +33,7 @@ import ( "github.com/matrix-org/dendrite/federationapi/storage" "github.com/matrix-org/dendrite/federationapi/storage/shared/receipt" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/process" ) @@ -140,7 +141,7 @@ func NewOutgoingQueues( type queuedPDU struct { dbReceipt *receipt.Receipt - pdu *gomatrixserverlib.HeaderedEvent + pdu *types.HeaderedEvent } type queuedEDU struct { @@ -187,7 +188,7 @@ func (oqs *OutgoingQueues) clearQueue(oq *destinationQueue) { // SendEvent sends an event to the destinations func (oqs *OutgoingQueues) SendEvent( - ev *gomatrixserverlib.HeaderedEvent, origin spec.ServerName, + ev *types.HeaderedEvent, origin spec.ServerName, destinations []spec.ServerName, ) error { if oqs.disabled { diff --git a/federationapi/queue/queue_test.go b/federationapi/queue/queue_test.go index f42b56e55..c19239116 100644 --- a/federationapi/queue/queue_test.go +++ b/federationapi/queue/queue_test.go @@ -35,6 +35,7 @@ import ( "github.com/matrix-org/dendrite/federationapi/statistics" "github.com/matrix-org/dendrite/federationapi/storage" rsapi "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/process" "github.com/matrix-org/dendrite/test" @@ -101,14 +102,14 @@ func (f *stubFederationClient) P2PSendTransactionToRelay(ctx context.Context, u return fclient.EmptyResp{}, result } -func mustCreatePDU(t *testing.T) *gomatrixserverlib.HeaderedEvent { +func mustCreatePDU(t *testing.T) *types.HeaderedEvent { t.Helper() content := `{"type":"m.room.message"}` ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionV10).NewEventFromTrustedJSON([]byte(content), false) if err != nil { t.Fatalf("failed to create event: %v", err) } - return ev.Headered(gomatrixserverlib.RoomVersionV10) + return &types.HeaderedEvent{Event: ev} } func mustCreateEDU(t *testing.T) *gomatrixserverlib.EDU { diff --git a/federationapi/routing/backfill.go b/federationapi/routing/backfill.go index e99d54a63..066853877 100644 --- a/federationapi/routing/backfill.go +++ b/federationapi/routing/backfill.go @@ -23,6 +23,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/fclient" @@ -104,7 +105,7 @@ func Backfill( // Filter any event that's not from the requested room out. evs := make([]*gomatrixserverlib.Event, 0) - var ev *gomatrixserverlib.HeaderedEvent + var ev *types.HeaderedEvent for _, ev = range res.Events { if ev.RoomID() == roomID { evs = append(evs, ev.Event) @@ -113,7 +114,7 @@ func Backfill( eventJSONs := []json.RawMessage{} for _, e := range gomatrixserverlib.ReverseTopologicalOrdering( - evs, + gomatrixserverlib.ToPDUs(evs), gomatrixserverlib.TopologicalOrderByPrevEvents, ) { eventJSONs = append(eventJSONs, e.JSON()) diff --git a/federationapi/routing/eventauth.go b/federationapi/routing/eventauth.go index 89db3e98e..da1e77d8f 100644 --- a/federationapi/routing/eventauth.go +++ b/federationapi/routing/eventauth.go @@ -18,7 +18,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/roomserver/api" - "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib/fclient" "github.com/matrix-org/util" ) @@ -72,7 +72,7 @@ func GetEventAuth( return util.JSONResponse{ Code: http.StatusOK, JSON: fclient.RespEventAuth{ - AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(response.AuthChainEvents), + AuthEvents: types.NewEventJSONsFromHeaderedEvents(response.AuthChainEvents), }, } } diff --git a/federationapi/routing/invite.go b/federationapi/routing/invite.go index 880718922..6fa37f4a1 100644 --- a/federationapi/routing/invite.go +++ b/federationapi/routing/invite.go @@ -20,8 +20,10 @@ import ( "fmt" "net/http" + "github.com/getsentry/sentry-go" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/fclient" @@ -196,25 +198,44 @@ func processInvite( ) // Add the invite event to the roomserver. - inviteEvent := signedEvent.Headered(roomVer) + inviteEvent := &types.HeaderedEvent{Event: &signedEvent} request := &api.PerformInviteRequest{ Event: inviteEvent, InviteRoomState: strippedState, - RoomVersion: inviteEvent.RoomVersion, + RoomVersion: inviteEvent.Version(), SendAsServer: string(api.DoNotSendToOtherServers), TransactionID: nil, } - response := &api.PerformInviteResponse{} - if err := rsAPI.PerformInvite(ctx, request, response); err != nil { + + if err = rsAPI.PerformInvite(ctx, request); err != nil { util.GetLogger(ctx).WithError(err).Error("PerformInvite failed") return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: jsonerror.InternalServerError(), } } - if response.Error != nil { - return response.Error.JSONResponse() + + switch e := err.(type) { + case api.ErrInvalidID: + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.Unknown(e.Error()), + } + case api.ErrNotAllowed: + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden(e.Error()), + } + case nil: + default: + util.GetLogger(ctx).WithError(err).Error("PerformInvite failed") + sentry.CaptureException(err) + return util.JSONResponse{ + Code: http.StatusInternalServerError, + JSON: jsonerror.InternalServerError(), + } } + // Return the signed event to the originating server, it should then tell // the other servers in the room that we have been invited. if isInviteV2 { diff --git a/federationapi/routing/join.go b/federationapi/routing/join.go index 0d83a2af9..a6a7511c6 100644 --- a/federationapi/routing/join.go +++ b/federationapi/routing/join.go @@ -30,6 +30,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" ) @@ -42,9 +43,8 @@ func MakeJoin( roomID, userID string, remoteVersions []gomatrixserverlib.RoomVersion, ) util.JSONResponse { - verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID} - verRes := api.QueryRoomVersionForRoomResponse{} - if err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), &verReq, &verRes); err != nil { + roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID) + if err != nil { return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: jsonerror.InternalServerError(), @@ -57,7 +57,7 @@ func MakeJoin( // https://matrix.org/docs/spec/server_server/r0.1.3#get-matrix-federation-v1-make-join-roomid-userid remoteSupportsVersion := false for _, v := range remoteVersions { - if v == verRes.RoomVersion { + if v == roomVersion { remoteSupportsVersion = true break } @@ -66,7 +66,7 @@ func MakeJoin( if !remoteSupportsVersion { return util.JSONResponse{ Code: http.StatusBadRequest, - JSON: jsonerror.IncompatibleRoomVersion(verRes.RoomVersion), + JSON: jsonerror.IncompatibleRoomVersion(roomVersion), } } @@ -109,7 +109,7 @@ func MakeJoin( // Check if the restricted join is allowed. If the room doesn't // support restricted joins then this is effectively a no-op. - res, authorisedVia, err := checkRestrictedJoin(httpReq, rsAPI, verRes.RoomVersion, roomID, userID) + res, authorisedVia, err := checkRestrictedJoin(httpReq, rsAPI, roomVersion, roomID, userID) if err != nil { util.GetLogger(httpReq.Context()).WithError(err).Error("checkRestrictedJoin failed") return jsonerror.InternalServerError() @@ -144,7 +144,7 @@ func MakeJoin( } queryRes := api.QueryLatestEventsAndStateResponse{ - RoomVersion: verRes.RoomVersion, + RoomVersion: roomVersion, } event, err := eventutil.QueryAndBuildEvent(httpReq.Context(), &builder, cfg.Matrix, identity, time.Now(), rsAPI, &queryRes) if err == eventutil.ErrRoomNoExists { @@ -168,7 +168,7 @@ func MakeJoin( stateEvents[i] = queryRes.StateEvents[i].Event } - provider := gomatrixserverlib.NewAuthEvents(stateEvents) + provider := gomatrixserverlib.NewAuthEvents(gomatrixserverlib.ToPDUs(stateEvents)) if err = gomatrixserverlib.Allowed(event.Event, &provider); err != nil { return util.JSONResponse{ Code: http.StatusForbidden, @@ -180,7 +180,7 @@ func MakeJoin( Code: http.StatusOK, JSON: map[string]interface{}{ "event": builder, - "room_version": verRes.RoomVersion, + "room_version": roomVersion, }, } } @@ -197,21 +197,20 @@ func SendJoin( keys gomatrixserverlib.JSONVerifier, roomID, eventID string, ) util.JSONResponse { - verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID} - verRes := api.QueryRoomVersionForRoomResponse{} - if err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), &verReq, &verRes); err != nil { + roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID) + if err != nil { util.GetLogger(httpReq.Context()).WithError(err).Error("rsAPI.QueryRoomVersionForRoom failed") return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: jsonerror.InternalServerError(), } } - verImpl, err := gomatrixserverlib.GetRoomVersion(verRes.RoomVersion) + verImpl, err := gomatrixserverlib.GetRoomVersion(roomVersion) if err != nil { return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: jsonerror.UnsupportedRoomVersion( - fmt.Sprintf("QueryRoomVersionForRoom returned unknown room version: %s", verRes.RoomVersion), + fmt.Sprintf("QueryRoomVersionForRoom returned unknown room version: %s", roomVersion), ), } } @@ -415,7 +414,7 @@ func SendJoin( InputRoomEvents: []api.InputRoomEvent{ { Kind: api.KindNew, - Event: signed.Headered(stateAndAuthChainResponse.RoomVersion), + Event: &types.HeaderedEvent{Event: &signed}, SendAsServer: string(cfg.Matrix.ServerName), TransactionID: nil, }, @@ -445,8 +444,8 @@ func SendJoin( return util.JSONResponse{ Code: http.StatusOK, JSON: fclient.RespSendJoin{ - StateEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(stateAndAuthChainResponse.StateEvents), - AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(stateAndAuthChainResponse.AuthChainEvents), + StateEvents: types.NewEventJSONsFromHeaderedEvents(stateAndAuthChainResponse.StateEvents), + AuthEvents: types.NewEventJSONsFromHeaderedEvents(stateAndAuthChainResponse.AuthChainEvents), Origin: cfg.Matrix.ServerName, Event: signed.JSON(), }, @@ -521,7 +520,7 @@ func checkRestrictedJoin( } } -type eventsByDepth []*gomatrixserverlib.HeaderedEvent +type eventsByDepth []*types.HeaderedEvent func (e eventsByDepth) Len() int { return len(e) diff --git a/federationapi/routing/leave.go b/federationapi/routing/leave.go index d189cc538..c9b13b98a 100644 --- a/federationapi/routing/leave.go +++ b/federationapi/routing/leave.go @@ -20,6 +20,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/fclient" @@ -101,7 +102,7 @@ func MakeLeave( return util.JSONResponse{ Code: http.StatusOK, JSON: map[string]interface{}{ - "room_version": event.RoomVersion, + "room_version": event.Version(), "event": state, }, } @@ -113,7 +114,7 @@ func MakeLeave( for i := range queryRes.StateEvents { stateEvents[i] = queryRes.StateEvents[i].Event } - provider := gomatrixserverlib.NewAuthEvents(stateEvents) + provider := gomatrixserverlib.NewAuthEvents(gomatrixserverlib.ToPDUs(stateEvents)) if err = gomatrixserverlib.Allowed(event.Event, &provider); err != nil { return util.JSONResponse{ Code: http.StatusForbidden, @@ -124,7 +125,7 @@ func MakeLeave( return util.JSONResponse{ Code: http.StatusOK, JSON: map[string]interface{}{ - "room_version": event.RoomVersion, + "room_version": event.Version(), "event": builder, }, } @@ -140,21 +141,20 @@ func SendLeave( keys gomatrixserverlib.JSONVerifier, roomID, eventID string, ) util.JSONResponse { - verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID} - verRes := api.QueryRoomVersionForRoomResponse{} - if err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), &verReq, &verRes); err != nil { + roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID) + if err != nil { return util.JSONResponse{ Code: http.StatusBadRequest, JSON: jsonerror.UnsupportedRoomVersion(err.Error()), } } - verImpl, err := gomatrixserverlib.GetRoomVersion(verRes.RoomVersion) + verImpl, err := gomatrixserverlib.GetRoomVersion(roomVersion) if err != nil { return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: jsonerror.UnsupportedRoomVersion( - fmt.Sprintf("QueryRoomVersionForRoom returned unknown version: %s", verRes.RoomVersion), + fmt.Sprintf("QueryRoomVersionForRoom returned unknown version: %s", roomVersion), ), } } @@ -313,7 +313,7 @@ func SendLeave( InputRoomEvents: []api.InputRoomEvent{ { Kind: api.KindNew, - Event: event.Headered(verRes.RoomVersion), + Event: &types.HeaderedEvent{Event: event}, SendAsServer: string(cfg.Matrix.ServerName), TransactionID: nil, }, diff --git a/federationapi/routing/missingevents.go b/federationapi/routing/missingevents.go index 28dc31da6..23a99bf00 100644 --- a/federationapi/routing/missingevents.go +++ b/federationapi/routing/missingevents.go @@ -18,7 +18,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/roomserver/api" - "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib/fclient" "github.com/matrix-org/util" ) @@ -69,7 +69,7 @@ func GetMissingEvents( eventsResponse.Events = filterEvents(eventsResponse.Events, roomID) resp := fclient.RespMissingEvents{ - Events: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(eventsResponse.Events), + Events: types.NewEventJSONsFromHeaderedEvents(eventsResponse.Events), } return util.JSONResponse{ @@ -80,8 +80,8 @@ func GetMissingEvents( // filterEvents returns only those events with matching roomID func filterEvents( - events []*gomatrixserverlib.HeaderedEvent, roomID string, -) []*gomatrixserverlib.HeaderedEvent { + events []*types.HeaderedEvent, roomID string, +) []*types.HeaderedEvent { ref := events[:0] for _, ev := range events { if ev.RoomID() == roomID { diff --git a/federationapi/routing/peek.go b/federationapi/routing/peek.go index 2ccf7cfc4..45dc7f8c1 100644 --- a/federationapi/routing/peek.go +++ b/federationapi/routing/peek.go @@ -19,6 +19,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/fclient" @@ -35,10 +36,8 @@ func Peek( remoteVersions []gomatrixserverlib.RoomVersion, ) util.JSONResponse { // TODO: check if we're just refreshing an existing peek by querying the federationapi - - verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID} - verRes := api.QueryRoomVersionForRoomResponse{} - if err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), &verReq, &verRes); err != nil { + roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID) + if err != nil { return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: jsonerror.InternalServerError(), @@ -50,7 +49,7 @@ func Peek( // the peek URL. remoteSupportsVersion := false for _, v := range remoteVersions { - if v == verRes.RoomVersion { + if v == roomVersion { remoteSupportsVersion = true break } @@ -59,7 +58,7 @@ func Peek( if !remoteSupportsVersion { return util.JSONResponse{ Code: http.StatusBadRequest, - JSON: jsonerror.IncompatibleRoomVersion(verRes.RoomVersion), + JSON: jsonerror.IncompatibleRoomVersion(roomVersion), } } @@ -69,7 +68,7 @@ func Peek( renewalInterval := int64(60 * 60 * 1000 * 1000) var response api.PerformInboundPeekResponse - err := rsAPI.PerformInboundPeek( + err = rsAPI.PerformInboundPeek( httpReq.Context(), &api.PerformInboundPeekRequest{ RoomID: roomID, @@ -89,10 +88,10 @@ func Peek( } respPeek := fclient.RespPeek{ - StateEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(response.StateEvents), - AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(response.AuthChainEvents), + StateEvents: types.NewEventJSONsFromHeaderedEvents(response.StateEvents), + AuthEvents: types.NewEventJSONsFromHeaderedEvents(response.AuthChainEvents), RoomVersion: response.RoomVersion, - LatestEvent: response.LatestEvent.Unwrap(), + LatestEvent: response.LatestEvent.Event, RenewalInterval: renewalInterval, } diff --git a/federationapi/routing/state.go b/federationapi/routing/state.go index 52a8c2b17..aa2cb2835 100644 --- a/federationapi/routing/state.go +++ b/federationapi/routing/state.go @@ -19,7 +19,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/roomserver/api" - "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib/fclient" "github.com/matrix-org/util" ) @@ -42,8 +42,8 @@ func GetState( } return util.JSONResponse{Code: http.StatusOK, JSON: &fclient.RespState{ - AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(authChain), - StateEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(stateEvents), + AuthEvents: types.NewEventJSONsFromHeaderedEvents(authChain), + StateEvents: types.NewEventJSONsFromHeaderedEvents(stateEvents), }} } @@ -101,7 +101,7 @@ func getState( rsAPI api.FederationRoomserverAPI, roomID string, eventID string, -) (stateEvents, authEvents []*gomatrixserverlib.HeaderedEvent, errRes *util.JSONResponse) { +) (stateEvents, authEvents []*types.HeaderedEvent, errRes *util.JSONResponse) { // If we don't think we belong to this room then don't waste the effort // responding to expensive requests for it. if err := ErrorIfLocalServerNotInRoom(ctx, rsAPI, roomID); err != nil { @@ -157,7 +157,7 @@ func getState( return response.StateEvents, response.AuthChainEvents, nil } -func getIDsFromEvent(events []*gomatrixserverlib.HeaderedEvent) []string { +func getIDsFromEvent(events []*types.HeaderedEvent) []string { IDs := make([]string, len(events)) for i := range events { IDs[i] = events[i].EventID() diff --git a/federationapi/routing/threepid.go b/federationapi/routing/threepid.go index aaee939e1..1b854501b 100644 --- a/federationapi/routing/threepid.go +++ b/federationapi/routing/threepid.go @@ -24,6 +24,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib/fclient" @@ -67,11 +68,10 @@ func CreateInvitesFrom3PIDInvites( return *reqErr } - evs := []*gomatrixserverlib.HeaderedEvent{} + evs := []*types.HeaderedEvent{} for _, inv := range body.Invites { - verReq := api.QueryRoomVersionForRoomRequest{RoomID: inv.RoomID} - verRes := api.QueryRoomVersionForRoomResponse{} - if err := rsAPI.QueryRoomVersionForRoom(req.Context(), &verReq, &verRes); err != nil { + _, err := rsAPI.QueryRoomVersionForRoom(req.Context(), inv.RoomID) + if err != nil { return util.JSONResponse{ Code: http.StatusBadRequest, JSON: jsonerror.UnsupportedRoomVersion(err.Error()), @@ -86,7 +86,7 @@ func CreateInvitesFrom3PIDInvites( return jsonerror.InternalServerError() } if event != nil { - evs = append(evs, event.Headered(verRes.RoomVersion)) + evs = append(evs, &types.HeaderedEvent{Event: event}) } } @@ -162,9 +162,8 @@ func ExchangeThirdPartyInvite( } } - verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID} - verRes := api.QueryRoomVersionForRoomResponse{} - if err = rsAPI.QueryRoomVersionForRoom(httpReq.Context(), &verReq, &verRes); err != nil { + roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID) + if err != nil { return util.JSONResponse{ Code: http.StatusBadRequest, JSON: jsonerror.UnsupportedRoomVersion(err.Error()), @@ -185,7 +184,7 @@ func ExchangeThirdPartyInvite( // Ask the requesting server to sign the newly created event so we know it // acknowledged it - inviteReq, err := fclient.NewInviteV2Request(event.Headered(verRes.RoomVersion), nil) + inviteReq, err := fclient.NewInviteV2Request(event, nil) if err != nil { util.GetLogger(httpReq.Context()).WithError(err).Error("failed to make invite v2 request") return jsonerror.InternalServerError() @@ -195,9 +194,9 @@ func ExchangeThirdPartyInvite( util.GetLogger(httpReq.Context()).WithError(err).Error("federation.SendInvite failed") return jsonerror.InternalServerError() } - verImpl, err := gomatrixserverlib.GetRoomVersion(verRes.RoomVersion) + verImpl, err := gomatrixserverlib.GetRoomVersion(roomVersion) if err != nil { - util.GetLogger(httpReq.Context()).WithError(err).Errorf("unknown room version: %s", verRes.RoomVersion) + util.GetLogger(httpReq.Context()).WithError(err).Errorf("unknown room version: %s", roomVersion) return jsonerror.InternalServerError() } inviteEvent, err := verImpl.NewEventFromUntrustedJSON(signedEvent.Event) @@ -210,8 +209,8 @@ func ExchangeThirdPartyInvite( if err = api.SendEvents( httpReq.Context(), rsAPI, api.KindNew, - []*gomatrixserverlib.HeaderedEvent{ - inviteEvent.Headered(verRes.RoomVersion), + []*types.HeaderedEvent{ + {Event: inviteEvent}, }, request.Destination(), request.Origin(), @@ -239,12 +238,6 @@ func createInviteFrom3PIDInvite( inv invite, federation fclient.FederationClient, userAPI userapi.FederationUserAPI, ) (*gomatrixserverlib.Event, error) { - verReq := api.QueryRoomVersionForRoomRequest{RoomID: inv.RoomID} - verRes := api.QueryRoomVersionForRoomResponse{} - if err := rsAPI.QueryRoomVersionForRoom(ctx, &verReq, &verRes); err != nil { - return nil, err - } - _, server, err := gomatrixserverlib.SplitID('@', inv.MXID) if err != nil { return nil, err diff --git a/federationapi/storage/interface.go b/federationapi/storage/interface.go index 7652efec0..5388b4d2b 100644 --- a/federationapi/storage/interface.go +++ b/federationapi/storage/interface.go @@ -23,6 +23,7 @@ import ( "github.com/matrix-org/dendrite/federationapi/storage/shared/receipt" "github.com/matrix-org/dendrite/federationapi/types" + rstypes "github.com/matrix-org/dendrite/roomserver/types" ) type Database interface { @@ -38,7 +39,7 @@ type Database interface { StoreJSON(ctx context.Context, js string) (*receipt.Receipt, error) - GetPendingPDUs(ctx context.Context, serverName spec.ServerName, limit int) (pdus map[*receipt.Receipt]*gomatrixserverlib.HeaderedEvent, err error) + GetPendingPDUs(ctx context.Context, serverName spec.ServerName, limit int) (pdus map[*receipt.Receipt]*rstypes.HeaderedEvent, err error) GetPendingEDUs(ctx context.Context, serverName spec.ServerName, limit int) (edus map[*receipt.Receipt]*gomatrixserverlib.EDU, err error) AssociatePDUWithDestinations(ctx context.Context, destinations map[spec.ServerName]struct{}, dbReceipt *receipt.Receipt) error diff --git a/federationapi/storage/shared/storage_pdus.go b/federationapi/storage/shared/storage_pdus.go index b7fad06bd..5fabfbf20 100644 --- a/federationapi/storage/shared/storage_pdus.go +++ b/federationapi/storage/shared/storage_pdus.go @@ -22,7 +22,7 @@ import ( "fmt" "github.com/matrix-org/dendrite/federationapi/storage/shared/receipt" - "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib/spec" ) @@ -56,7 +56,7 @@ func (d *Database) GetPendingPDUs( serverName spec.ServerName, limit int, ) ( - events map[*receipt.Receipt]*gomatrixserverlib.HeaderedEvent, + events map[*receipt.Receipt]*types.HeaderedEvent, err error, ) { // Strictly speaking this doesn't need to be using the writer @@ -64,7 +64,7 @@ func (d *Database) GetPendingPDUs( // a guarantee of transactional isolation, it's actually useful // to know in SQLite mode that nothing else is trying to modify // the database. - events = make(map[*receipt.Receipt]*gomatrixserverlib.HeaderedEvent) + events = make(map[*receipt.Receipt]*types.HeaderedEvent) err = d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error { nids, err := d.FederationQueuePDUs.SelectQueuePDUs(ctx, txn, serverName, limit) if err != nil { @@ -87,7 +87,7 @@ func (d *Database) GetPendingPDUs( } for nid, blob := range blobs { - var event gomatrixserverlib.HeaderedEvent + var event types.HeaderedEvent if err := json.Unmarshal(blob, &event); err != nil { return fmt.Errorf("json.Unmarshal: %w", err) } diff --git a/go.mod b/go.mod index 8f04ffbc9..3c50331d0 100644 --- a/go.mod +++ b/go.mod @@ -18,11 +18,11 @@ require ( github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/kardianos/minwinsvc v1.0.2 - github.com/lib/pq v1.10.7 + github.com/lib/pq v1.10.8 github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 - github.com/matrix-org/gomatrixserverlib v0.0.0-20230424155704-8daeaebaa0bc + github.com/matrix-org/gomatrixserverlib v0.0.0-20230428192809-ff52c27efdce github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 github.com/mattn/go-sqlite3 v1.14.16 @@ -35,7 +35,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.13.0 github.com/sirupsen/logrus v1.9.0 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.2 github.com/tidwall/gjson v1.14.4 github.com/tidwall/sjson v1.2.5 github.com/uber/jaeger-client-go v2.30.0+incompatible @@ -49,6 +49,7 @@ require ( gopkg.in/h2non/bimg.v1 v1.1.9 gopkg.in/yaml.v2 v2.4.0 gotest.tools/v3 v3.4.0 + maunium.net/go/mautrix v0.15.1 modernc.org/sqlite v1.19.3 nhooyr.io/websocket v1.8.7 ) @@ -93,6 +94,7 @@ require ( github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/compress v1.16.0 // indirect github.com/kr/pretty v0.3.1 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/minio/highwayhash v1.0.2 // indirect @@ -117,6 +119,7 @@ require ( github.com/quic-go/qtls-go1-20 v0.1.0 // indirect github.com/quic-go/quic-go v0.32.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20220927061507-ef77025ab5aa // indirect + github.com/rs/zerolog v1.29.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect go.etcd.io/bbolt v1.3.6 // indirect @@ -131,6 +134,7 @@ require ( gopkg.in/macaroon.v2 v2.1.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/uint128 v1.2.0 // indirect + maunium.net/go/maulogger/v2 v2.4.1 // indirect modernc.org/cc/v3 v3.40.0 // indirect modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8 // indirect modernc.org/libc v1.21.4 // indirect diff --git a/go.sum b/go.sum index 374573c8f..73b330549 100644 --- a/go.sum +++ b/go.sum @@ -123,6 +123,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/codeclysm/extract v2.2.0+incompatible h1:q3wyckoA30bhUSiwdQezMqVhwd8+WGE64/GL//LtUhI= github.com/codeclysm/extract v2.2.0+incompatible/go.mod h1:2nhFMPHiU9At61hz+12bfrlpXSUrOnK+wR+KlGO4Uks= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -188,6 +189,7 @@ github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -313,21 +315,25 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.8 h1:3fdt97i/cwSU83+E0hZTC/Xpc9mTZxc6UWSCRcSbxiE= +github.com/lib/pq v1.10.8/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e h1:DP5RC0Z3XdyBEW5dKt8YPeN6vZbm6OzVaGVp7f1BQRM= github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e/go.mod h1:NgPCr+UavRGH6n5jmdX8DuqFZ4JiCWIJoZiuhTRLSUg= github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 h1:s7fexw2QV3YD/fRrzEDPNGgTlJlvXY0EHHnT87wF3OA= github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo= github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U= github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= -github.com/matrix-org/gomatrixserverlib v0.0.0-20230424155704-8daeaebaa0bc h1:F73iHhpTZxWVO6qbyGZxd7Ch44v1gK6xNQZ7QVos/Es= -github.com/matrix-org/gomatrixserverlib v0.0.0-20230424155704-8daeaebaa0bc/go.mod h1:7HTbSZe+CIdmeqVyFMekwD5dFU8khWQyngKATvd12FU= +github.com/matrix-org/gomatrixserverlib v0.0.0-20230428192809-ff52c27efdce h1:ZdNs5Qj1Cf42GfwUE01oPIZccSiaPJ/HcZP9qxHte8k= +github.com/matrix-org/gomatrixserverlib v0.0.0-20230428192809-ff52c27efdce/go.mod h1:7HTbSZe+CIdmeqVyFMekwD5dFU8khWQyngKATvd12FU= github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a h1:awrPDf9LEFySxTLKYBMCiObelNx/cBuv/wzllvCCH3A= github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a/go.mod h1:HchJX9oKMXaT2xYFs0Ha/6Zs06mxLU8k6F1ODnrGkeQ= github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y= github.com/matrix-org/util v0.0.0-20221111132719-399730281e66/go.mod h1:iBI1foelCqA09JJgPV0FYz4qA5dUXYOxMi57FxKBdd4= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= @@ -430,6 +436,9 @@ github.com/remyoudompheng/bigfft v0.0.0-20220927061507-ef77025ab5aa/go.mod h1:qq github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= +github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -453,8 +462,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -650,6 +659,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -848,6 +859,10 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +maunium.net/go/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= +maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= +maunium.net/go/mautrix v0.15.1 h1:pmCtMjYRpd83+2UL+KTRFYQo5to0373yulimvLK+1k0= +maunium.net/go/mautrix v0.15.1/go.mod h1:icQIrvz2NldkRLTuzSGzmaeuMUmw+fzO7UVycPeauN8= modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8 h1:0+dsXf0zeLx9ixj4nilg6jKe5Bg1ilzBwSFq4kJmIUc= diff --git a/internal/caching/cache_federationevents.go b/internal/caching/cache_federationevents.go index 24af51bdc..fc1f5496e 100644 --- a/internal/caching/cache_federationevents.go +++ b/internal/caching/cache_federationevents.go @@ -1,14 +1,15 @@ package caching import ( + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" ) // FederationCache contains the subset of functions needed for // a federation event cache. type FederationCache interface { - GetFederationQueuedPDU(eventNID int64) (event *gomatrixserverlib.HeaderedEvent, ok bool) - StoreFederationQueuedPDU(eventNID int64, event *gomatrixserverlib.HeaderedEvent) + GetFederationQueuedPDU(eventNID int64) (event *types.HeaderedEvent, ok bool) + StoreFederationQueuedPDU(eventNID int64, event *types.HeaderedEvent) EvictFederationQueuedPDU(eventNID int64) GetFederationQueuedEDU(eventNID int64) (event *gomatrixserverlib.EDU, ok bool) @@ -16,11 +17,11 @@ type FederationCache interface { EvictFederationQueuedEDU(eventNID int64) } -func (c Caches) GetFederationQueuedPDU(eventNID int64) (*gomatrixserverlib.HeaderedEvent, bool) { +func (c Caches) GetFederationQueuedPDU(eventNID int64) (*types.HeaderedEvent, bool) { return c.FederationPDUs.Get(eventNID) } -func (c Caches) StoreFederationQueuedPDU(eventNID int64, event *gomatrixserverlib.HeaderedEvent) { +func (c Caches) StoreFederationQueuedPDU(eventNID int64, event *types.HeaderedEvent) { c.FederationPDUs.Set(eventNID, event) } diff --git a/internal/caching/caches.go b/internal/caching/caches.go index a678632eb..f4bbea789 100644 --- a/internal/caching/caches.go +++ b/internal/caching/caches.go @@ -33,7 +33,7 @@ type Caches struct { RoomServerStateKeyNIDs Cache[string, types.EventStateKeyNID] // event state key -> eventStateKey NID RoomServerEventTypeNIDs Cache[string, types.EventTypeNID] // eventType -> eventType NID RoomServerEventTypes Cache[types.EventTypeNID, string] // eventType NID -> eventType - FederationPDUs Cache[int64, *gomatrixserverlib.HeaderedEvent] // queue NID -> PDU + FederationPDUs Cache[int64, *types.HeaderedEvent] // queue NID -> PDU FederationEDUs Cache[int64, *gomatrixserverlib.EDU] // queue NID -> EDU SpaceSummaryRooms Cache[string, fclient.MSC2946SpacesResponse] // room ID -> space response LazyLoading Cache[lazyLoadingCacheKey, string] // composite key -> event ID diff --git a/internal/caching/impl_ristretto.go b/internal/caching/impl_ristretto.go index 4656b6b7e..247eec613 100644 --- a/internal/caching/impl_ristretto.go +++ b/internal/caching/impl_ristretto.go @@ -131,8 +131,8 @@ func NewRistrettoCache(maxCost config.DataUnit, maxAge time.Duration, enableProm Prefix: eventTypeNIDCache, MaxAge: maxAge, }, - FederationPDUs: &RistrettoCostedCachePartition[int64, *gomatrixserverlib.HeaderedEvent]{ // queue NID -> PDU - &RistrettoCachePartition[int64, *gomatrixserverlib.HeaderedEvent]{ + FederationPDUs: &RistrettoCostedCachePartition[int64, *types.HeaderedEvent]{ // queue NID -> PDU + &RistrettoCachePartition[int64, *types.HeaderedEvent]{ cache: cache, Prefix: federationPDUsCache, Mutable: true, diff --git a/internal/eventutil/events.go b/internal/eventutil/events.go index 283c91d89..72408d2f1 100644 --- a/internal/eventutil/events.go +++ b/internal/eventutil/events.go @@ -21,6 +21,7 @@ import ( "time" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/gomatrixserverlib/fclient" "github.com/matrix-org/gomatrixserverlib/spec" @@ -43,7 +44,7 @@ func QueryAndBuildEvent( builder *gomatrixserverlib.EventBuilder, cfg *config.Global, identity *fclient.SigningIdentity, evTime time.Time, rsAPI api.QueryLatestEventsAndStateAPI, queryRes *api.QueryLatestEventsAndStateResponse, -) (*gomatrixserverlib.HeaderedEvent, error) { +) (*types.HeaderedEvent, error) { if queryRes == nil { queryRes = &api.QueryLatestEventsAndStateResponse{} } @@ -63,7 +64,7 @@ func BuildEvent( builder *gomatrixserverlib.EventBuilder, cfg *config.Global, identity *fclient.SigningIdentity, evTime time.Time, eventsNeeded *gomatrixserverlib.StateNeeded, queryRes *api.QueryLatestEventsAndStateResponse, -) (*gomatrixserverlib.HeaderedEvent, error) { +) (*types.HeaderedEvent, error) { if err := addPrevEventsToEvent(builder, eventsNeeded, queryRes); err != nil { return nil, err } @@ -76,7 +77,7 @@ func BuildEvent( return nil, err } - return event.Headered(queryRes.RoomVersion), nil + return &types.HeaderedEvent{Event: event}, nil } // queryRequiredEventsForBuilder queries the roomserver for auth/prev events needed for this builder. diff --git a/internal/hooks/hooks.go b/internal/hooks/hooks.go index d6c79e989..802ff8187 100644 --- a/internal/hooks/hooks.go +++ b/internal/hooks/hooks.go @@ -21,17 +21,17 @@ import ( ) const ( - // KindNewEventPersisted is a hook which is called with *gomatrixserverlib.HeaderedEvent + // KindNewEventPersisted is a hook which is called with *types.HeaderedEvent // It is run when a new event is persisted in the roomserver. // Usage: // hooks.Attach(hooks.KindNewEventPersisted, func(headeredEvent interface{}) { ... }) KindNewEventPersisted = "new_event_persisted" - // KindNewEventReceived is a hook which is called with *gomatrixserverlib.HeaderedEvent + // KindNewEventReceived is a hook which is called with *types.HeaderedEvent // It is run before a new event is processed by the roomserver. This hook can be used // to modify the event before it is persisted by adding data to `unsigned`. // Usage: // hooks.Attach(hooks.KindNewEventReceived, func(headeredEvent interface{}) { - // ev := headeredEvent.(*gomatrixserverlib.HeaderedEvent) + // ev := headeredEvent.(*types.HeaderedEvent) // _ = ev.SetUnsignedField("key", "val") // }) KindNewEventReceived = "new_event_received" diff --git a/internal/pushrules/evaluate.go b/internal/pushrules/evaluate.go index fc8e0f174..7c98efd30 100644 --- a/internal/pushrules/evaluate.go +++ b/internal/pushrules/evaluate.go @@ -53,7 +53,7 @@ func NewRuleSetEvaluator(ec EvaluationContext, ruleSet *RuleSet) *RuleSetEvaluat // MatchEvent returns the first matching rule. Returns nil if there // was no match rule. -func (rse *RuleSetEvaluator) MatchEvent(event *gomatrixserverlib.Event) (*Rule, error) { +func (rse *RuleSetEvaluator) MatchEvent(event gomatrixserverlib.PDU) (*Rule, error) { // TODO: server-default rules have lower priority than user rules, // but they are stored together with the user rules. It's a bit // unclear what the specification (11.14.1.4 Predefined rules) @@ -83,7 +83,7 @@ func (rse *RuleSetEvaluator) MatchEvent(event *gomatrixserverlib.Event) (*Rule, return nil, nil } -func ruleMatches(rule *Rule, kind Kind, event *gomatrixserverlib.Event, ec EvaluationContext) (bool, error) { +func ruleMatches(rule *Rule, kind Kind, event gomatrixserverlib.PDU, ec EvaluationContext) (bool, error) { if !rule.Enabled { return false, nil } @@ -120,7 +120,7 @@ func ruleMatches(rule *Rule, kind Kind, event *gomatrixserverlib.Event, ec Evalu } } -func conditionMatches(cond *Condition, event *gomatrixserverlib.Event, ec EvaluationContext) (bool, error) { +func conditionMatches(cond *Condition, event gomatrixserverlib.PDU, ec EvaluationContext) (bool, error) { switch cond.Kind { case EventMatchCondition: if cond.Pattern == nil { @@ -150,7 +150,7 @@ func conditionMatches(cond *Condition, event *gomatrixserverlib.Event, ec Evalua } } -func patternMatches(key, pattern string, event *gomatrixserverlib.Event) (bool, error) { +func patternMatches(key, pattern string, event gomatrixserverlib.PDU) (bool, error) { // It doesn't make sense for an empty pattern to match anything. if pattern == "" { return false, nil diff --git a/internal/pushrules/evaluate_test.go b/internal/pushrules/evaluate_test.go index 4fa17b294..5045a864e 100644 --- a/internal/pushrules/evaluate_test.go +++ b/internal/pushrules/evaluate_test.go @@ -29,7 +29,7 @@ func TestRuleSetEvaluatorMatchEvent(t *testing.T) { Name string RuleSet RuleSet Want *Rule - Event *gomatrixserverlib.Event + Event gomatrixserverlib.PDU }{ {"empty", RuleSet{}, nil, ev}, {"defaultCanWin", RuleSet{Override: []*Rule{defaultEnabled}}, defaultEnabled, ev}, @@ -188,7 +188,7 @@ func TestPatternMatches(t *testing.T) { } } -func mustEventFromJSON(t *testing.T, json string) *gomatrixserverlib.Event { +func mustEventFromJSON(t *testing.T, json string) gomatrixserverlib.PDU { ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionV7).NewEventFromTrustedJSON([]byte(json), false) if err != nil { t.Fatal(err) diff --git a/internal/transactionrequest.go b/internal/transactionrequest.go index bb16cefe6..29107b4d2 100644 --- a/internal/transactionrequest.go +++ b/internal/transactionrequest.go @@ -25,6 +25,7 @@ import ( "github.com/matrix-org/dendrite/federationapi/producers" "github.com/matrix-org/dendrite/federationapi/types" "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" syncTypes "github.com/matrix-org/dendrite/syncapi/types" userAPI "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" @@ -115,14 +116,13 @@ func (t *TxnReq) ProcessTransaction(ctx context.Context) (*fclient.RespSend, *ut if v, ok := roomVersions[roomID]; ok { return v } - verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID} - verRes := api.QueryRoomVersionForRoomResponse{} - if err := t.rsAPI.QueryRoomVersionForRoom(ctx, &verReq, &verRes); err != nil { - util.GetLogger(ctx).WithError(err).Debug("Transaction: Failed to query room version for room", verReq.RoomID) + roomVersion, err := t.rsAPI.QueryRoomVersionForRoom(ctx, roomID) + if err != nil { + util.GetLogger(ctx).WithError(err).Debug("Transaction: Failed to query room version for room", roomID) return "" } - roomVersions[roomID] = verRes.RoomVersion - return verRes.RoomVersion + roomVersions[roomID] = roomVersion + return roomVersion } for _, pdu := range t.PDUs { @@ -168,7 +168,7 @@ func (t *TxnReq) ProcessTransaction(ctx context.Context) (*fclient.RespSend, *ut } continue } - if err = event.VerifyEventSignatures(ctx, t.keys); err != nil { + if err = gomatrixserverlib.VerifyEventSignatures(ctx, event, t.keys); err != nil { util.GetLogger(ctx).WithError(err).Debugf("Transaction: Couldn't validate signature of event %q", event.EventID()) results[event.EventID()] = fclient.PDUResult{ Error: err.Error(), @@ -183,8 +183,8 @@ func (t *TxnReq) ProcessTransaction(ctx context.Context) (*fclient.RespSend, *ut ctx, t.rsAPI, api.KindNew, - []*gomatrixserverlib.HeaderedEvent{ - event.Headered(roomVersion), + []*rstypes.HeaderedEvent{ + {Event: event}, }, t.Destination, t.Origin, diff --git a/internal/transactionrequest_test.go b/internal/transactionrequest_test.go index 6b4c6129c..949010880 100644 --- a/internal/transactionrequest_test.go +++ b/internal/transactionrequest_test.go @@ -31,6 +31,7 @@ import ( "github.com/matrix-org/dendrite/federationapi/producers" rsAPI "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/process" @@ -59,8 +60,8 @@ var ( } testEvent = []byte(`{"auth_events":["$x4MKEPRSF6OGlo0qpnsP3BfSmYX5HhVlykOsQH3ECyg","$BcEcbZnlFLB5rxSNSZNBn6fO3jU/TKAJ79wfKyCQLiU"],"content":{"body":"Test Message"},"depth":3917,"hashes":{"sha256":"cNAWtlHIegrji0mMA6x1rhpYCccY8W1NsWZqSpJFhjs"},"origin":"localhost","origin_server_ts":0,"prev_events":["$4GDB0bVjkWwS3G4noUZCq5oLWzpBYpwzdMcf7gj24CI"],"room_id":"!roomid:localhost","sender":"@userid:localhost","signatures":{"localhost":{"ed25519:auto":"NKym6Kcy3u9mGUr21Hjfe3h7DfDilDhN5PqztT0QZ4NTZ+8Y7owseLolQVXp+TvNjecvzdDywsXXVvGiuQiWAQ"}},"type":"m.room.message"}`) testRoomVersion = gomatrixserverlib.RoomVersionV1 - testEvents = []*gomatrixserverlib.HeaderedEvent{} - testStateEvents = make(map[gomatrixserverlib.StateKeyTuple]*gomatrixserverlib.HeaderedEvent) + testEvents = []*rstypes.HeaderedEvent{} + testStateEvents = make(map[gomatrixserverlib.StateKeyTuple]*rstypes.HeaderedEvent) ) type FakeRsAPI struct { @@ -72,14 +73,12 @@ type FakeRsAPI struct { func (r *FakeRsAPI) QueryRoomVersionForRoom( ctx context.Context, - req *rsAPI.QueryRoomVersionForRoomRequest, - res *rsAPI.QueryRoomVersionForRoomResponse, -) error { + roomID string, +) (gomatrixserverlib.RoomVersion, error) { if r.shouldFailQuery { - return fmt.Errorf("Failure") + return "", fmt.Errorf("Failure") } - res.RoomVersion = gomatrixserverlib.RoomVersionV10 - return nil + return gomatrixserverlib.RoomVersionV10, nil } func (r *FakeRsAPI) QueryServerBannedFromRoom( @@ -637,7 +636,7 @@ func init() { if err != nil { panic("cannot load test data: " + err.Error()) } - h := e.Headered(testRoomVersion) + h := &rstypes.HeaderedEvent{Event: e} testEvents = append(testEvents, h) if e.StateKey() != nil { testStateEvents[gomatrixserverlib.StateKeyTuple{ @@ -722,11 +721,9 @@ func (t *testRoomserverAPI) QueryServerJoinedToRoom( // Asks for the room version for a given room. func (t *testRoomserverAPI) QueryRoomVersionForRoom( ctx context.Context, - request *rsAPI.QueryRoomVersionForRoomRequest, - response *rsAPI.QueryRoomVersionForRoomResponse, -) error { - response.RoomVersion = testRoomVersion - return nil + roomID string, +) (gomatrixserverlib.RoomVersion, error) { + return testRoomVersion, nil } func (t *testRoomserverAPI) QueryServerBannedFromRoom( @@ -781,7 +778,7 @@ NextPDU: } } -func assertInputRoomEvents(t *testing.T, got []rsAPI.InputRoomEvent, want []*gomatrixserverlib.HeaderedEvent) { +func assertInputRoomEvents(t *testing.T, got []rsAPI.InputRoomEvent, want []*rstypes.HeaderedEvent) { for _, g := range got { fmt.Println("GOT ", g.Event.EventID()) } @@ -805,7 +802,7 @@ func TestBasicTransaction(t *testing.T) { } txn := mustCreateTransaction(rsAPI, pdus) mustProcessTransaction(t, txn, nil) - assertInputRoomEvents(t, rsAPI.inputRoomEvents, []*gomatrixserverlib.HeaderedEvent{testEvents[len(testEvents)-1]}) + assertInputRoomEvents(t, rsAPI.inputRoomEvents, []*rstypes.HeaderedEvent{testEvents[len(testEvents)-1]}) } // The purpose of this test is to check that if the event received fails auth checks the event is still sent to the roomserver @@ -818,5 +815,5 @@ func TestTransactionFailAuthChecks(t *testing.T) { txn := mustCreateTransaction(rsAPI, pdus) mustProcessTransaction(t, txn, []string{}) // expect message to be sent to the roomserver - assertInputRoomEvents(t, rsAPI.inputRoomEvents, []*gomatrixserverlib.HeaderedEvent{testEvents[len(testEvents)-1]}) + assertInputRoomEvents(t, rsAPI.inputRoomEvents, []*rstypes.HeaderedEvent{testEvents[len(testEvents)-1]}) } diff --git a/relayapi/internal/perform.go b/relayapi/internal/perform.go index 457652112..79d600abf 100644 --- a/relayapi/internal/perform.go +++ b/relayapi/internal/perform.go @@ -101,11 +101,11 @@ func (r *RelayInternalAPI) QueryTransactions( userID spec.UserID, previousEntry fclient.RelayEntry, ) (api.QueryRelayTransactionsResponse, error) { - logrus.Infof("QueryTransactions for %s", userID.Raw()) + logrus.Infof("QueryTransactions for %s", userID.String()) if previousEntry.EntryID > 0 { logrus.Infof("Cleaning previous entry (%v) from db for %s", previousEntry.EntryID, - userID.Raw(), + userID.String(), ) prevReceipt := receipt.NewReceipt(previousEntry.EntryID) err := r.db.CleanTransactions(ctx, userID, []*receipt.Receipt{&prevReceipt}) @@ -123,12 +123,12 @@ func (r *RelayInternalAPI) QueryTransactions( response := api.QueryRelayTransactionsResponse{} if transaction != nil && receipt != nil { - logrus.Infof("Obtained transaction (%v) for %s", transaction.TransactionID, userID.Raw()) + logrus.Infof("Obtained transaction (%v) for %s", transaction.TransactionID, userID.String()) response.Transaction = *transaction response.EntryID = receipt.GetNID() response.EntriesQueued = true } else { - logrus.Infof("No more entries in the queue for %s", userID.Raw()) + logrus.Infof("No more entries in the queue for %s", userID.String()) response.EntryID = 0 response.EntriesQueued = false } diff --git a/relayapi/routing/relaytxn.go b/relayapi/routing/relaytxn.go index 2fc61373a..9a3ced529 100644 --- a/relayapi/routing/relaytxn.go +++ b/relayapi/routing/relaytxn.go @@ -34,7 +34,7 @@ func GetTransactionFromRelay( relayAPI api.RelayInternalAPI, userID spec.UserID, ) util.JSONResponse { - logrus.Infof("Processing relay_txn for %s", userID.Raw()) + logrus.Infof("Processing relay_txn for %s", userID.String()) var previousEntry fclient.RelayEntry if err := json.Unmarshal(fedReq.Content(), &previousEntry); err != nil { diff --git a/relayapi/routing/relaytxn_test.go b/relayapi/routing/relaytxn_test.go index e6d2d9e5d..1041d8e7e 100644 --- a/relayapi/routing/relaytxn_test.go +++ b/relayapi/routing/relaytxn_test.go @@ -35,7 +35,7 @@ func createQuery( prevEntry fclient.RelayEntry, ) fclient.FederationRequest { var federationPathPrefixV1 = "/_matrix/federation/v1" - path := federationPathPrefixV1 + "/relay_txn/" + userID.Raw() + path := federationPathPrefixV1 + "/relay_txn/" + userID.String() request := fclient.NewFederationRequest("GET", userID.Domain(), "relay", path) request.SetContent(prevEntry) diff --git a/relayapi/routing/sendrelay.go b/relayapi/routing/sendrelay.go index e4794dc4d..6ff08e205 100644 --- a/relayapi/routing/sendrelay.go +++ b/relayapi/routing/sendrelay.go @@ -36,7 +36,7 @@ func SendTransactionToRelay( txnID gomatrixserverlib.TransactionID, userID spec.UserID, ) util.JSONResponse { - logrus.Infof("Processing send_relay for %s", userID.Raw()) + logrus.Infof("Processing send_relay for %s", userID.String()) var txnEvents fclient.RelayEvents if err := json.Unmarshal(fedReq.Content(), &txnEvents); err != nil { diff --git a/relayapi/routing/sendrelay_test.go b/relayapi/routing/sendrelay_test.go index 05dfbe6d1..cac109e19 100644 --- a/relayapi/routing/sendrelay_test.go +++ b/relayapi/routing/sendrelay_test.go @@ -52,7 +52,7 @@ func createFederationRequest( content interface{}, ) fclient.FederationRequest { var federationPathPrefixV1 = "/_matrix/federation/v1" - path := federationPathPrefixV1 + "/send_relay/" + string(txnID) + "/" + userID.Raw() + path := federationPathPrefixV1 + "/send_relay/" + string(txnID) + "/" + userID.String() request := fclient.NewFederationRequest("PUT", origin, destination, path) request.SetContent(content) diff --git a/roomserver/acls/acls.go b/roomserver/acls/acls.go index 80d45e8c3..3850c256e 100644 --- a/roomserver/acls/acls.go +++ b/roomserver/acls/acls.go @@ -23,6 +23,7 @@ import ( "strings" "sync" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/sirupsen/logrus" @@ -34,7 +35,7 @@ type ServerACLDatabase interface { // GetStateEvent returns the state event of a given type for a given room with a given state key // If no event could be found, returns nil // If there was an issue during the retrieval, returns an error - GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*gomatrixserverlib.HeaderedEvent, error) + GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*types.HeaderedEvent, error) } type ServerACLs struct { diff --git a/roomserver/api/api.go b/roomserver/api/api.go index 4ce40e3ea..2aaecbbf4 100644 --- a/roomserver/api/api.go +++ b/roomserver/api/api.go @@ -11,6 +11,25 @@ import ( userapi "github.com/matrix-org/dendrite/userapi/api" ) +// ErrInvalidID is an error returned if the userID is invalid +type ErrInvalidID struct { + Err error +} + +func (e ErrInvalidID) Error() string { + return e.Err.Error() +} + +// ErrNotAllowed is an error returned if the user is not allowed +// to execute some action (e.g. invite) +type ErrNotAllowed struct { + Err error +} + +func (e ErrNotAllowed) Error() string { + return e.Err.Error() +} + // RoomserverInputAPI is used to write events to the room server. type RoomserverInternalAPI interface { SyncRoomserverAPI @@ -102,7 +121,7 @@ type SyncRoomserverAPI interface { ) error // QueryMembershipAtEvent queries the memberships at the given events. - // Returns a map from eventID to a slice of gomatrixserverlib.HeaderedEvent. + // Returns a map from eventID to a slice of types.HeaderedEvent. QueryMembershipAtEvent( ctx context.Context, request *QueryMembershipAtEventRequest, @@ -143,24 +162,24 @@ type ClientRoomserverAPI interface { QueryStateAfterEvents(ctx context.Context, req *QueryStateAfterEventsRequest, res *QueryStateAfterEventsResponse) error // QueryKnownUsers returns a list of users that we know about from our joined rooms. QueryKnownUsers(ctx context.Context, req *QueryKnownUsersRequest, res *QueryKnownUsersResponse) error - QueryRoomVersionForRoom(ctx context.Context, req *QueryRoomVersionForRoomRequest, res *QueryRoomVersionForRoomResponse) error + QueryRoomVersionForRoom(ctx context.Context, roomID string) (gomatrixserverlib.RoomVersion, error) QueryPublishedRooms(ctx context.Context, req *QueryPublishedRoomsRequest, res *QueryPublishedRoomsResponse) error GetRoomIDForAlias(ctx context.Context, req *GetRoomIDForAliasRequest, res *GetRoomIDForAliasResponse) error GetAliasesForRoomID(ctx context.Context, req *GetAliasesForRoomIDRequest, res *GetAliasesForRoomIDResponse) error // PerformRoomUpgrade upgrades a room to a newer version - PerformRoomUpgrade(ctx context.Context, req *PerformRoomUpgradeRequest, resp *PerformRoomUpgradeResponse) error - PerformAdminEvacuateRoom(ctx context.Context, req *PerformAdminEvacuateRoomRequest, res *PerformAdminEvacuateRoomResponse) error - PerformAdminEvacuateUser(ctx context.Context, req *PerformAdminEvacuateUserRequest, res *PerformAdminEvacuateUserResponse) error - PerformAdminPurgeRoom(ctx context.Context, req *PerformAdminPurgeRoomRequest, res *PerformAdminPurgeRoomResponse) error - PerformAdminDownloadState(ctx context.Context, req *PerformAdminDownloadStateRequest, res *PerformAdminDownloadStateResponse) error - PerformPeek(ctx context.Context, req *PerformPeekRequest, res *PerformPeekResponse) error - PerformUnpeek(ctx context.Context, req *PerformUnpeekRequest, res *PerformUnpeekResponse) error - PerformInvite(ctx context.Context, req *PerformInviteRequest, res *PerformInviteResponse) error - PerformJoin(ctx context.Context, req *PerformJoinRequest, res *PerformJoinResponse) error + PerformRoomUpgrade(ctx context.Context, roomID, userID string, roomVersion gomatrixserverlib.RoomVersion) (newRoomID string, err error) + PerformAdminEvacuateRoom(ctx context.Context, roomID string) (affected []string, err error) + PerformAdminEvacuateUser(ctx context.Context, userID string) (affected []string, err error) + PerformAdminPurgeRoom(ctx context.Context, roomID string) error + PerformAdminDownloadState(ctx context.Context, roomID, userID string, serverName spec.ServerName) error + PerformPeek(ctx context.Context, req *PerformPeekRequest) (roomID string, err error) + PerformUnpeek(ctx context.Context, roomID, userID, deviceID string) error + PerformInvite(ctx context.Context, req *PerformInviteRequest) error + PerformJoin(ctx context.Context, req *PerformJoinRequest) (roomID string, joinedVia spec.ServerName, err error) PerformLeave(ctx context.Context, req *PerformLeaveRequest, res *PerformLeaveResponse) error - PerformPublish(ctx context.Context, req *PerformPublishRequest, res *PerformPublishResponse) error + PerformPublish(ctx context.Context, req *PerformPublishRequest) error // PerformForget forgets a rooms history for a specific user PerformForget(ctx context.Context, req *PerformForgetRequest, resp *PerformForgetResponse) error SetRoomAlias(ctx context.Context, req *SetRoomAliasRequest, res *SetRoomAliasResponse) error @@ -172,8 +191,8 @@ type UserRoomserverAPI interface { KeyserverRoomserverAPI QueryCurrentState(ctx context.Context, req *QueryCurrentStateRequest, res *QueryCurrentStateResponse) error QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error - PerformAdminEvacuateUser(ctx context.Context, req *PerformAdminEvacuateUserRequest, res *PerformAdminEvacuateUserResponse) error - PerformJoin(ctx context.Context, req *PerformJoinRequest, res *PerformJoinResponse) error + PerformAdminEvacuateUser(ctx context.Context, userID string) (affected []string, err error) + PerformJoin(ctx context.Context, req *PerformJoinRequest) (roomID string, joinedVia spec.ServerName, err error) } type FederationRoomserverAPI interface { @@ -183,7 +202,7 @@ type FederationRoomserverAPI interface { // QueryServerBannedFromRoom returns whether a server is banned from a room by server ACLs. QueryServerBannedFromRoom(ctx context.Context, req *QueryServerBannedFromRoomRequest, res *QueryServerBannedFromRoomResponse) error QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error - QueryRoomVersionForRoom(ctx context.Context, req *QueryRoomVersionForRoomRequest, res *QueryRoomVersionForRoomResponse) error + QueryRoomVersionForRoom(ctx context.Context, roomID string) (gomatrixserverlib.RoomVersion, error) GetRoomIDForAlias(ctx context.Context, req *GetRoomIDForAliasRequest, res *GetRoomIDForAliasResponse) error // QueryEventsByID queries a list of events by event ID for one room. If no room is specified, it will try to determine // which room to use by querying the first events roomID. @@ -202,7 +221,7 @@ type FederationRoomserverAPI interface { QueryRoomsForUser(ctx context.Context, req *QueryRoomsForUserRequest, res *QueryRoomsForUserResponse) error QueryRestrictedJoinAllowed(ctx context.Context, req *QueryRestrictedJoinAllowedRequest, res *QueryRestrictedJoinAllowedResponse) error PerformInboundPeek(ctx context.Context, req *PerformInboundPeekRequest, res *PerformInboundPeekResponse) error - PerformInvite(ctx context.Context, req *PerformInviteRequest, res *PerformInviteResponse) error + PerformInvite(ctx context.Context, req *PerformInviteRequest) error // Query a given amount (or less) of events prior to a given set of events. PerformBackfill(ctx context.Context, req *PerformBackfillRequest, res *PerformBackfillResponse) error } diff --git a/roomserver/api/input.go b/roomserver/api/input.go index b52317cd5..8947ad624 100644 --- a/roomserver/api/input.go +++ b/roomserver/api/input.go @@ -18,6 +18,7 @@ package api import ( "fmt" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" ) @@ -67,7 +68,7 @@ type InputRoomEvent struct { // This controls how the event is processed. Kind Kind `json:"kind"` // The event JSON for the event to add. - Event *gomatrixserverlib.HeaderedEvent `json:"event"` + Event *types.HeaderedEvent `json:"event"` // Which server told us about this event. Origin spec.ServerName `json:"origin"` // Whether the state is supplied as a list of event IDs or whether it diff --git a/roomserver/api/output.go b/roomserver/api/output.go index 737887473..16b504957 100644 --- a/roomserver/api/output.go +++ b/roomserver/api/output.go @@ -15,6 +15,7 @@ package api import ( + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" ) @@ -107,7 +108,7 @@ const ( // prev_events. type OutputNewRoomEvent struct { // The Event. - Event *gomatrixserverlib.HeaderedEvent `json:"event"` + Event *types.HeaderedEvent `json:"event"` // Does the event completely rewrite the room state? If so, then AddsStateEventIDs // will contain the entire room state. RewritesState bool `json:"rewrites_state,omitempty"` @@ -170,8 +171,8 @@ type OutputNewRoomEvent struct { HistoryVisibility gomatrixserverlib.HistoryVisibility `json:"history_visibility"` } -func (o *OutputNewRoomEvent) NeededStateEventIDs() ([]*gomatrixserverlib.HeaderedEvent, []string) { - addsStateEvents := make([]*gomatrixserverlib.HeaderedEvent, 0, 1) +func (o *OutputNewRoomEvent) NeededStateEventIDs() ([]*types.HeaderedEvent, []string) { + addsStateEvents := make([]*types.HeaderedEvent, 0, 1) missingEventIDs := make([]string, 0, len(o.AddsStateEventIDs)) for _, eventID := range o.AddsStateEventIDs { if eventID != o.Event.EventID() { @@ -194,7 +195,7 @@ func (o *OutputNewRoomEvent) NeededStateEventIDs() ([]*gomatrixserverlib.Headere // should build their current room state up from OutputNewRoomEvents only. type OutputOldRoomEvent struct { // The Event. - Event *gomatrixserverlib.HeaderedEvent `json:"event"` + Event *types.HeaderedEvent `json:"event"` HistoryVisibility gomatrixserverlib.HistoryVisibility `json:"history_visibility"` } @@ -205,7 +206,7 @@ type OutputNewInviteEvent struct { // The room version of the invited room. RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"` // The "m.room.member" invite event. - Event *gomatrixserverlib.HeaderedEvent `json:"event"` + Event *types.HeaderedEvent `json:"event"` } // An OutputRetireInviteEvent is written whenever an existing invite is no longer @@ -232,7 +233,7 @@ type OutputRedactedEvent struct { // The event ID that was redacted RedactedEventID string // The value of `unsigned.redacted_because` - the redaction event itself - RedactedBecause *gomatrixserverlib.HeaderedEvent + RedactedBecause *types.HeaderedEvent } // An OutputNewPeek is written whenever a user starts peeking into a room diff --git a/roomserver/api/perform.go b/roomserver/api/perform.go index e125a3008..c6e5f5a1c 100644 --- a/roomserver/api/perform.go +++ b/roomserver/api/perform.go @@ -1,80 +1,11 @@ package api import ( - "encoding/json" - "fmt" - "net/http" - + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/fclient" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/util" - - "github.com/matrix-org/dendrite/clientapi/jsonerror" -) - -type PerformErrorCode int - -type PerformError struct { - Msg string - RemoteCode int // remote HTTP status code, for PerformErrRemote - Code PerformErrorCode -} - -func (p *PerformError) Error() string { - return fmt.Sprintf("%d : %s", p.Code, p.Msg) -} - -// JSONResponse maps error codes to suitable HTTP error codes, defaulting to 500. -func (p *PerformError) JSONResponse() util.JSONResponse { - switch p.Code { - case PerformErrorBadRequest: - return util.JSONResponse{ - Code: http.StatusBadRequest, - JSON: jsonerror.Unknown(p.Msg), - } - case PerformErrorNoRoom: - return util.JSONResponse{ - Code: http.StatusNotFound, - JSON: jsonerror.NotFound(p.Msg), - } - case PerformErrorNotAllowed: - return util.JSONResponse{ - Code: http.StatusForbidden, - JSON: jsonerror.Forbidden(p.Msg), - } - case PerformErrorNoOperation: - return util.JSONResponse{ - Code: http.StatusForbidden, - JSON: jsonerror.Forbidden(p.Msg), - } - case PerformErrRemote: - // if the code is 0 then something bad happened and it isn't - // a remote HTTP error being encapsulated, e.g network error to remote. - if p.RemoteCode == 0 { - return util.ErrorResponse(fmt.Errorf("%s", p.Msg)) - } - return util.JSONResponse{ - Code: p.RemoteCode, - // TODO: Should we assert this is in fact JSON? E.g gjson parse? - JSON: json.RawMessage(p.Msg), - } - default: - return util.ErrorResponse(p) - } -} - -const ( - // PerformErrorNotAllowed means the user is not allowed to invite/join/etc this room (e.g join_rule:invite or banned) - PerformErrorNotAllowed PerformErrorCode = 1 - // PerformErrorBadRequest means the request was wrong in some way (invalid user ID, wrong server, etc) - PerformErrorBadRequest PerformErrorCode = 2 - // PerformErrorNoRoom means that the room being joined doesn't exist. - PerformErrorNoRoom PerformErrorCode = 3 - // PerformErrorNoOperation means that the request resulted in nothing happening e.g invite->invite or leave->leave. - PerformErrorNoOperation PerformErrorCode = 4 - // PerformErrRemote means that the request failed and the PerformError.Msg is the raw remote JSON error response - PerformErrRemote PerformErrorCode = 5 ) type PerformJoinRequest struct { @@ -86,14 +17,6 @@ type PerformJoinRequest struct { Unsigned map[string]interface{} `json:"unsigned"` } -type PerformJoinResponse struct { - // The room ID, populated on success. - RoomID string `json:"room_id"` - JoinedVia spec.ServerName - // If non-nil, the join request failed. Contains more information why it failed. - Error *PerformError -} - type PerformLeaveRequest struct { RoomID string `json:"room_id"` UserID string `json:"user_id"` @@ -105,15 +28,11 @@ type PerformLeaveResponse struct { } type PerformInviteRequest struct { - RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"` - Event *gomatrixserverlib.HeaderedEvent `json:"event"` - InviteRoomState []fclient.InviteV2StrippedState `json:"invite_room_state"` - SendAsServer string `json:"send_as_server"` - TransactionID *TransactionID `json:"transaction_id"` -} - -type PerformInviteResponse struct { - Error *PerformError + RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"` + Event *types.HeaderedEvent `json:"event"` + InviteRoomState []fclient.InviteV2StrippedState `json:"invite_room_state"` + SendAsServer string `json:"send_as_server"` + TransactionID *TransactionID `json:"transaction_id"` } type PerformPeekRequest struct { @@ -123,24 +42,6 @@ type PerformPeekRequest struct { ServerNames []spec.ServerName `json:"server_names"` } -type PerformPeekResponse struct { - // The room ID, populated on success. - RoomID string `json:"room_id"` - // If non-nil, the join request failed. Contains more information why it failed. - Error *PerformError -} - -type PerformUnpeekRequest struct { - RoomID string `json:"room_id"` - UserID string `json:"user_id"` - DeviceID string `json:"device_id"` -} - -type PerformUnpeekResponse struct { - // If non-nil, the join request failed. Contains more information why it failed. - Error *PerformError -} - // PerformBackfillRequest is a request to PerformBackfill. type PerformBackfillRequest struct { // The room to backfill @@ -168,7 +69,7 @@ func (r *PerformBackfillRequest) PrevEventIDs() []string { // PerformBackfillResponse is a response to PerformBackfill. type PerformBackfillResponse struct { // Missing events, arbritrary order. - Events []*gomatrixserverlib.HeaderedEvent `json:"events"` + Events []*types.HeaderedEvent `json:"events"` HistoryVisibility gomatrixserverlib.HistoryVisibility `json:"history_visibility"` } @@ -179,11 +80,6 @@ type PerformPublishRequest struct { NetworkID string } -type PerformPublishResponse struct { - // If non-nil, the publish request failed. Contains more information why it failed. - Error *PerformError -} - type PerformInboundPeekRequest struct { UserID string `json:"user_id"` RoomID string `json:"room_id"` @@ -200,10 +96,10 @@ type PerformInboundPeekResponse struct { RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"` // The current state and auth chain events. // The lists will be in an arbitrary order. - StateEvents []*gomatrixserverlib.HeaderedEvent `json:"state_events"` - AuthChainEvents []*gomatrixserverlib.HeaderedEvent `json:"auth_chain_events"` + StateEvents []*types.HeaderedEvent `json:"state_events"` + AuthChainEvents []*types.HeaderedEvent `json:"auth_chain_events"` // The event at which this state was captured - LatestEvent *gomatrixserverlib.HeaderedEvent `json:"latest_event"` + LatestEvent *types.HeaderedEvent `json:"latest_event"` } // PerformForgetRequest is a request to PerformForget @@ -213,50 +109,3 @@ type PerformForgetRequest struct { } type PerformForgetResponse struct{} - -type PerformRoomUpgradeRequest struct { - RoomID string `json:"room_id"` - UserID string `json:"user_id"` - RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"` -} - -type PerformRoomUpgradeResponse struct { - NewRoomID string - Error *PerformError -} - -type PerformAdminEvacuateRoomRequest struct { - RoomID string `json:"room_id"` -} - -type PerformAdminEvacuateRoomResponse struct { - Affected []string `json:"affected"` - Error *PerformError -} - -type PerformAdminEvacuateUserRequest struct { - UserID string `json:"user_id"` -} - -type PerformAdminEvacuateUserResponse struct { - Affected []string `json:"affected"` - Error *PerformError -} - -type PerformAdminPurgeRoomRequest struct { - RoomID string `json:"room_id"` -} - -type PerformAdminPurgeRoomResponse struct { - Error *PerformError `json:"error,omitempty"` -} - -type PerformAdminDownloadStateRequest struct { - RoomID string `json:"room_id"` - UserID string `json:"user_id"` - ServerName spec.ServerName `json:"server_name"` -} - -type PerformAdminDownloadStateResponse struct { - Error *PerformError `json:"error,omitempty"` -} diff --git a/roomserver/api/query.go b/roomserver/api/query.go index 56915b1e4..55d1a6dba 100644 --- a/roomserver/api/query.go +++ b/roomserver/api/query.go @@ -25,6 +25,7 @@ import ( "github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/dendrite/clientapi/auth/authtypes" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/synctypes" ) @@ -53,7 +54,7 @@ type QueryLatestEventsAndStateResponse struct { // This list will be in an arbitrary order. // These are used to set the auth_events when sending an event. // These are used to check whether the event is allowed. - StateEvents []*gomatrixserverlib.HeaderedEvent `json:"state_events"` + StateEvents []*types.HeaderedEvent `json:"state_events"` // The depth of the latest events. // This is one greater than the maximum depth of the latest events. // This is used to set the depth when sending an event. @@ -83,7 +84,7 @@ type QueryStateAfterEventsResponse struct { PrevEventsExist bool `json:"prev_events_exist"` // The state events requested. // This list will be in an arbitrary order. - StateEvents []*gomatrixserverlib.HeaderedEvent `json:"state_events"` + StateEvents []*types.HeaderedEvent `json:"state_events"` } // QueryEventsByIDRequest is a request to QueryEventsByID @@ -104,7 +105,7 @@ type QueryEventsByIDResponse struct { // fails to read it from the database then it will fail // the entire request. // This list will be in an arbitrary order. - Events []*gomatrixserverlib.HeaderedEvent `json:"events"` + Events []*types.HeaderedEvent `json:"events"` } // QueryMembershipForUserRequest is a request to QueryMembership @@ -202,7 +203,7 @@ type QueryMissingEventsRequest struct { // QueryMissingEventsResponse is a response to QueryMissingEvents type QueryMissingEventsResponse struct { // Missing events, arbritrary order. - Events []*gomatrixserverlib.HeaderedEvent `json:"events"` + Events []*types.HeaderedEvent `json:"events"` } // QueryStateAndAuthChainRequest is a request to QueryStateAndAuthChain @@ -236,8 +237,8 @@ type QueryStateAndAuthChainResponse struct { StateKnown bool `json:"state_known"` // The state and auth chain events that were requested. // The lists will be in an arbitrary order. - StateEvents []*gomatrixserverlib.HeaderedEvent `json:"state_events"` - AuthChainEvents []*gomatrixserverlib.HeaderedEvent `json:"auth_chain_events"` + StateEvents []*types.HeaderedEvent `json:"state_events"` + AuthChainEvents []*types.HeaderedEvent `json:"auth_chain_events"` // True if the queried event was rejected earlier. IsRejected bool `json:"is_rejected"` } @@ -269,7 +270,7 @@ type QueryAuthChainRequest struct { } type QueryAuthChainResponse struct { - AuthChain []*gomatrixserverlib.HeaderedEvent + AuthChain []*types.HeaderedEvent } type QuerySharedUsersRequest struct { @@ -327,7 +328,7 @@ type QueryCurrentStateRequest struct { } type QueryCurrentStateResponse struct { - StateEvents map[gomatrixserverlib.StateKeyTuple]*gomatrixserverlib.HeaderedEvent + StateEvents map[gomatrixserverlib.StateKeyTuple]*types.HeaderedEvent } type QueryKnownUsersRequest struct { @@ -404,7 +405,7 @@ func (r *QueryBulkStateContentResponse) UnmarshalJSON(data []byte) error { // MarshalJSON stringifies the StateKeyTuple keys so they can be sent over the wire in HTTP API mode. func (r *QueryCurrentStateResponse) MarshalJSON() ([]byte, error) { - se := make(map[string]*gomatrixserverlib.HeaderedEvent, len(r.StateEvents)) + se := make(map[string]*types.HeaderedEvent, len(r.StateEvents)) for k, v := range r.StateEvents { // use 0x1F (unit separator) as the delimiter between type/state key, se[fmt.Sprintf("%s\x1F%s", k.EventType, k.StateKey)] = v @@ -413,12 +414,12 @@ func (r *QueryCurrentStateResponse) MarshalJSON() ([]byte, error) { } func (r *QueryCurrentStateResponse) UnmarshalJSON(data []byte) error { - res := make(map[string]*gomatrixserverlib.HeaderedEvent) + res := make(map[string]*types.HeaderedEvent) err := json.Unmarshal(data, &res) if err != nil { return err } - r.StateEvents = make(map[gomatrixserverlib.StateKeyTuple]*gomatrixserverlib.HeaderedEvent, len(res)) + r.StateEvents = make(map[gomatrixserverlib.StateKeyTuple]*types.HeaderedEvent, len(res)) for k, v := range res { fields := strings.Split(k, "\x1F") r.StateEvents[gomatrixserverlib.StateKeyTuple{ @@ -442,7 +443,7 @@ type QueryMembershipAtEventResponse struct { // Membership is a map from eventID to membership event. Events that // do not have known state will return a nil event, resulting in a "leave" membership // when calculating history visibility. - Membership map[string]*gomatrixserverlib.HeaderedEvent `json:"membership"` + Membership map[string]*types.HeaderedEvent `json:"membership"` } // QueryLeftUsersRequest is a request to calculate users that we (the server) don't share a diff --git a/roomserver/api/wrapper.go b/roomserver/api/wrapper.go index ff4445bfa..d4606622f 100644 --- a/roomserver/api/wrapper.go +++ b/roomserver/api/wrapper.go @@ -17,6 +17,7 @@ package api import ( "context" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/fclient" "github.com/matrix-org/gomatrixserverlib/spec" @@ -27,7 +28,7 @@ import ( // SendEvents to the roomserver The events are written with KindNew. func SendEvents( ctx context.Context, rsAPI InputRoomEventsAPI, - kind Kind, events []*gomatrixserverlib.HeaderedEvent, + kind Kind, events []*types.HeaderedEvent, virtualHost, origin spec.ServerName, sendAsServer spec.ServerName, txnID *TransactionID, async bool, @@ -51,10 +52,11 @@ func SendEvents( func SendEventWithState( ctx context.Context, rsAPI InputRoomEventsAPI, virtualHost spec.ServerName, kind Kind, - state gomatrixserverlib.StateResponse, event *gomatrixserverlib.HeaderedEvent, + state gomatrixserverlib.StateResponse, event *types.HeaderedEvent, origin spec.ServerName, haveEventIDs map[string]bool, async bool, ) error { - outliers := gomatrixserverlib.LineariseStateResponse(event.RoomVersion, state) + outliersPDU := gomatrixserverlib.LineariseStateResponse(event.Version(), state) + outliers := gomatrixserverlib.TempCastToEvents(outliersPDU) ires := make([]InputRoomEvent, 0, len(outliers)) for _, outlier := range outliers { if haveEventIDs[outlier.EventID()] { @@ -62,12 +64,12 @@ func SendEventWithState( } ires = append(ires, InputRoomEvent{ Kind: KindOutlier, - Event: outlier.Headered(event.RoomVersion), + Event: &types.HeaderedEvent{Event: outlier}, Origin: origin, }) } - stateEvents := state.GetStateEvents().UntrustedEvents(event.RoomVersion) + stateEvents := state.GetStateEvents().UntrustedEvents(event.Version()) stateEventIDs := make([]string, len(stateEvents)) for i := range stateEvents { stateEventIDs[i] = stateEvents[i].EventID() @@ -110,7 +112,7 @@ func SendInputRoomEvents( } // GetEvent returns the event or nil, even on errors. -func GetEvent(ctx context.Context, rsAPI QueryEventsAPI, roomID, eventID string) *gomatrixserverlib.HeaderedEvent { +func GetEvent(ctx context.Context, rsAPI QueryEventsAPI, roomID, eventID string) *types.HeaderedEvent { var res QueryEventsByIDResponse err := rsAPI.QueryEventsByID(ctx, &QueryEventsByIDRequest{ RoomID: roomID, @@ -127,7 +129,7 @@ func GetEvent(ctx context.Context, rsAPI QueryEventsAPI, roomID, eventID string) } // GetStateEvent returns the current state event in the room or nil. -func GetStateEvent(ctx context.Context, rsAPI QueryEventsAPI, roomID string, tuple gomatrixserverlib.StateKeyTuple) *gomatrixserverlib.HeaderedEvent { +func GetStateEvent(ctx context.Context, rsAPI QueryEventsAPI, roomID string, tuple gomatrixserverlib.StateKeyTuple) *types.HeaderedEvent { var res QueryCurrentStateResponse err := rsAPI.QueryCurrentState(ctx, &QueryCurrentStateRequest{ RoomID: roomID, diff --git a/roomserver/auth/auth.go b/roomserver/auth/auth.go index 5f72454ae..e872dcc3b 100644 --- a/roomserver/auth/auth.go +++ b/roomserver/auth/auth.go @@ -26,6 +26,10 @@ func IsServerAllowed( serverCurrentlyInRoom bool, authEvents []*gomatrixserverlib.Event, ) bool { + // In practice should not happen, but avoids unneeded CPU cycles + if serverName == "" || len(authEvents) == 0 { + return false + } historyVisibility := HistoryVisibilityForRoom(authEvents) // 1. If the history_visibility was set to world_readable, allow. diff --git a/roomserver/auth/auth_test.go b/roomserver/auth/auth_test.go new file mode 100644 index 000000000..7478b9248 --- /dev/null +++ b/roomserver/auth/auth_test.go @@ -0,0 +1,85 @@ +package auth + +import ( + "testing" + + "github.com/matrix-org/dendrite/test" + "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/gomatrixserverlib/spec" +) + +func TestIsServerAllowed(t *testing.T) { + alice := test.NewUser(t) + + tests := []struct { + name string + want bool + roomFunc func() *test.Room + serverName spec.ServerName + serverCurrentlyInRoom bool + }{ + { + name: "no servername specified", + roomFunc: func() *test.Room { return test.NewRoom(t, alice) }, + }, + { + name: "no authEvents specified", + serverName: "test", + roomFunc: func() *test.Room { return &test.Room{} }, + }, + { + name: "default denied", + serverName: "test2", + roomFunc: func() *test.Room { return test.NewRoom(t, alice) }, + }, + { + name: "world readable room", + serverName: "test", + roomFunc: func() *test.Room { + return test.NewRoom(t, alice, test.RoomHistoryVisibility(gomatrixserverlib.HistoryVisibilityWorldReadable)) + }, + want: true, + }, + { + name: "allowed due to alice being joined", + serverName: "test", + roomFunc: func() *test.Room { return test.NewRoom(t, alice) }, + want: true, + }, + { + name: "allowed due to 'serverCurrentlyInRoom'", + serverName: "test2", + roomFunc: func() *test.Room { return test.NewRoom(t, alice) }, + want: true, + serverCurrentlyInRoom: true, + }, + { + name: "allowed due to pending invite", + serverName: "test2", + roomFunc: func() *test.Room { + bob := test.User{ID: "@bob:test2"} + r := test.NewRoom(t, alice, test.RoomHistoryVisibility(gomatrixserverlib.HistoryVisibilityInvited)) + r.CreateAndInsert(t, alice, spec.MRoomMember, map[string]interface{}{ + "membership": spec.Invite, + }, test.WithStateKey(bob.ID)) + return r + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.roomFunc == nil { + t.Fatalf("missing roomFunc") + } + var authEvents []*gomatrixserverlib.Event + for _, ev := range tt.roomFunc().Events() { + authEvents = append(authEvents, ev.Event) + } + + if got := IsServerAllowed(tt.serverName, tt.serverCurrentlyInRoom, authEvents); got != tt.want { + t.Errorf("IsServerAllowed() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/roomserver/internal/alias.go b/roomserver/internal/alias.go index 46598746c..d3ab10f0c 100644 --- a/roomserver/internal/alias.go +++ b/roomserver/internal/alias.go @@ -25,6 +25,7 @@ import ( "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/internal/helpers" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/tidwall/gjson" @@ -140,7 +141,7 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias( } if creatorID != request.UserID { - var plEvent *gomatrixserverlib.HeaderedEvent + var plEvent *types.HeaderedEvent var pls *gomatrixserverlib.PowerLevelContent plEvent, err = r.DB.GetStateEvent(ctx, roomID, spec.MRoomPowerLevels, "") @@ -212,7 +213,7 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias( return err } - err = api.SendEvents(ctx, r, api.KindNew, []*gomatrixserverlib.HeaderedEvent{newEvent}, virtualHost, r.ServerName, r.ServerName, nil, false) + err = api.SendEvents(ctx, r, api.KindNew, []*types.HeaderedEvent{newEvent}, virtualHost, r.ServerName, r.ServerName, nil, false) if err != nil { return err } diff --git a/roomserver/internal/api.go b/roomserver/internal/api.go index 975e77966..81904c8b8 100644 --- a/roomserver/internal/api.go +++ b/roomserver/internal/api.go @@ -209,11 +209,9 @@ func (r *RoomserverInternalAPI) SetAppserviceAPI(asAPI asAPI.AppServiceInternalA func (r *RoomserverInternalAPI) PerformInvite( ctx context.Context, req *api.PerformInviteRequest, - res *api.PerformInviteResponse, ) error { - outputEvents, err := r.Inviter.PerformInvite(ctx, req, res) + outputEvents, err := r.Inviter.PerformInvite(ctx, req) if err != nil { - sentry.CaptureException(err) return err } if len(outputEvents) == 0 { diff --git a/roomserver/internal/helpers/auth.go b/roomserver/internal/helpers/auth.go index 4ef6e2480..48e2e1cf5 100644 --- a/roomserver/internal/helpers/auth.go +++ b/roomserver/internal/helpers/auth.go @@ -34,7 +34,7 @@ func CheckForSoftFail( ctx context.Context, db storage.RoomDatabase, roomInfo *types.RoomInfo, - event *gomatrixserverlib.HeaderedEvent, + event *types.HeaderedEvent, stateEventIDs []string, ) (bool, error) { rewritesState := len(stateEventIDs) > 1 @@ -65,7 +65,9 @@ func CheckForSoftFail( } // Work out which of the state events we actually need. - stateNeeded := gomatrixserverlib.StateNeededForAuth([]*gomatrixserverlib.Event{event.Unwrap()}) + stateNeeded := gomatrixserverlib.StateNeededForAuth( + gomatrixserverlib.ToPDUs([]*gomatrixserverlib.Event{event.Event}), + ) // Load the actual auth events from the database. authEvents, err := loadAuthEvents(ctx, db, roomInfo, stateNeeded, authStateEntries) @@ -87,7 +89,7 @@ func CheckAuthEvents( ctx context.Context, db storage.RoomDatabase, roomInfo *types.RoomInfo, - event *gomatrixserverlib.HeaderedEvent, + event *types.HeaderedEvent, authEventIDs []string, ) ([]types.EventNID, error) { // Grab the numeric IDs for the supplied auth state events from the database. @@ -98,7 +100,7 @@ func CheckAuthEvents( authStateEntries = types.DeduplicateStateEntries(authStateEntries) // Work out which of the state events we actually need. - stateNeeded := gomatrixserverlib.StateNeededForAuth([]*gomatrixserverlib.Event{event.Unwrap()}) + stateNeeded := gomatrixserverlib.StateNeededForAuth([]gomatrixserverlib.PDU{event.Event}) // Load the actual auth events from the database. authEvents, err := loadAuthEvents(ctx, db, roomInfo, stateNeeded, authStateEntries) @@ -132,31 +134,31 @@ func (ae *authEvents) Valid() bool { } // Create implements gomatrixserverlib.AuthEventProvider -func (ae *authEvents) Create() (*gomatrixserverlib.Event, error) { +func (ae *authEvents) Create() (gomatrixserverlib.PDU, error) { return ae.lookupEventWithEmptyStateKey(types.MRoomCreateNID), nil } // PowerLevels implements gomatrixserverlib.AuthEventProvider -func (ae *authEvents) PowerLevels() (*gomatrixserverlib.Event, error) { +func (ae *authEvents) PowerLevels() (gomatrixserverlib.PDU, error) { return ae.lookupEventWithEmptyStateKey(types.MRoomPowerLevelsNID), nil } // JoinRules implements gomatrixserverlib.AuthEventProvider -func (ae *authEvents) JoinRules() (*gomatrixserverlib.Event, error) { +func (ae *authEvents) JoinRules() (gomatrixserverlib.PDU, error) { return ae.lookupEventWithEmptyStateKey(types.MRoomJoinRulesNID), nil } // Memmber implements gomatrixserverlib.AuthEventProvider -func (ae *authEvents) Member(stateKey string) (*gomatrixserverlib.Event, error) { +func (ae *authEvents) Member(stateKey string) (gomatrixserverlib.PDU, error) { return ae.lookupEvent(types.MRoomMemberNID, stateKey), nil } // ThirdPartyInvite implements gomatrixserverlib.AuthEventProvider -func (ae *authEvents) ThirdPartyInvite(stateKey string) (*gomatrixserverlib.Event, error) { +func (ae *authEvents) ThirdPartyInvite(stateKey string) (gomatrixserverlib.PDU, error) { return ae.lookupEvent(types.MRoomThirdPartyInviteNID, stateKey), nil } -func (ae *authEvents) lookupEventWithEmptyStateKey(typeNID types.EventTypeNID) *gomatrixserverlib.Event { +func (ae *authEvents) lookupEventWithEmptyStateKey(typeNID types.EventTypeNID) gomatrixserverlib.PDU { eventNID, ok := ae.state.lookup(types.StateKeyTuple{ EventTypeNID: typeNID, EventStateKeyNID: types.EmptyStateKeyNID, @@ -171,7 +173,7 @@ func (ae *authEvents) lookupEventWithEmptyStateKey(typeNID types.EventTypeNID) * return event.Event } -func (ae *authEvents) lookupEvent(typeNID types.EventTypeNID, stateKey string) *gomatrixserverlib.Event { +func (ae *authEvents) lookupEvent(typeNID types.EventTypeNID, stateKey string) gomatrixserverlib.PDU { stateKeyNID, ok := ae.stateKeyNIDMap[stateKey] if !ok { return nil diff --git a/roomserver/internal/helpers/helpers.go b/roomserver/internal/helpers/helpers.go index b90f5fe54..802333dc1 100644 --- a/roomserver/internal/helpers/helpers.go +++ b/roomserver/internal/helpers/helpers.go @@ -45,7 +45,7 @@ func UpdateToInviteMembership( updates = append(updates, api.OutputEvent{ Type: api.OutputTypeNewInviteEvent, NewInviteEvent: &api.OutputNewInviteEvent{ - Event: add.Headered(roomVersion), + Event: &types.HeaderedEvent{Event: add.Event}, RoomVersion: roomVersion, }, }) @@ -479,7 +479,7 @@ func QueryLatestEventsAndState( } for _, event := range stateEvents { - response.StateEvents = append(response.StateEvents, event.Headered(roomInfo.RoomVersion)) + response.StateEvents = append(response.StateEvents, &types.HeaderedEvent{Event: event}) } return nil diff --git a/roomserver/internal/helpers/helpers_test.go b/roomserver/internal/helpers/helpers_test.go index dd74b844a..3fade6d91 100644 --- a/roomserver/internal/helpers/helpers_test.go +++ b/roomserver/internal/helpers/helpers_test.go @@ -41,7 +41,7 @@ func TestIsInvitePendingWithoutNID(t *testing.T) { var authNIDs []types.EventNID for _, x := range room.Events() { - roomInfo, err := db.GetOrCreateRoomInfo(context.Background(), x.Unwrap()) + roomInfo, err := db.GetOrCreateRoomInfo(context.Background(), x.Event) assert.NoError(t, err) assert.NotNil(t, roomInfo) diff --git a/roomserver/internal/input/input_events.go b/roomserver/internal/input/input_events.go index 334e68b9a..763e41702 100644 --- a/roomserver/internal/input/input_events.go +++ b/roomserver/internal/input/input_events.go @@ -102,7 +102,7 @@ func (r *Inputer) processRoomEvent( // Parse and validate the event JSON headered := input.Event - event := headered.Unwrap() + event := headered.Event logger := util.GetLogger(ctx).WithFields(logrus.Fields{ "event_id": event.EventID(), "room_id": event.RoomID(), @@ -235,7 +235,7 @@ func (r *Inputer) processRoomEvent( haveEvents: map[string]*gomatrixserverlib.Event{}, } var stateSnapshot *parsedRespState - if stateSnapshot, err = missingState.processEventWithMissingState(ctx, event, headered.RoomVersion); err != nil { + if stateSnapshot, err = missingState.processEventWithMissingState(ctx, event, headered.Version()); err != nil { // Something went wrong with retrieving the missing state, so we can't // really do anything with the event other than reject it at this point. isRejected = true @@ -467,7 +467,7 @@ func (r *Inputer) processRoomEvent( Type: api.OutputTypeRedactedEvent, RedactedEvent: &api.OutputRedactedEvent{ RedactedEventID: redactedEventID, - RedactedBecause: redactionEvent.Headered(headered.RoomVersion), + RedactedBecause: &types.HeaderedEvent{Event: redactionEvent}, }, }, }) @@ -478,7 +478,7 @@ func (r *Inputer) processRoomEvent( // If guest_access changed and is not can_join, kick all guest users. if event.Type() == spec.MRoomGuestAccess && gjson.GetBytes(event.Content(), "guest_access").Str != "can_join" { - if err = r.kickGuests(ctx, event, roomInfo); err != nil { + if err = r.kickGuests(ctx, event, roomInfo); err != nil && err != sql.ErrNoRows { logrus.WithError(err).Error("failed to kick guest users on m.room.guest_access revocation") } } @@ -509,7 +509,7 @@ func (r *Inputer) processStateBefore( missingPrev bool, ) (historyVisibility gomatrixserverlib.HistoryVisibility, rejectionErr error, err error) { historyVisibility = gomatrixserverlib.HistoryVisibilityShared // Default to shared. - event := input.Event.Unwrap() + event := input.Event.Event isCreateEvent := event.Type() == spec.MRoomCreate && event.StateKeyEquals("") var stateBeforeEvent []*gomatrixserverlib.Event switch { @@ -545,7 +545,7 @@ func (r *Inputer) processStateBefore( // will include the history visibility here even though we don't // actually need it for auth, because we want to send it in the // output events. - tuplesNeeded := gomatrixserverlib.StateNeededForAuth([]*gomatrixserverlib.Event{event}).Tuples() + tuplesNeeded := gomatrixserverlib.StateNeededForAuth([]gomatrixserverlib.PDU{event}).Tuples() tuplesNeeded = append(tuplesNeeded, gomatrixserverlib.StateKeyTuple{ EventType: spec.MRoomHistoryVisibility, StateKey: "", @@ -567,14 +567,20 @@ func (r *Inputer) processStateBefore( rejectionErr = fmt.Errorf("prev events of %q are not known", event.EventID()) return default: - stateBeforeEvent = gomatrixserverlib.UnwrapEventHeaders(stateBeforeRes.StateEvents) + stateBeforeEvent = make([]*gomatrixserverlib.Event, len(stateBeforeRes.StateEvents)) + for i := range stateBeforeRes.StateEvents { + stateBeforeEvent[i] = stateBeforeRes.StateEvents[i].Event + } } } // At this point, stateBeforeEvent should be populated either by // the supplied state in the input request, or from the prev events. // Check whether the event is allowed or not. - stateBeforeAuth := gomatrixserverlib.NewAuthEvents(stateBeforeEvent) + stateBeforeAuth := gomatrixserverlib.NewAuthEvents( + gomatrixserverlib.ToPDUs(stateBeforeEvent), + ) if rejectionErr = gomatrixserverlib.Allowed(event, &stateBeforeAuth); rejectionErr != nil { + rejectionErr = fmt.Errorf("Allowed() failed for stateBeforeEvent: %w", rejectionErr) return } // Work out what the history visibility was at the time of the @@ -604,7 +610,7 @@ func (r *Inputer) fetchAuthEvents( logger *logrus.Entry, roomInfo *types.RoomInfo, virtualHost spec.ServerName, - event *gomatrixserverlib.HeaderedEvent, + event *types.HeaderedEvent, auth *gomatrixserverlib.AuthEvents, known map[string]*types.Event, servers []spec.ServerName, @@ -654,7 +660,7 @@ func (r *Inputer) fetchAuthEvents( // Request the entire auth chain for the event in question. This should // contain all of the auth events — including ones that we already know — // so we'll need to filter through those in the next section. - res, err = r.FSAPI.GetEventAuth(ctx, virtualHost, serverName, event.RoomVersion, event.RoomID(), event.EventID()) + res, err = r.FSAPI.GetEventAuth(ctx, virtualHost, serverName, event.Version(), event.RoomID(), event.EventID()) if err != nil { logger.WithError(err).Warnf("Failed to get event auth from federation for %q: %s", event.EventID(), err) continue @@ -671,7 +677,7 @@ func (r *Inputer) fetchAuthEvents( isRejected := false nextAuthEvent: for _, authEvent := range gomatrixserverlib.ReverseTopologicalOrdering( - res.AuthEvents.UntrustedEvents(event.RoomVersion), + gomatrixserverlib.ToPDUs(res.AuthEvents.UntrustedEvents(event.Version())), gomatrixserverlib.TopologicalOrderByAuthEvents, ) { // If we already know about this event from the database then we don't @@ -684,7 +690,7 @@ nextAuthEvent: // Check the signatures of the event. If this fails then we'll simply // skip it, because gomatrixserverlib.Allowed() will notice a problem // if a critical event is missing anyway. - if err := authEvent.VerifyEventSignatures(ctx, r.FSAPI.KeyRing()); err != nil { + if err := gomatrixserverlib.VerifyEventSignatures(ctx, authEvent, r.FSAPI.KeyRing()); err != nil { continue nextAuthEvent } @@ -739,7 +745,7 @@ nextAuthEvent: // Now we know about this event, it was stored and the signatures were OK. known[authEvent.EventID()] = &types.Event{ EventNID: eventNID, - Event: authEvent, + Event: authEvent.(*gomatrixserverlib.Event), } } diff --git a/roomserver/internal/input/input_latest_events.go b/roomserver/internal/input/input_latest_events.go index 09db18431..e4783da87 100644 --- a/roomserver/internal/input/input_latest_events.go +++ b/roomserver/internal/input/input_latest_events.go @@ -393,7 +393,7 @@ func (u *latestEventsUpdater) makeOutputNewRoomEvent() (*api.OutputEvent, error) } ore := api.OutputNewRoomEvent{ - Event: u.event.Headered(u.roomInfo.RoomVersion), + Event: &types.HeaderedEvent{Event: u.event}, RewritesState: u.rewritesState, LastSentEventID: u.lastEventIDSent, LatestEventIDs: latestEventIDs, diff --git a/roomserver/internal/input/input_missing.go b/roomserver/internal/input/input_missing.go index 1aeb67c93..6847509bb 100644 --- a/roomserver/internal/input/input_missing.go +++ b/roomserver/internal/input/input_missing.go @@ -26,7 +26,7 @@ type parsedRespState struct { StateEvents []*gomatrixserverlib.Event } -func (p *parsedRespState) Events() []*gomatrixserverlib.Event { +func (p *parsedRespState) Events() []gomatrixserverlib.PDU { eventsByID := make(map[string]*gomatrixserverlib.Event, len(p.AuthEvents)+len(p.StateEvents)) for i, event := range p.AuthEvents { eventsByID[event.EventID()] = p.AuthEvents[i] @@ -38,7 +38,8 @@ func (p *parsedRespState) Events() []*gomatrixserverlib.Event { for _, event := range eventsByID { allEvents = append(allEvents, event) } - return gomatrixserverlib.ReverseTopologicalOrdering(allEvents, gomatrixserverlib.TopologicalOrderByAuthEvents) + return gomatrixserverlib.ReverseTopologicalOrdering( + gomatrixserverlib.ToPDUs(allEvents), gomatrixserverlib.TopologicalOrderByAuthEvents) } type missingStateReq struct { @@ -106,7 +107,7 @@ func (t *missingStateReq) processEventWithMissingState( for _, newEvent := range newEvents { err = t.inputer.processRoomEvent(ctx, t.virtualHost, &api.InputRoomEvent{ Kind: api.KindOld, - Event: newEvent.Headered(roomVersion), + Event: &types.HeaderedEvent{Event: newEvent}, Origin: t.origin, SendAsServer: api.DoNotSendToOtherServers, }) @@ -155,7 +156,7 @@ func (t *missingStateReq) processEventWithMissingState( } outlierRoomEvents = append(outlierRoomEvents, api.InputRoomEvent{ Kind: api.KindOutlier, - Event: outlier.Headered(roomVersion), + Event: &types.HeaderedEvent{Event: outlier.(*gomatrixserverlib.Event)}, Origin: t.origin, }) } @@ -185,7 +186,7 @@ func (t *missingStateReq) processEventWithMissingState( err = t.inputer.processRoomEvent(ctx, t.virtualHost, &api.InputRoomEvent{ Kind: api.KindOld, - Event: backwardsExtremity.Headered(roomVersion), + Event: &types.HeaderedEvent{Event: backwardsExtremity}, Origin: t.origin, HasState: true, StateEventIDs: stateIDs, @@ -204,7 +205,7 @@ func (t *missingStateReq) processEventWithMissingState( for _, newEvent := range newEvents { err = t.inputer.processRoomEvent(ctx, t.virtualHost, &api.InputRoomEvent{ Kind: api.KindOld, - Event: newEvent.Headered(roomVersion), + Event: &types.HeaderedEvent{Event: newEvent}, Origin: t.origin, SendAsServer: api.DoNotSendToOtherServers, }) @@ -468,7 +469,9 @@ func (t *missingStateReq) resolveStatesAndCheck(ctx context.Context, roomVersion authEventList = append(authEventList, state.AuthEvents...) stateEventList = append(stateEventList, state.StateEvents...) } - resolvedStateEvents, err := gomatrixserverlib.ResolveConflicts(roomVersion, stateEventList, authEventList) + resolvedStateEvents, err := gomatrixserverlib.ResolveConflicts( + roomVersion, gomatrixserverlib.ToPDUs(stateEventList), gomatrixserverlib.ToPDUs(authEventList), + ) if err != nil { return nil, err } @@ -482,7 +485,7 @@ retryAllowedState: case verifySigError: return &parsedRespState{ AuthEvents: authEventList, - StateEvents: resolvedStateEvents, + StateEvents: gomatrixserverlib.TempCastToEvents(resolvedStateEvents), }, nil case nil: // do nothing @@ -498,7 +501,7 @@ retryAllowedState: } return &parsedRespState{ AuthEvents: authEventList, - StateEvents: resolvedStateEvents, + StateEvents: gomatrixserverlib.TempCastToEvents(resolvedStateEvents), }, nil } @@ -559,7 +562,7 @@ func (t *missingStateReq) getMissingEvents(ctx context.Context, e *gomatrixserve // will be added and duplicates will be removed. missingEvents := make([]*gomatrixserverlib.Event, 0, len(missingResp.Events)) for _, ev := range missingResp.Events.UntrustedEvents(roomVersion) { - if err = ev.VerifyEventSignatures(ctx, t.keys); err != nil { + if err = gomatrixserverlib.VerifyEventSignatures(ctx, ev, t.keys); err != nil { continue } missingEvents = append(missingEvents, t.cacheAndReturn(ev)) @@ -567,7 +570,9 @@ func (t *missingStateReq) getMissingEvents(ctx context.Context, e *gomatrixserve logger.Debugf("get_missing_events returned %d events (%d passed signature checks)", len(missingResp.Events), len(missingEvents)) // topologically sort and sanity check that we are making forward progress - newEvents = gomatrixserverlib.ReverseTopologicalOrdering(missingEvents, gomatrixserverlib.TopologicalOrderByPrevEvents) + newEventsPDUs := gomatrixserverlib.ReverseTopologicalOrdering( + gomatrixserverlib.ToPDUs(missingEvents), gomatrixserverlib.TopologicalOrderByPrevEvents) + newEvents = gomatrixserverlib.TempCastToEvents(newEventsPDUs) shouldHaveSomeEventIDs := e.PrevEventIDs() hasPrevEvent := false Event: @@ -882,14 +887,14 @@ func (t *missingStateReq) lookupEvent(ctx context.Context, roomVersion gomatrixs t.log.WithField("missing_event_id", missingEventID).Warnf("Failed to get missing /event for event ID from %d server(s)", len(t.servers)) return nil, fmt.Errorf("wasn't able to find event via %d server(s)", len(t.servers)) } - if err := event.VerifyEventSignatures(ctx, t.keys); err != nil { + if err := gomatrixserverlib.VerifyEventSignatures(ctx, event, t.keys); err != nil { t.log.WithError(err).Warnf("Couldn't validate signature of event %q from /event", event.EventID()) return nil, verifySigError{event.EventID(), err} } return t.cacheAndReturn(event), nil } -func checkAllowedByState(e *gomatrixserverlib.Event, stateEvents []*gomatrixserverlib.Event) error { +func checkAllowedByState(e *gomatrixserverlib.Event, stateEvents []gomatrixserverlib.PDU) error { authUsingState := gomatrixserverlib.NewAuthEvents(nil) for i := range stateEvents { err := authUsingState.AddEvent(stateEvents[i]) diff --git a/roomserver/internal/input/input_test.go b/roomserver/internal/input/input_test.go index 493848d95..20bf26c6b 100644 --- a/roomserver/internal/input/input_test.go +++ b/roomserver/internal/input/input_test.go @@ -10,6 +10,7 @@ import ( "github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/internal/input" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test/testrig" @@ -44,7 +45,7 @@ func TestSingleTransactionOnInput(t *testing.T) { } in := api.InputRoomEvent{ Kind: api.KindOutlier, // don't panic if we generate an output event - Event: event.Headered(gomatrixserverlib.RoomVersionV6), + Event: &types.HeaderedEvent{Event: event}, } inputter := &input.Inputer{ diff --git a/roomserver/internal/perform/perform_admin.go b/roomserver/internal/perform/perform_admin.go index e7b9db1ff..050e5a62c 100644 --- a/roomserver/internal/perform/perform_admin.go +++ b/roomserver/internal/perform/perform_admin.go @@ -26,8 +26,10 @@ import ( "github.com/matrix-org/dendrite/roomserver/internal/input" "github.com/matrix-org/dendrite/roomserver/internal/query" "github.com/matrix-org/dendrite/roomserver/storage" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/gomatrixserverlib/fclient" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/sirupsen/logrus" ) @@ -40,61 +42,44 @@ type Admin struct { Leaver *Leaver } -// PerformEvacuateRoom will remove all local users from the given room. +// PerformAdminEvacuateRoom will remove all local users from the given room. func (r *Admin) PerformAdminEvacuateRoom( ctx context.Context, - req *api.PerformAdminEvacuateRoomRequest, - res *api.PerformAdminEvacuateRoomResponse, -) error { - roomInfo, err := r.DB.RoomInfo(ctx, req.RoomID) + roomID string, +) (affected []string, err error) { + roomInfo, err := r.DB.RoomInfo(ctx, roomID) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.DB.RoomInfo: %s", err), - } - return nil + return nil, err } if roomInfo == nil || roomInfo.IsStub() { - res.Error = &api.PerformError{ - Code: api.PerformErrorNoRoom, - Msg: fmt.Sprintf("Room %s not found", req.RoomID), - } - return nil + return nil, eventutil.ErrRoomNoExists } memberNIDs, err := r.DB.GetMembershipEventNIDsForRoom(ctx, roomInfo.RoomNID, true, true) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.DB.GetMembershipEventNIDsForRoom: %s", err), - } - return nil + return nil, err } memberEvents, err := r.DB.Events(ctx, roomInfo, memberNIDs) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.DB.Events: %s", err), - } - return nil + return nil, err } inputEvents := make([]api.InputRoomEvent, 0, len(memberEvents)) - res.Affected = make([]string, 0, len(memberEvents)) + affected = make([]string, 0, len(memberEvents)) latestReq := &api.QueryLatestEventsAndStateRequest{ - RoomID: req.RoomID, + RoomID: roomID, } latestRes := &api.QueryLatestEventsAndStateResponse{} if err = r.Queryer.QueryLatestEventsAndState(ctx, latestReq, latestRes); err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.Queryer.QueryLatestEventsAndState: %s", err), - } - return nil + return nil, err } prevEvents := latestRes.LatestEvents + var senderDomain spec.ServerName + var eventsNeeded gomatrixserverlib.StateNeeded + var identity *fclient.SigningIdentity + var event *types.HeaderedEvent for _, memberEvent := range memberEvents { if memberEvent.StateKey() == nil { continue @@ -102,57 +87,41 @@ func (r *Admin) PerformAdminEvacuateRoom( var memberContent gomatrixserverlib.MemberContent if err = json.Unmarshal(memberEvent.Content(), &memberContent); err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("json.Unmarshal: %s", err), - } - return nil + return nil, err } memberContent.Membership = spec.Leave stateKey := *memberEvent.StateKey() fledglingEvent := &gomatrixserverlib.EventBuilder{ - RoomID: req.RoomID, + RoomID: roomID, Type: spec.MRoomMember, StateKey: &stateKey, Sender: stateKey, PrevEvents: prevEvents, } - _, senderDomain, err := gomatrixserverlib.SplitID('@', fledglingEvent.Sender) + _, senderDomain, err = gomatrixserverlib.SplitID('@', fledglingEvent.Sender) if err != nil { continue } if fledglingEvent.Content, err = json.Marshal(memberContent); err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("json.Marshal: %s", err), - } - return nil + return nil, err } - eventsNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(fledglingEvent) + eventsNeeded, err = gomatrixserverlib.StateNeededForEventBuilder(fledglingEvent) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("gomatrixserverlib.StateNeededForEventBuilder: %s", err), - } - return nil + return nil, err } - identity, err := r.Cfg.Matrix.SigningIdentityFor(senderDomain) + identity, err = r.Cfg.Matrix.SigningIdentityFor(senderDomain) if err != nil { continue } - event, err := eventutil.BuildEvent(ctx, fledglingEvent, r.Cfg.Matrix, identity, time.Now(), &eventsNeeded, latestRes) + event, err = eventutil.BuildEvent(ctx, fledglingEvent, r.Cfg.Matrix, identity, time.Now(), &eventsNeeded, latestRes) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("eventutil.BuildEvent: %s", err), - } - return nil + return nil, err } inputEvents = append(inputEvents, api.InputRoomEvent{ @@ -161,7 +130,7 @@ func (r *Admin) PerformAdminEvacuateRoom( Origin: senderDomain, SendAsServer: string(senderDomain), }) - res.Affected = append(res.Affected, stateKey) + affected = append(affected, stateKey) prevEvents = []gomatrixserverlib.EventReference{ event.EventReference(), } @@ -172,108 +141,85 @@ func (r *Admin) PerformAdminEvacuateRoom( Asynchronous: true, } inputRes := &api.InputRoomEventsResponse{} - return r.Inputer.InputRoomEvents(ctx, inputReq, inputRes) + err = r.Inputer.InputRoomEvents(ctx, inputReq, inputRes) + return affected, err } +// PerformAdminEvacuateUser will remove the given user from all rooms. func (r *Admin) PerformAdminEvacuateUser( ctx context.Context, - req *api.PerformAdminEvacuateUserRequest, - res *api.PerformAdminEvacuateUserResponse, -) error { - _, domain, err := gomatrixserverlib.SplitID('@', req.UserID) + userID string, +) (affected []string, err error) { + _, domain, err := gomatrixserverlib.SplitID('@', userID) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("Malformed user ID: %s", err), - } - return nil + return nil, err } if !r.Cfg.Matrix.IsLocalServerName(domain) { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: "Can only evacuate local users using this endpoint", - } - return nil + return nil, fmt.Errorf("can only evacuate local users using this endpoint") } - roomIDs, err := r.DB.GetRoomsByMembership(ctx, req.UserID, spec.Join) + roomIDs, err := r.DB.GetRoomsByMembership(ctx, userID, spec.Join) + if err != nil { + return nil, err + } + + inviteRoomIDs, err := r.DB.GetRoomsByMembership(ctx, userID, spec.Invite) if err != nil && err != sql.ErrNoRows { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.DB.GetRoomsByMembership: %s", err), - } - return nil + return nil, err } - inviteRoomIDs, err := r.DB.GetRoomsByMembership(ctx, req.UserID, spec.Invite) - if err != nil && err != sql.ErrNoRows { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.DB.GetRoomsByMembership: %s", err), - } - return nil - } - - for _, roomID := range append(roomIDs, inviteRoomIDs...) { + allRooms := append(roomIDs, inviteRoomIDs...) + affected = make([]string, 0, len(allRooms)) + for _, roomID := range allRooms { leaveReq := &api.PerformLeaveRequest{ RoomID: roomID, - UserID: req.UserID, + UserID: userID, } leaveRes := &api.PerformLeaveResponse{} outputEvents, err := r.Leaver.PerformLeave(ctx, leaveReq, leaveRes) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.Leaver.PerformLeave: %s", err), - } - return nil + return nil, err } - res.Affected = append(res.Affected, roomID) + affected = append(affected, roomID) if len(outputEvents) == 0 { continue } if err := r.Inputer.OutputProducer.ProduceRoomEvents(roomID, outputEvents); err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.Inputer.WriteOutputEvents: %s", err), - } - return nil + return nil, err } } - return nil + return affected, nil } +// PerformAdminPurgeRoom removes all traces for the given room from the database. func (r *Admin) PerformAdminPurgeRoom( ctx context.Context, - req *api.PerformAdminPurgeRoomRequest, - res *api.PerformAdminPurgeRoomResponse, + roomID string, ) error { // Validate we actually got a room ID and nothing else - if _, _, err := gomatrixserverlib.SplitID('!', req.RoomID); err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("Malformed room ID: %s", err), - } - return nil + if _, _, err := gomatrixserverlib.SplitID('!', roomID); err != nil { + return err } - logrus.WithField("room_id", req.RoomID).Warn("Purging room from roomserver") - if err := r.DB.PurgeRoom(ctx, req.RoomID); err != nil { - logrus.WithField("room_id", req.RoomID).WithError(err).Warn("Failed to purge room from roomserver") - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: err.Error(), - } - return nil + // Evacuate the room before purging it from the database + if _, err := r.PerformAdminEvacuateRoom(ctx, roomID); err != nil { + logrus.WithField("room_id", roomID).WithError(err).Warn("Failed to evacuate room before purging") + return err } - logrus.WithField("room_id", req.RoomID).Warn("Room purged from roomserver") + logrus.WithField("room_id", roomID).Warn("Purging room from roomserver") + if err := r.DB.PurgeRoom(ctx, roomID); err != nil { + logrus.WithField("room_id", roomID).WithError(err).Warn("Failed to purge room from roomserver") + return err + } - return r.Inputer.OutputProducer.ProduceRoomEvents(req.RoomID, []api.OutputEvent{ + logrus.WithField("room_id", roomID).Warn("Room purged from roomserver") + + return r.Inputer.OutputProducer.ProduceRoomEvents(roomID, []api.OutputEvent{ { Type: api.OutputTypePurgeRoom, PurgeRoom: &api.OutputPurgeRoom{ - RoomID: req.RoomID, + RoomID: roomID, }, }, }) @@ -281,42 +227,25 @@ func (r *Admin) PerformAdminPurgeRoom( func (r *Admin) PerformAdminDownloadState( ctx context.Context, - req *api.PerformAdminDownloadStateRequest, - res *api.PerformAdminDownloadStateResponse, + roomID, userID string, serverName spec.ServerName, ) error { - _, senderDomain, err := r.Cfg.Matrix.SplitLocalID('@', req.UserID) + _, senderDomain, err := r.Cfg.Matrix.SplitLocalID('@', userID) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.Cfg.Matrix.SplitLocalID: %s", err), - } - return nil + return err } - roomInfo, err := r.DB.RoomInfo(ctx, req.RoomID) + roomInfo, err := r.DB.RoomInfo(ctx, roomID) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.DB.RoomInfo: %s", err), - } - return nil + return err } if roomInfo == nil || roomInfo.IsStub() { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("room %q not found", req.RoomID), - } - return nil + return eventutil.ErrRoomNoExists } fwdExtremities, _, depth, err := r.DB.LatestEventIDs(ctx, roomInfo.RoomNID) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.DB.LatestEventIDs: %s", err), - } - return nil + return err } authEventMap := map[string]*gomatrixserverlib.Event{} @@ -324,54 +253,46 @@ func (r *Admin) PerformAdminDownloadState( for _, fwdExtremity := range fwdExtremities { var state gomatrixserverlib.StateResponse - state, err = r.Inputer.FSAPI.LookupState(ctx, r.Inputer.ServerName, req.ServerName, req.RoomID, fwdExtremity.EventID, roomInfo.RoomVersion) + state, err = r.Inputer.FSAPI.LookupState(ctx, r.Inputer.ServerName, serverName, roomID, fwdExtremity.EventID, roomInfo.RoomVersion) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.Inputer.FSAPI.LookupState (%q): %s", fwdExtremity.EventID, err), - } - return nil + return fmt.Errorf("r.Inputer.FSAPI.LookupState (%q): %s", fwdExtremity.EventID, err) } for _, authEvent := range state.GetAuthEvents().UntrustedEvents(roomInfo.RoomVersion) { - if err = authEvent.VerifyEventSignatures(ctx, r.Inputer.KeyRing); err != nil { + if err = gomatrixserverlib.VerifyEventSignatures(ctx, authEvent, r.Inputer.KeyRing); err != nil { continue } authEventMap[authEvent.EventID()] = authEvent } for _, stateEvent := range state.GetStateEvents().UntrustedEvents(roomInfo.RoomVersion) { - if err = stateEvent.VerifyEventSignatures(ctx, r.Inputer.KeyRing); err != nil { + if err = gomatrixserverlib.VerifyEventSignatures(ctx, stateEvent, r.Inputer.KeyRing); err != nil { continue } stateEventMap[stateEvent.EventID()] = stateEvent } } - authEvents := make([]*gomatrixserverlib.HeaderedEvent, 0, len(authEventMap)) - stateEvents := make([]*gomatrixserverlib.HeaderedEvent, 0, len(stateEventMap)) + authEvents := make([]*types.HeaderedEvent, 0, len(authEventMap)) + stateEvents := make([]*types.HeaderedEvent, 0, len(stateEventMap)) stateIDs := make([]string, 0, len(stateEventMap)) for _, authEvent := range authEventMap { - authEvents = append(authEvents, authEvent.Headered(roomInfo.RoomVersion)) + authEvents = append(authEvents, &types.HeaderedEvent{Event: authEvent}) } for _, stateEvent := range stateEventMap { - stateEvents = append(stateEvents, stateEvent.Headered(roomInfo.RoomVersion)) + stateEvents = append(stateEvents, &types.HeaderedEvent{Event: stateEvent}) stateIDs = append(stateIDs, stateEvent.EventID()) } builder := &gomatrixserverlib.EventBuilder{ Type: "org.matrix.dendrite.state_download", - Sender: req.UserID, - RoomID: req.RoomID, + Sender: userID, + RoomID: roomID, Content: spec.RawJSON("{}"), } eventsNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(builder) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("gomatrixserverlib.StateNeededForEventBuilder: %s", err), - } - return nil + return fmt.Errorf("gomatrixserverlib.StateNeededForEventBuilder: %w", err) } queryRes := &api.QueryLatestEventsAndStateResponse{ @@ -389,11 +310,7 @@ func (r *Admin) PerformAdminDownloadState( ev, err := eventutil.BuildEvent(ctx, builder, r.Cfg.Matrix, identity, time.Now(), &eventsNeeded, queryRes) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("eventutil.BuildEvent: %s", err), - } - return nil + return fmt.Errorf("eventutil.BuildEvent: %w", err) } inputReq := &api.InputRoomEventsRequest{ @@ -417,19 +334,12 @@ func (r *Admin) PerformAdminDownloadState( SendAsServer: string(r.Cfg.Matrix.ServerName), }) - if err := r.Inputer.InputRoomEvents(ctx, inputReq, inputRes); err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("r.Inputer.InputRoomEvents: %s", err), - } - return nil + if err = r.Inputer.InputRoomEvents(ctx, inputReq, inputRes); err != nil { + return fmt.Errorf("r.Inputer.InputRoomEvents: %w", err) } if inputRes.ErrMsg != "" { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: inputRes.ErrMsg, - } + return inputRes.Err() } return nil diff --git a/roomserver/internal/perform/perform_backfill.go b/roomserver/internal/perform/perform_backfill.go index d9a2394a8..daaf58782 100644 --- a/roomserver/internal/perform/perform_backfill.go +++ b/roomserver/internal/perform/perform_backfill.go @@ -99,7 +99,7 @@ func (r *Backfiller) PerformBackfill( if _, ok := redactEventIDs[event.EventID()]; ok { event.Redact() } - response.Events = append(response.Events, event.Headered(info.RoomVersion)) + response.Events = append(response.Events, &types.HeaderedEvent{Event: event}) } return err @@ -133,7 +133,7 @@ func (r *Backfiller) backfillViaFederation(ctx context.Context, req *api.Perform logrus.WithError(err).WithField("room_id", req.RoomID).Infof("backfilled %d events", len(events)) // persist these new events - auth checks have already been done - roomNID, backfilledEventMap := persistEvents(ctx, r.DB, events) + roomNID, backfilledEventMap := persistEvents(ctx, r.DB, gomatrixserverlib.TempCastToEvents(events)) for _, ev := range backfilledEventMap { // now add state for these events @@ -168,7 +168,10 @@ func (r *Backfiller) backfillViaFederation(ctx context.Context, req *api.Perform // TODO: update backwards extremities, as that should be moved from syncapi to roomserver at some point. - res.Events = events + res.Events = make([]*types.HeaderedEvent, len(events)) + for i := range events { + res.Events[i] = &types.HeaderedEvent{Event: events[i].(*gomatrixserverlib.Event)} + } res.HistoryVisibility = requester.historyVisiblity return nil } @@ -186,7 +189,7 @@ func (r *Backfiller) fetchAndStoreMissingEvents(ctx context.Context, roomVer gom util.GetLogger(ctx).WithError(err).Warn("cannot query missing events") return } - missingMap := make(map[string]*gomatrixserverlib.HeaderedEvent) // id -> event + missingMap := make(map[string]*types.HeaderedEvent) // id -> event for _, id := range stateIDs { if _, ok := nidMap[id]; !ok { missingMap[id] = nil @@ -227,15 +230,15 @@ func (r *Backfiller) fetchAndStoreMissingEvents(ctx context.Context, roomVer gom logger.WithError(err).Warn("event failed PDU checks") continue } - missingMap[id] = res.Event + missingMap[id] = &types.HeaderedEvent{Event: res.Event.(*gomatrixserverlib.Event)} } } } - var newEvents []*gomatrixserverlib.HeaderedEvent + var newEvents []*gomatrixserverlib.Event for _, ev := range missingMap { if ev != nil { - newEvents = append(newEvents, ev) + newEvents = append(newEvents, ev.Event) } } util.GetLogger(ctx).Infof("Persisting %d new events", len(newEvents)) @@ -254,7 +257,7 @@ type backfillRequester struct { // per-request state servers []spec.ServerName eventIDToBeforeStateIDs map[string][]string - eventIDMap map[string]*gomatrixserverlib.Event + eventIDMap map[string]gomatrixserverlib.PDU historyVisiblity gomatrixserverlib.HistoryVisibility roomInfo types.RoomInfo } @@ -275,15 +278,15 @@ func newBackfillRequester( virtualHost: virtualHost, isLocalServerName: isLocalServerName, eventIDToBeforeStateIDs: make(map[string][]string), - eventIDMap: make(map[string]*gomatrixserverlib.Event), + eventIDMap: make(map[string]gomatrixserverlib.PDU), bwExtrems: bwExtrems, preferServer: preferServer, historyVisiblity: gomatrixserverlib.HistoryVisibilityShared, } } -func (b *backfillRequester) StateIDsBeforeEvent(ctx context.Context, targetEvent *gomatrixserverlib.HeaderedEvent) ([]string, error) { - b.eventIDMap[targetEvent.EventID()] = targetEvent.Unwrap() +func (b *backfillRequester) StateIDsBeforeEvent(ctx context.Context, targetEvent gomatrixserverlib.PDU) ([]string, error) { + b.eventIDMap[targetEvent.EventID()] = targetEvent if ids, ok := b.eventIDToBeforeStateIDs[targetEvent.EventID()]; ok { return ids, nil } @@ -305,7 +308,7 @@ func (b *backfillRequester) StateIDsBeforeEvent(ctx context.Context, targetEvent if !ok { goto FederationHit } - newStateIDs := b.calculateNewStateIDs(targetEvent.Unwrap(), prevEvent, prevEventStateIDs) + newStateIDs := b.calculateNewStateIDs(targetEvent, prevEvent, prevEventStateIDs) if newStateIDs != nil { b.eventIDToBeforeStateIDs[targetEvent.EventID()] = newStateIDs return newStateIDs, nil @@ -334,7 +337,7 @@ FederationHit: return nil, lastErr } -func (b *backfillRequester) calculateNewStateIDs(targetEvent, prevEvent *gomatrixserverlib.Event, prevEventStateIDs []string) []string { +func (b *backfillRequester) calculateNewStateIDs(targetEvent, prevEvent gomatrixserverlib.PDU, prevEventStateIDs []string) []string { newStateIDs := prevEventStateIDs[:] if prevEvent.StateKey() == nil { // state is the same as the previous event @@ -372,7 +375,7 @@ func (b *backfillRequester) calculateNewStateIDs(targetEvent, prevEvent *gomatri } func (b *backfillRequester) StateBeforeEvent(ctx context.Context, roomVer gomatrixserverlib.RoomVersion, - event *gomatrixserverlib.HeaderedEvent, eventIDs []string) (map[string]*gomatrixserverlib.Event, error) { + event gomatrixserverlib.PDU, eventIDs []string) (map[string]gomatrixserverlib.PDU, error) { // try to fetch the events from the database first events, err := b.ProvideEvents(roomVer, eventIDs) @@ -382,7 +385,7 @@ func (b *backfillRequester) StateBeforeEvent(ctx context.Context, roomVer gomatr } else { logrus.Infof("Fetched %d/%d events from the database", len(events), len(eventIDs)) if len(events) == len(eventIDs) { - result := make(map[string]*gomatrixserverlib.Event) + result := make(map[string]gomatrixserverlib.PDU) for i := range events { result[events[i].EventID()] = events[i] b.eventIDMap[events[i].EventID()] = events[i] @@ -513,7 +516,7 @@ func (b *backfillRequester) Backfill(ctx context.Context, origin, server spec.Se return tx, err } -func (b *backfillRequester) ProvideEvents(roomVer gomatrixserverlib.RoomVersion, eventIDs []string) ([]*gomatrixserverlib.Event, error) { +func (b *backfillRequester) ProvideEvents(roomVer gomatrixserverlib.RoomVersion, eventIDs []string) ([]gomatrixserverlib.PDU, error) { ctx := context.Background() nidMap, err := b.db.EventNIDs(ctx, eventIDs) if err != nil { @@ -535,7 +538,7 @@ func (b *backfillRequester) ProvideEvents(roomVer gomatrixserverlib.RoomVersion, logrus.WithError(err).WithField("event_nids", eventNIDs).Error("Failed to load events") return nil, err } - events := make([]*gomatrixserverlib.Event, len(eventsWithNids)) + events := make([]gomatrixserverlib.PDU, len(eventsWithNids)) for i := range eventsWithNids { events[i] = eventsWithNids[i].Event } @@ -587,7 +590,7 @@ func joinEventsFromHistoryVisibility( return evs, visibility, err } -func persistEvents(ctx context.Context, db storage.Database, events []*gomatrixserverlib.HeaderedEvent) (types.RoomNID, map[string]types.Event) { +func persistEvents(ctx context.Context, db storage.Database, events []*gomatrixserverlib.Event) (types.RoomNID, map[string]types.Event) { var roomNID types.RoomNID var eventNID types.EventNID backfilledEventMap := make(map[string]types.Event) @@ -604,7 +607,7 @@ func persistEvents(ctx context.Context, db storage.Database, events []*gomatrixs i++ } - roomInfo, err := db.GetOrCreateRoomInfo(ctx, ev.Unwrap()) + roomInfo, err := db.GetOrCreateRoomInfo(ctx, ev) if err != nil { logrus.WithError(err).Error("failed to get or create roomNID") continue @@ -623,7 +626,7 @@ func persistEvents(ctx context.Context, db storage.Database, events []*gomatrixs continue } - eventNID, _, err = db.StoreEvent(ctx, ev.Unwrap(), roomInfo, eventTypeNID, eventStateKeyNID, authNids, false) + eventNID, _, err = db.StoreEvent(ctx, ev, roomInfo, eventTypeNID, eventStateKeyNID, authNids, false) if err != nil { logrus.WithError(err).WithField("event_id", ev.EventID()).Error("Failed to persist event") continue @@ -631,7 +634,7 @@ func persistEvents(ctx context.Context, db storage.Database, events []*gomatrixs resolver := state.NewStateResolution(db, roomInfo) - _, redactedEvent, err := db.MaybeRedactEvent(ctx, roomInfo, eventNID, ev.Unwrap(), &resolver) + _, redactedEvent, err := db.MaybeRedactEvent(ctx, roomInfo, eventNID, ev, &resolver) if err != nil { logrus.WithError(err).WithField("event_id", ev.EventID()).Error("Failed to redact event") continue @@ -640,12 +643,12 @@ func persistEvents(ctx context.Context, db storage.Database, events []*gomatrixs // It's also possible for this event to be a redaction which results in another event being // redacted, which we don't care about since we aren't returning it in this backfill. if redactedEvent != nil && redactedEvent.EventID() == ev.EventID() { - ev = redactedEvent.Headered(ev.RoomVersion) + ev = redactedEvent events[j] = ev } backfilledEventMap[ev.EventID()] = types.Event{ EventNID: eventNID, - Event: ev.Unwrap(), + Event: ev, } } return roomNID, backfilledEventMap diff --git a/roomserver/internal/perform/perform_inbound_peek.go b/roomserver/internal/perform/perform_inbound_peek.go index 1fb6eb43a..68b827462 100644 --- a/roomserver/internal/perform/perform_inbound_peek.go +++ b/roomserver/internal/perform/perform_inbound_peek.go @@ -68,7 +68,7 @@ func (r *InboundPeeker) PerformInboundPeek( if err != nil { return err } - var sortedLatestEvents []*gomatrixserverlib.Event + var sortedLatestEvents []gomatrixserverlib.PDU for _, ev := range latestEvents { sortedLatestEvents = append(sortedLatestEvents, ev.Event) } @@ -76,7 +76,7 @@ func (r *InboundPeeker) PerformInboundPeek( sortedLatestEvents, gomatrixserverlib.TopologicalOrderByPrevEvents, ) - response.LatestEvent = sortedLatestEvents[0].Headered(info.RoomVersion) + response.LatestEvent = &types.HeaderedEvent{Event: sortedLatestEvents[0].(*gomatrixserverlib.Event)} // XXX: do we actually need to do a state resolution here? roomState := state.NewStateResolution(r.DB, info) @@ -106,11 +106,11 @@ func (r *InboundPeeker) PerformInboundPeek( } for _, event := range stateEvents { - response.StateEvents = append(response.StateEvents, event.Headered(info.RoomVersion)) + response.StateEvents = append(response.StateEvents, &types.HeaderedEvent{Event: event}) } for _, event := range authEvents { - response.AuthChainEvents = append(response.AuthChainEvents, event.Headered(info.RoomVersion)) + response.AuthChainEvents = append(response.AuthChainEvents, &types.HeaderedEvent{Event: event}) } err = r.Inputer.OutputProducer.ProduceRoomEvents(request.RoomID, []api.OutputEvent{ diff --git a/roomserver/internal/perform/perform_invite.go b/roomserver/internal/perform/perform_invite.go index a23cdea10..dd7982892 100644 --- a/roomserver/internal/perform/perform_invite.go +++ b/roomserver/internal/perform/perform_invite.go @@ -45,7 +45,6 @@ type Inviter struct { func (r *Inviter) PerformInvite( ctx context.Context, req *api.PerformInviteRequest, - res *api.PerformInviteResponse, ) ([]api.OutputEvent, error) { var outputUpdates []api.OutputEvent event := req.Event @@ -66,20 +65,12 @@ func (r *Inviter) PerformInvite( _, domain, err := gomatrixserverlib.SplitID('@', targetUserID) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("The user ID %q is invalid!", targetUserID), - } - return nil, nil + return nil, api.ErrInvalidID{Err: fmt.Errorf("the user ID %s is invalid", targetUserID)} } isTargetLocal := r.Cfg.Matrix.IsLocalServerName(domain) isOriginLocal := r.Cfg.Matrix.IsLocalServerName(senderDomain) if !isOriginLocal && !isTargetLocal { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: "The invite must be either from or to a local user", - } - return nil, nil + return nil, api.ErrInvalidID{Err: fmt.Errorf("the invite must be either from or to a local user")} } logger := util.GetLogger(ctx).WithFields(map[string]interface{}{ @@ -119,8 +110,8 @@ func (r *Inviter) PerformInvite( } outputUpdates, err = helpers.UpdateToInviteMembership(updater, &types.Event{ EventNID: 0, - Event: event.Unwrap(), - }, outputUpdates, req.Event.RoomVersion) + Event: event.Event, + }, outputUpdates, req.Event.Version()) if err != nil { return nil, fmt.Errorf("updateToInviteMembership: %w", err) } @@ -175,12 +166,8 @@ func (r *Inviter) PerformInvite( // For now we will implement option 2. Since in the abesence of a retry // mechanism it will be equivalent to option 1, and we don't have a // signalling mechanism to implement option 3. - res.Error = &api.PerformError{ - Code: api.PerformErrorNotAllowed, - Msg: "User is already joined to room", - } logger.Debugf("user already joined") - return nil, nil + return nil, api.ErrNotAllowed{Err: fmt.Errorf("user is already joined to room")} } // If the invite originated remotely then we can't send an @@ -201,11 +188,7 @@ func (r *Inviter) PerformInvite( logger.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error( "processInviteEvent.checkAuthEvents failed for event", ) - res.Error = &api.PerformError{ - Msg: err.Error(), - Code: api.PerformErrorNotAllowed, - } - return nil, nil + return nil, api.ErrNotAllowed{Err: err} } // If the invite originated from us and the target isn't local then we @@ -220,12 +203,8 @@ func (r *Inviter) PerformInvite( } fsRes := &federationAPI.PerformInviteResponse{} if err = r.FSAPI.PerformInvite(ctx, fsReq, fsRes); err != nil { - res.Error = &api.PerformError{ - Msg: err.Error(), - Code: api.PerformErrorNotAllowed, - } logger.WithError(err).WithField("event_id", event.EventID()).Error("r.FSAPI.PerformInvite failed") - return nil, nil + return nil, api.ErrNotAllowed{Err: err} } event = fsRes.Event logger.Debugf("Federated PerformInvite success with event ID %s", event.EventID()) @@ -251,11 +230,8 @@ func (r *Inviter) PerformInvite( return nil, fmt.Errorf("r.Inputer.InputRoomEvents: %w", err) } if err = inputRes.Err(); err != nil { - res.Error = &api.PerformError{ - Msg: fmt.Sprintf("r.InputRoomEvents: %s", err.Error()), - Code: api.PerformErrorNotAllowed, - } logger.WithError(err).WithField("event_id", event.EventID()).Error("r.InputRoomEvents failed") + return nil, api.ErrNotAllowed{Err: err} } // Don't notify the sync api of this event in the same way as a federated invite so the invitee @@ -300,7 +276,7 @@ func buildInviteStrippedState( inviteState := []fclient.InviteV2StrippedState{ fclient.NewInviteV2StrippedState(input.Event.Event), } - stateEvents = append(stateEvents, types.Event{Event: input.Event.Unwrap()}) + stateEvents = append(stateEvents, types.Event{Event: input.Event.Event}) for _, event := range stateEvents { inviteState = append(inviteState, fclient.NewInviteV2StrippedState(event.Event)) } diff --git a/roomserver/internal/perform/perform_join.go b/roomserver/internal/perform/perform_join.go index 9b0895e9f..06cc0d673 100644 --- a/roomserver/internal/perform/perform_join.go +++ b/roomserver/internal/perform/perform_join.go @@ -36,6 +36,7 @@ import ( "github.com/matrix-org/dendrite/roomserver/internal/input" "github.com/matrix-org/dendrite/roomserver/internal/query" "github.com/matrix-org/dendrite/roomserver/storage" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" ) @@ -53,32 +54,22 @@ type Joiner struct { func (r *Joiner) PerformJoin( ctx context.Context, req *rsAPI.PerformJoinRequest, - res *rsAPI.PerformJoinResponse, -) error { +) (roomID string, joinedVia spec.ServerName, err error) { logger := logrus.WithContext(ctx).WithFields(logrus.Fields{ "room_id": req.RoomIDOrAlias, "user_id": req.UserID, "servers": req.ServerNames, }) logger.Info("User requested to room join") - roomID, joinedVia, err := r.performJoin(context.Background(), req) + roomID, joinedVia, err = r.performJoin(context.Background(), req) if err != nil { logger.WithError(err).Error("Failed to join room") sentry.CaptureException(err) - perr, ok := err.(*rsAPI.PerformError) - if ok { - res.Error = perr - } else { - res.Error = &rsAPI.PerformError{ - Msg: err.Error(), - } - } - return nil + return "", "", err } logger.Info("User joined room successfully") - res.RoomID = roomID - res.JoinedVia = joinedVia - return nil + + return roomID, joinedVia, nil } func (r *Joiner) performJoin( @@ -87,16 +78,10 @@ func (r *Joiner) performJoin( ) (string, spec.ServerName, error) { _, domain, err := gomatrixserverlib.SplitID('@', req.UserID) if err != nil { - return "", "", &rsAPI.PerformError{ - Code: rsAPI.PerformErrorBadRequest, - Msg: fmt.Sprintf("Supplied user ID %q in incorrect format", req.UserID), - } + return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("supplied user ID %q in incorrect format", req.UserID)} } if !r.Cfg.Matrix.IsLocalServerName(domain) { - return "", "", &rsAPI.PerformError{ - Code: rsAPI.PerformErrorBadRequest, - Msg: fmt.Sprintf("User %q does not belong to this homeserver", req.UserID), - } + return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("user %q does not belong to this homeserver", req.UserID)} } if strings.HasPrefix(req.RoomIDOrAlias, "!") { return r.performJoinRoomByID(ctx, req) @@ -104,10 +89,7 @@ func (r *Joiner) performJoin( if strings.HasPrefix(req.RoomIDOrAlias, "#") { return r.performJoinRoomByAlias(ctx, req) } - return "", "", &rsAPI.PerformError{ - Code: rsAPI.PerformErrorBadRequest, - Msg: fmt.Sprintf("Room ID or alias %q is invalid", req.RoomIDOrAlias), - } + return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("room ID or alias %q is invalid", req.RoomIDOrAlias)} } func (r *Joiner) performJoinRoomByAlias( @@ -182,10 +164,7 @@ func (r *Joiner) performJoinRoomByID( // Get the domain part of the room ID. _, domain, err := gomatrixserverlib.SplitID('!', req.RoomIDOrAlias) if err != nil { - return "", "", &rsAPI.PerformError{ - Code: rsAPI.PerformErrorBadRequest, - Msg: fmt.Sprintf("Room ID %q is invalid: %s", req.RoomIDOrAlias, err), - } + return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("room ID %q is invalid: %w", req.RoomIDOrAlias, err)} } // If the server name in the room ID isn't ours then it's a @@ -199,10 +178,7 @@ func (r *Joiner) performJoinRoomByID( userID := req.UserID _, userDomain, err := r.Cfg.Matrix.SplitLocalID('@', userID) if err != nil { - return "", "", &rsAPI.PerformError{ - Code: rsAPI.PerformErrorBadRequest, - Msg: fmt.Sprintf("User ID %q is invalid: %s", userID, err), - } + return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("user ID %q is invalid: %w", userID, err)} } eb := gomatrixserverlib.EventBuilder{ Type: spec.MRoomMember, @@ -273,7 +249,7 @@ func (r *Joiner) performJoinRoomByID( // If a guest is trying to join a room, check that the room has a m.room.guest_access event if req.IsGuest { - var guestAccessEvent *gomatrixserverlib.HeaderedEvent + var guestAccessEvent *types.HeaderedEvent guestAccess := "forbidden" guestAccessEvent, err = r.DB.GetStateEvent(ctx, req.RoomIDOrAlias, spec.MRoomGuestAccess, "") if (err != nil && !errors.Is(err, sql.ErrNoRows)) || guestAccessEvent == nil { @@ -286,10 +262,7 @@ func (r *Joiner) performJoinRoomByID( // Servers MUST only allow guest users to join rooms if the m.room.guest_access state event // is present on the room and has the guest_access value can_join. if guestAccess != "can_join" { - return "", "", &rsAPI.PerformError{ - Code: rsAPI.PerformErrorNotAllowed, - Msg: "Guest access is forbidden", - } + return "", "", rsAPI.ErrNotAllowed{Err: fmt.Errorf("guest access is forbidden")} } } @@ -334,23 +307,17 @@ func (r *Joiner) performJoinRoomByID( InputRoomEvents: []rsAPI.InputRoomEvent{ { Kind: rsAPI.KindNew, - Event: event.Headered(buildRes.RoomVersion), + Event: event, SendAsServer: string(userDomain), }, }, } inputRes := rsAPI.InputRoomEventsResponse{} if err = r.Inputer.InputRoomEvents(ctx, &inputReq, &inputRes); err != nil { - return "", "", &rsAPI.PerformError{ - Code: rsAPI.PerformErrorNoOperation, - Msg: fmt.Sprintf("InputRoomEvents failed: %s", err), - } + return "", "", rsAPI.ErrNotAllowed{Err: err} } if err = inputRes.Err(); err != nil { - return "", "", &rsAPI.PerformError{ - Code: rsAPI.PerformErrorNotAllowed, - Msg: fmt.Sprintf("InputRoomEvents auth failed: %s", err), - } + return "", "", rsAPI.ErrNotAllowed{Err: err} } } @@ -363,10 +330,7 @@ func (r *Joiner) performJoinRoomByID( // Otherwise we'll try a federated join as normal, since it's quite // possible that the room still exists on other servers. if len(req.ServerNames) == 0 { - return "", "", &rsAPI.PerformError{ - Code: rsAPI.PerformErrorNoRoom, - Msg: fmt.Sprintf("room ID %q does not exist", req.RoomIDOrAlias), - } + return "", "", eventutil.ErrRoomNoExists } } @@ -401,11 +365,7 @@ func (r *Joiner) performFederatedJoinRoomByID( fedRes := fsAPI.PerformJoinResponse{} r.FSAPI.PerformJoin(ctx, &fedReq, &fedRes) if fedRes.LastError != nil { - return "", &rsAPI.PerformError{ - Code: rsAPI.PerformErrRemote, - Msg: fedRes.LastError.Message, - RemoteCode: fedRes.LastError.Code, - } + return "", fedRes.LastError } return fedRes.JoinedVia, nil } @@ -429,10 +389,7 @@ func (r *Joiner) populateAuthorisedViaUserForRestrictedJoin( return "", nil } if !res.Allowed { - return "", &rsAPI.PerformError{ - Code: rsAPI.PerformErrorNotAllowed, - Msg: fmt.Sprintf("The join to room %s was not allowed.", joinReq.RoomIDOrAlias), - } + return "", rsAPI.ErrNotAllowed{Err: fmt.Errorf("the join to room %s was not allowed", joinReq.RoomIDOrAlias)} } return res.AuthorisedVia, nil } diff --git a/roomserver/internal/perform/perform_leave.go b/roomserver/internal/perform/perform_leave.go index 4dfb522a2..1db5707d9 100644 --- a/roomserver/internal/perform/perform_leave.go +++ b/roomserver/internal/perform/perform_leave.go @@ -196,7 +196,7 @@ func (r *Leaver) performLeaveRoomByID( InputRoomEvents: []api.InputRoomEvent{ { Kind: api.KindNew, - Event: event.Headered(buildRes.RoomVersion), + Event: event, Origin: senderDomain, SendAsServer: string(senderDomain), }, diff --git a/roomserver/internal/perform/perform_peek.go b/roomserver/internal/perform/perform_peek.go index 2f39050dd..661fe20a8 100644 --- a/roomserver/internal/perform/perform_peek.go +++ b/roomserver/internal/perform/perform_peek.go @@ -44,21 +44,8 @@ type Peeker struct { func (r *Peeker) PerformPeek( ctx context.Context, req *api.PerformPeekRequest, - res *api.PerformPeekResponse, -) error { - roomID, err := r.performPeek(ctx, req) - if err != nil { - perr, ok := err.(*api.PerformError) - if ok { - res.Error = perr - } else { - res.Error = &api.PerformError{ - Msg: err.Error(), - } - } - } - res.RoomID = roomID - return nil +) (roomID string, err error) { + return r.performPeek(ctx, req) } func (r *Peeker) performPeek( @@ -68,16 +55,10 @@ func (r *Peeker) performPeek( // FIXME: there's way too much duplication with performJoin _, domain, err := gomatrixserverlib.SplitID('@', req.UserID) if err != nil { - return "", &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("Supplied user ID %q in incorrect format", req.UserID), - } + return "", api.ErrInvalidID{Err: fmt.Errorf("supplied user ID %q in incorrect format", req.UserID)} } if !r.Cfg.Matrix.IsLocalServerName(domain) { - return "", &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("User %q does not belong to this homeserver", req.UserID), - } + return "", api.ErrInvalidID{Err: fmt.Errorf("user %q does not belong to this homeserver", req.UserID)} } if strings.HasPrefix(req.RoomIDOrAlias, "!") { return r.performPeekRoomByID(ctx, req) @@ -85,10 +66,7 @@ func (r *Peeker) performPeek( if strings.HasPrefix(req.RoomIDOrAlias, "#") { return r.performPeekRoomByAlias(ctx, req) } - return "", &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("Room ID or alias %q is invalid", req.RoomIDOrAlias), - } + return "", api.ErrInvalidID{Err: fmt.Errorf("room ID or alias %q is invalid", req.RoomIDOrAlias)} } func (r *Peeker) performPeekRoomByAlias( @@ -98,7 +76,7 @@ func (r *Peeker) performPeekRoomByAlias( // Get the domain part of the room alias. _, domain, err := gomatrixserverlib.SplitID('#', req.RoomIDOrAlias) if err != nil { - return "", fmt.Errorf("alias %q is not in the correct format", req.RoomIDOrAlias) + return "", api.ErrInvalidID{Err: fmt.Errorf("alias %q is not in the correct format", req.RoomIDOrAlias)} } req.ServerNames = append(req.ServerNames, domain) @@ -147,10 +125,7 @@ func (r *Peeker) performPeekRoomByID( // Get the domain part of the room ID. _, domain, err := gomatrixserverlib.SplitID('!', roomID) if err != nil { - return "", &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("Room ID %q is invalid: %s", roomID, err), - } + return "", api.ErrInvalidID{Err: fmt.Errorf("room ID %q is invalid: %w", roomID, err)} } // handle federated peeks @@ -169,11 +144,7 @@ func (r *Peeker) performPeekRoomByID( fedRes := fsAPI.PerformOutboundPeekResponse{} _ = r.FSAPI.PerformOutboundPeek(ctx, &fedReq, &fedRes) if fedRes.LastError != nil { - return "", &api.PerformError{ - Code: api.PerformErrRemote, - Msg: fedRes.LastError.Message, - RemoteCode: fedRes.LastError.Code, - } + return "", fedRes.LastError } } @@ -194,17 +165,11 @@ func (r *Peeker) performPeekRoomByID( } if !worldReadable { - return "", &api.PerformError{ - Code: api.PerformErrorNotAllowed, - Msg: "Room is not world-readable", - } + return "", api.ErrNotAllowed{Err: fmt.Errorf("room is not world-readable")} } if ev, _ := r.DB.GetStateEvent(ctx, roomID, "m.room.encryption", ""); ev != nil { - return "", &api.PerformError{ - Code: api.PerformErrorNotAllowed, - Msg: "Cannot peek into an encrypted room", - } + return "", api.ErrNotAllowed{Err: fmt.Errorf("Cannot peek into an encrypted room")} } // TODO: handle federated peeks diff --git a/roomserver/internal/perform/perform_publish.go b/roomserver/internal/perform/perform_publish.go index fbbfc3219..297a4a189 100644 --- a/roomserver/internal/perform/perform_publish.go +++ b/roomserver/internal/perform/perform_publish.go @@ -25,16 +25,10 @@ type Publisher struct { DB storage.Database } +// PerformPublish publishes or unpublishes a room from the room directory. Returns a database error, if any. func (r *Publisher) PerformPublish( ctx context.Context, req *api.PerformPublishRequest, - res *api.PerformPublishResponse, ) error { - err := r.DB.PublishRoom(ctx, req.RoomID, req.AppserviceID, req.NetworkID, req.Visibility == "public") - if err != nil { - res.Error = &api.PerformError{ - Msg: err.Error(), - } - } - return nil + return r.DB.PublishRoom(ctx, req.RoomID, req.AppserviceID, req.NetworkID, req.Visibility == "public") } diff --git a/roomserver/internal/perform/perform_unpeek.go b/roomserver/internal/perform/perform_unpeek.go index 28486fa14..1ea8079d4 100644 --- a/roomserver/internal/perform/perform_unpeek.go +++ b/roomserver/internal/perform/perform_unpeek.go @@ -34,84 +34,48 @@ type Unpeeker struct { Inputer *input.Inputer } -// PerformPeek handles peeking into matrix rooms, including over federation by talking to the federationapi. +// PerformUnpeek handles un-peeking matrix rooms, including over federation by talking to the federationapi. func (r *Unpeeker) PerformUnpeek( ctx context.Context, - req *api.PerformUnpeekRequest, - res *api.PerformUnpeekResponse, -) error { - if err := r.performUnpeek(ctx, req); err != nil { - perr, ok := err.(*api.PerformError) - if ok { - res.Error = perr - } else { - res.Error = &api.PerformError{ - Msg: err.Error(), - } - } - } - return nil -} - -func (r *Unpeeker) performUnpeek( - ctx context.Context, - req *api.PerformUnpeekRequest, + roomID, userID, deviceID string, ) error { // FIXME: there's way too much duplication with performJoin - _, domain, err := gomatrixserverlib.SplitID('@', req.UserID) + _, domain, err := gomatrixserverlib.SplitID('@', userID) if err != nil { - return &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("Supplied user ID %q in incorrect format", req.UserID), - } + return api.ErrInvalidID{Err: fmt.Errorf("supplied user ID %q in incorrect format", userID)} } if !r.Cfg.Matrix.IsLocalServerName(domain) { - return &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("User %q does not belong to this homeserver", req.UserID), - } + return api.ErrInvalidID{Err: fmt.Errorf("user %q does not belong to this homeserver", userID)} } - if strings.HasPrefix(req.RoomID, "!") { - return r.performUnpeekRoomByID(ctx, req) - } - return &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("Room ID %q is invalid", req.RoomID), + if strings.HasPrefix(roomID, "!") { + return r.performUnpeekRoomByID(ctx, roomID, userID, deviceID) } + return api.ErrInvalidID{Err: fmt.Errorf("room ID %q is invalid", roomID)} } func (r *Unpeeker) performUnpeekRoomByID( _ context.Context, - req *api.PerformUnpeekRequest, + roomID, userID, deviceID string, ) (err error) { // Get the domain part of the room ID. - _, _, err = gomatrixserverlib.SplitID('!', req.RoomID) + _, _, err = gomatrixserverlib.SplitID('!', roomID) if err != nil { - return &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("Room ID %q is invalid: %s", req.RoomID, err), - } + return api.ErrInvalidID{Err: fmt.Errorf("room ID %q is invalid: %w", roomID, err)} } // TODO: handle federated peeks - - err = r.Inputer.OutputProducer.ProduceRoomEvents(req.RoomID, []api.OutputEvent{ - { - Type: api.OutputTypeRetirePeek, - RetirePeek: &api.OutputRetirePeek{ - RoomID: req.RoomID, - UserID: req.UserID, - DeviceID: req.DeviceID, - }, - }, - }) - if err != nil { - return - } - // By this point, if req.RoomIDOrAlias contained an alias, then // it will have been overwritten with a room ID by performPeekRoomByAlias. // We should now include this in the response so that the CS API can // return the right room ID. - return nil + return r.Inputer.OutputProducer.ProduceRoomEvents(roomID, []api.OutputEvent{ + { + Type: api.OutputTypeRetirePeek, + RetirePeek: &api.OutputRetirePeek{ + RoomID: roomID, + UserID: userID, + DeviceID: deviceID, + }, + }, + }) } diff --git a/roomserver/internal/perform/perform_upgrade.go b/roomserver/internal/perform/perform_upgrade.go index ed57abf26..3a3c11482 100644 --- a/roomserver/internal/perform/perform_upgrade.go +++ b/roomserver/internal/perform/perform_upgrade.go @@ -22,6 +22,7 @@ import ( "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" @@ -44,46 +45,29 @@ type fledglingEvent struct { // PerformRoomUpgrade upgrades a room from one version to another func (r *Upgrader) PerformRoomUpgrade( ctx context.Context, - req *api.PerformRoomUpgradeRequest, - res *api.PerformRoomUpgradeResponse, -) error { - res.NewRoomID, res.Error = r.performRoomUpgrade(ctx, req) - if res.Error != nil { - res.NewRoomID = "" - logrus.WithContext(ctx).WithError(res.Error).Error("Room upgrade failed") - } - return nil + roomID, userID string, roomVersion gomatrixserverlib.RoomVersion, +) (newRoomID string, err error) { + return r.performRoomUpgrade(ctx, roomID, userID, roomVersion) } func (r *Upgrader) performRoomUpgrade( ctx context.Context, - req *api.PerformRoomUpgradeRequest, -) (string, *api.PerformError) { - roomID := req.RoomID - userID := req.UserID + roomID, userID string, roomVersion gomatrixserverlib.RoomVersion, +) (string, error) { _, userDomain, err := r.Cfg.Matrix.SplitLocalID('@', userID) if err != nil { - return "", &api.PerformError{ - Code: api.PerformErrorNotAllowed, - Msg: "Error validating the user ID", - } + return "", api.ErrNotAllowed{Err: fmt.Errorf("error validating the user ID")} } evTime := time.Now() // Return an immediate error if the room does not exist if err := r.validateRoomExists(ctx, roomID); err != nil { - return "", &api.PerformError{ - Code: api.PerformErrorNoRoom, - Msg: "Error validating that the room exists", - } + return "", err } // 1. Check if the user is authorized to actually perform the upgrade (can send m.room.tombstone) if !r.userIsAuthorized(ctx, userID, roomID) { - return "", &api.PerformError{ - Code: api.PerformErrorNotAllowed, - Msg: "You don't have permission to upgrade the room, power level too low.", - } + return "", api.ErrNotAllowed{Err: fmt.Errorf("You don't have permission to upgrade the room, power level too low.")} } // TODO (#267): Check room ID doesn't clash with an existing one, and we @@ -96,9 +80,7 @@ func (r *Upgrader) performRoomUpgrade( } oldRoomRes := &api.QueryLatestEventsAndStateResponse{} if err := r.URSAPI.QueryLatestEventsAndState(ctx, oldRoomReq, oldRoomRes); err != nil { - return "", &api.PerformError{ - Msg: fmt.Sprintf("Failed to get latest state: %s", err), - } + return "", fmt.Errorf("Failed to get latest state: %s", err) } // Make the tombstone event @@ -109,13 +91,13 @@ func (r *Upgrader) performRoomUpgrade( // Generate the initial events we need to send into the new room. This includes copied state events and bans // as well as the power level events needed to set up the room - eventsToMake, pErr := r.generateInitialEvents(ctx, oldRoomRes, userID, roomID, string(req.RoomVersion), tombstoneEvent) + eventsToMake, pErr := r.generateInitialEvents(ctx, oldRoomRes, userID, roomID, roomVersion, tombstoneEvent) if pErr != nil { return "", pErr } // Send the setup events to the new room - if pErr = r.sendInitialEvents(ctx, evTime, userID, userDomain, newRoomID, string(req.RoomVersion), eventsToMake); pErr != nil { + if pErr = r.sendInitialEvents(ctx, evTime, userID, userDomain, newRoomID, roomVersion, eventsToMake); pErr != nil { return "", pErr } @@ -147,22 +129,15 @@ func (r *Upgrader) performRoomUpgrade( return newRoomID, nil } -func (r *Upgrader) getRoomPowerLevels(ctx context.Context, roomID string) (*gomatrixserverlib.PowerLevelContent, *api.PerformError) { +func (r *Upgrader) getRoomPowerLevels(ctx context.Context, roomID string) (*gomatrixserverlib.PowerLevelContent, error) { oldPowerLevelsEvent := api.GetStateEvent(ctx, r.URSAPI, roomID, gomatrixserverlib.StateKeyTuple{ EventType: spec.MRoomPowerLevels, StateKey: "", }) - powerLevelContent, err := oldPowerLevelsEvent.PowerLevels() - if err != nil { - util.GetLogger(ctx).WithError(err).Error() - return nil, &api.PerformError{ - Msg: "Power level event was invalid or malformed", - } - } - return powerLevelContent, nil + return oldPowerLevelsEvent.PowerLevels() } -func (r *Upgrader) restrictOldRoomPowerLevels(ctx context.Context, evTime time.Time, userID string, userDomain spec.ServerName, roomID string) *api.PerformError { +func (r *Upgrader) restrictOldRoomPowerLevels(ctx context.Context, evTime time.Time, userID string, userDomain spec.ServerName, roomID string) error { restrictedPowerLevelContent, pErr := r.getRoomPowerLevels(ctx, roomID) if pErr != nil { return pErr @@ -184,54 +159,46 @@ func (r *Upgrader) restrictOldRoomPowerLevels(ctx context.Context, evTime time.T StateKey: "", Content: restrictedPowerLevelContent, }) - if resErr != nil { - if resErr.Code == api.PerformErrorNotAllowed { - util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not restrict power levels in old room") - } else { - return resErr - } - } else { - if resErr = r.sendHeaderedEvent(ctx, userDomain, restrictedPowerLevelsHeadered, api.DoNotSendToOtherServers); resErr != nil { - return resErr - } + + switch resErr.(type) { + case api.ErrNotAllowed: + util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not restrict power levels in old room") + case nil: + return r.sendHeaderedEvent(ctx, userDomain, restrictedPowerLevelsHeadered, api.DoNotSendToOtherServers) + default: + return resErr } return nil } func moveLocalAliases(ctx context.Context, roomID, newRoomID, userID string, - URSAPI api.RoomserverInternalAPI) *api.PerformError { - var err error + URSAPI api.RoomserverInternalAPI, +) (err error) { aliasReq := api.GetAliasesForRoomIDRequest{RoomID: roomID} aliasRes := api.GetAliasesForRoomIDResponse{} if err = URSAPI.GetAliasesForRoomID(ctx, &aliasReq, &aliasRes); err != nil { - return &api.PerformError{ - Msg: fmt.Sprintf("Failed to get old room aliases: %s", err), - } + return fmt.Errorf("Failed to get old room aliases: %w", err) } for _, alias := range aliasRes.Aliases { removeAliasReq := api.RemoveRoomAliasRequest{UserID: userID, Alias: alias} removeAliasRes := api.RemoveRoomAliasResponse{} if err = URSAPI.RemoveRoomAlias(ctx, &removeAliasReq, &removeAliasRes); err != nil { - return &api.PerformError{ - Msg: fmt.Sprintf("Failed to remove old room alias: %s", err), - } + return fmt.Errorf("Failed to remove old room alias: %w", err) } setAliasReq := api.SetRoomAliasRequest{UserID: userID, Alias: alias, RoomID: newRoomID} setAliasRes := api.SetRoomAliasResponse{} if err = URSAPI.SetRoomAlias(ctx, &setAliasReq, &setAliasRes); err != nil { - return &api.PerformError{ - Msg: fmt.Sprintf("Failed to set new room alias: %s", err), - } + return fmt.Errorf("Failed to set new room alias: %w", err) } } return nil } -func (r *Upgrader) clearOldCanonicalAliasEvent(ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, evTime time.Time, userID string, userDomain spec.ServerName, roomID string) *api.PerformError { +func (r *Upgrader) clearOldCanonicalAliasEvent(ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, evTime time.Time, userID string, userDomain spec.ServerName, roomID string) error { for _, event := range oldRoom.StateEvents { if event.Type() != spec.MRoomCanonicalAlias || !event.StateKeyEquals("") { continue @@ -241,9 +208,7 @@ func (r *Upgrader) clearOldCanonicalAliasEvent(ctx context.Context, oldRoom *api AltAliases []string `json:"alt_aliases"` } if err := json.Unmarshal(event.Content(), &aliasContent); err != nil { - return &api.PerformError{ - Msg: fmt.Sprintf("Failed to unmarshal canonical aliases: %s", err), - } + return fmt.Errorf("failed to unmarshal canonical aliases: %w", err) } if aliasContent.Alias == "" && len(aliasContent.AltAliases) == 0 { // There are no canonical aliases to clear, therefore do nothing. @@ -255,30 +220,25 @@ func (r *Upgrader) clearOldCanonicalAliasEvent(ctx context.Context, oldRoom *api Type: spec.MRoomCanonicalAlias, Content: map[string]interface{}{}, }) - if resErr != nil { - if resErr.Code == api.PerformErrorNotAllowed { - util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not set empty canonical alias event in old room") - } else { - return resErr - } - } else { - if resErr = r.sendHeaderedEvent(ctx, userDomain, emptyCanonicalAliasEvent, api.DoNotSendToOtherServers); resErr != nil { - return resErr - } + switch resErr.(type) { + case api.ErrNotAllowed: + util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not set empty canonical alias event in old room") + case nil: + return r.sendHeaderedEvent(ctx, userDomain, emptyCanonicalAliasEvent, api.DoNotSendToOtherServers) + default: + return resErr } return nil } -func (r *Upgrader) publishIfOldRoomWasPublic(ctx context.Context, roomID, newRoomID string) *api.PerformError { +func (r *Upgrader) publishIfOldRoomWasPublic(ctx context.Context, roomID, newRoomID string) error { // check if the old room was published var pubQueryRes api.QueryPublishedRoomsResponse err := r.URSAPI.QueryPublishedRooms(ctx, &api.QueryPublishedRoomsRequest{ RoomID: roomID, }, &pubQueryRes) if err != nil { - return &api.PerformError{ - Msg: "QueryPublishedRooms failed", - } + return err } // if the old room is published (was public), publish the new room @@ -294,38 +254,27 @@ func publishNewRoomAndUnpublishOldRoom( oldRoomID, newRoomID string, ) { // expose this room in the published room list - var pubNewRoomRes api.PerformPublishResponse if err := URSAPI.PerformPublish(ctx, &api.PerformPublishRequest{ RoomID: newRoomID, - Visibility: "public", - }, &pubNewRoomRes); err != nil { - util.GetLogger(ctx).WithError(err).Error("failed to reach internal API") - } else if pubNewRoomRes.Error != nil { + Visibility: spec.Public, + }); err != nil { // treat as non-fatal since the room is already made by this point - util.GetLogger(ctx).WithError(pubNewRoomRes.Error).Error("failed to visibility:public") + util.GetLogger(ctx).WithError(err).Error("failed to publish room") } - var unpubOldRoomRes api.PerformPublishResponse // remove the old room from the published room list if err := URSAPI.PerformPublish(ctx, &api.PerformPublishRequest{ RoomID: oldRoomID, Visibility: "private", - }, &unpubOldRoomRes); err != nil { - util.GetLogger(ctx).WithError(err).Error("failed to reach internal API") - } else if unpubOldRoomRes.Error != nil { + }); err != nil { // treat as non-fatal since the room is already made by this point - util.GetLogger(ctx).WithError(unpubOldRoomRes.Error).Error("failed to visibility:private") + util.GetLogger(ctx).WithError(err).Error("failed to un-publish room") } } func (r *Upgrader) validateRoomExists(ctx context.Context, roomID string) error { - verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID} - verRes := api.QueryRoomVersionForRoomResponse{} - if err := r.URSAPI.QueryRoomVersionForRoom(ctx, &verReq, &verRes); err != nil { - return &api.PerformError{ - Code: api.PerformErrorNoRoom, - Msg: "Room does not exist", - } + if _, err := r.URSAPI.QueryRoomVersionForRoom(ctx, roomID); err != nil { + return eventutil.ErrRoomNoExists } return nil } @@ -349,15 +298,15 @@ func (r *Upgrader) userIsAuthorized(ctx context.Context, userID, roomID string, } // nolint:gocyclo -func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, userID, roomID, newVersion string, tombstoneEvent *gomatrixserverlib.HeaderedEvent) ([]fledglingEvent, *api.PerformError) { - state := make(map[gomatrixserverlib.StateKeyTuple]*gomatrixserverlib.HeaderedEvent, len(oldRoom.StateEvents)) +func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, userID, roomID string, newVersion gomatrixserverlib.RoomVersion, tombstoneEvent *types.HeaderedEvent) ([]fledglingEvent, error) { + state := make(map[gomatrixserverlib.StateKeyTuple]*types.HeaderedEvent, len(oldRoom.StateEvents)) for _, event := range oldRoom.StateEvents { if event.StateKey() == nil { // This shouldn't ever happen, but better to be safe than sorry. continue } if event.Type() == spec.MRoomMember && !event.StateKeyEquals(userID) { - // With the exception of bans and invites which we do want to copy, we + // With the exception of bans which we do want to copy, we // should ignore membership events that aren't our own, as event auth will // prevent us from being able to create membership events on behalf of other // users anyway unless they are invites or bans. @@ -367,11 +316,15 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query } switch membership { case spec.Ban: - case spec.Invite: default: continue } } + // skip events that rely on a specific user being present + sKey := *event.StateKey() + if event.Type() != spec.MRoomMember && len(sKey) > 0 && sKey[:1] == "@" { + continue + } state[gomatrixserverlib.StateKeyTuple{EventType: event.Type(), StateKey: *event.StateKey()}] = event } @@ -388,9 +341,7 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query // old room state. Check that they are there. for tuple := range override { if _, ok := state[tuple]; !ok { - return nil, &api.PerformError{ - Msg: fmt.Sprintf("Essential event of type %q state key %q is missing", tuple.EventType, tuple.StateKey), - } + return nil, fmt.Errorf("essential event of type %q state key %q is missing", tuple.EventType, tuple.StateKey) } } @@ -437,9 +388,7 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query powerLevelContent, err := oldPowerLevelsEvent.PowerLevels() if err != nil { util.GetLogger(ctx).WithError(err).Error() - return nil, &api.PerformError{ - Msg: "Power level event content was invalid", - } + return nil, fmt.Errorf("Power level event content was invalid") } tempPowerLevelsEvent, powerLevelsOverridden := createTemporaryPowerLevels(powerLevelContent, userID) @@ -503,9 +452,9 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query return eventsToMake, nil } -func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, userID string, userDomain spec.ServerName, newRoomID, newVersion string, eventsToMake []fledglingEvent) *api.PerformError { +func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, userID string, userDomain spec.ServerName, newRoomID string, newVersion gomatrixserverlib.RoomVersion, eventsToMake []fledglingEvent) error { var err error - var builtEvents []*gomatrixserverlib.HeaderedEvent + var builtEvents []*types.HeaderedEvent authEvents := gomatrixserverlib.NewAuthEvents(nil) for i, e := range eventsToMake { depth := i + 1 // depth starts at 1 @@ -519,34 +468,27 @@ func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, user } err = builder.SetContent(e.Content) if err != nil { - return &api.PerformError{ - Msg: fmt.Sprintf("Failed to set content of new %q event: %s", builder.Type, err), - } + return fmt.Errorf("failed to set content of new %q event: %w", builder.Type, err) } if i > 0 { builder.PrevEvents = []gomatrixserverlib.EventReference{builtEvents[i-1].EventReference()} } var event *gomatrixserverlib.Event - event, err = builder.AddAuthEventsAndBuild(userDomain, &authEvents, evTime, gomatrixserverlib.RoomVersion(newVersion), r.Cfg.Matrix.KeyID, r.Cfg.Matrix.PrivateKey) + event, err = builder.AddAuthEventsAndBuild(userDomain, &authEvents, evTime, newVersion, r.Cfg.Matrix.KeyID, r.Cfg.Matrix.PrivateKey) if err != nil { - return &api.PerformError{ - Msg: fmt.Sprintf("Failed to build new %q event: %s", builder.Type, err), - } + return fmt.Errorf("failed to build new %q event: %w", builder.Type, err) + } if err = gomatrixserverlib.Allowed(event, &authEvents); err != nil { - return &api.PerformError{ - Msg: fmt.Sprintf("Failed to auth new %q event: %s", builder.Type, err), - } + return fmt.Errorf("Failed to auth new %q event: %w", builder.Type, err) } // Add the event to the list of auth events - builtEvents = append(builtEvents, event.Headered(gomatrixserverlib.RoomVersion(newVersion))) + builtEvents = append(builtEvents, &types.HeaderedEvent{Event: event}) err = authEvents.AddEvent(event) if err != nil { - return &api.PerformError{ - Msg: fmt.Sprintf("Failed to add new %q event to auth set: %s", builder.Type, err), - } + return fmt.Errorf("failed to add new %q event to auth set: %w", builder.Type, err) } } @@ -560,9 +502,7 @@ func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, user }) } if err = api.SendInputRoomEvents(ctx, r.URSAPI, userDomain, inputs, false); err != nil { - return &api.PerformError{ - Msg: fmt.Sprintf("Failed to send new room %q to roomserver: %s", newRoomID, err), - } + return fmt.Errorf("failed to send new room %q to roomserver: %w", newRoomID, err) } return nil } @@ -571,7 +511,7 @@ func (r *Upgrader) makeTombstoneEvent( ctx context.Context, evTime time.Time, userID, roomID, newRoomID string, -) (*gomatrixserverlib.HeaderedEvent, *api.PerformError) { +) (*types.HeaderedEvent, error) { content := map[string]interface{}{ "body": "This room has been replaced", "replacement_room": newRoomID, @@ -583,7 +523,7 @@ func (r *Upgrader) makeTombstoneEvent( return r.makeHeaderedEvent(ctx, evTime, userID, roomID, event) } -func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, userID, roomID string, event fledglingEvent) (*gomatrixserverlib.HeaderedEvent, *api.PerformError) { +func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, userID, roomID string, event fledglingEvent) (*types.HeaderedEvent, error) { builder := gomatrixserverlib.EventBuilder{ Sender: userID, RoomID: roomID, @@ -592,59 +532,36 @@ func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, user } err := builder.SetContent(event.Content) if err != nil { - return nil, &api.PerformError{ - Msg: fmt.Sprintf("Failed to set new %q event content: %s", builder.Type, err), - } + return nil, fmt.Errorf("failed to set new %q event content: %w", builder.Type, err) } // Get the sender domain. _, senderDomain, serr := r.Cfg.Matrix.SplitLocalID('@', builder.Sender) if serr != nil { - return nil, &api.PerformError{ - Msg: fmt.Sprintf("Failed to split user ID %q: %s", builder.Sender, err), - } + return nil, fmt.Errorf("Failed to split user ID %q: %w", builder.Sender, err) } identity, err := r.Cfg.Matrix.SigningIdentityFor(senderDomain) if err != nil { - return nil, &api.PerformError{ - Msg: fmt.Sprintf("Failed to get signing identity for %q: %s", senderDomain, err), - } + return nil, fmt.Errorf("failed to get signing identity for %q: %w", senderDomain, err) } var queryRes api.QueryLatestEventsAndStateResponse headeredEvent, err := eventutil.QueryAndBuildEvent(ctx, &builder, r.Cfg.Matrix, identity, evTime, r.URSAPI, &queryRes) if err == eventutil.ErrRoomNoExists { - return nil, &api.PerformError{ - Code: api.PerformErrorNoRoom, - Msg: "Room does not exist", - } + return nil, err } else if e, ok := err.(gomatrixserverlib.BadJSONError); ok { - return nil, &api.PerformError{ - Msg: e.Error(), - } + return nil, e } else if e, ok := err.(gomatrixserverlib.EventValidationError); ok { - if e.Code == gomatrixserverlib.EventValidationTooLarge { - return nil, &api.PerformError{ - Msg: e.Error(), - } - } - return nil, &api.PerformError{ - Msg: e.Error(), - } + return nil, e } else if err != nil { - return nil, &api.PerformError{ - Msg: fmt.Sprintf("Failed to build new %q event: %s", builder.Type, err), - } + return nil, fmt.Errorf("failed to build new %q event: %w", builder.Type, err) } // check to see if this user can perform this operation stateEvents := make([]*gomatrixserverlib.Event, len(queryRes.StateEvents)) for i := range queryRes.StateEvents { stateEvents[i] = queryRes.StateEvents[i].Event } - provider := gomatrixserverlib.NewAuthEvents(stateEvents) + provider := gomatrixserverlib.NewAuthEvents(gomatrixserverlib.ToPDUs(stateEvents)) if err = gomatrixserverlib.Allowed(headeredEvent.Event, &provider); err != nil { - return nil, &api.PerformError{ - Code: api.PerformErrorNotAllowed, - Msg: fmt.Sprintf("Failed to auth new %q event: %s", builder.Type, err), // TODO: Is this error string comprehensible to the client? - } + return nil, api.ErrNotAllowed{Err: fmt.Errorf("failed to auth new %q event: %w", builder.Type, err)} // TODO: Is this error string comprehensible to the client? } return headeredEvent, nil @@ -690,9 +607,9 @@ func createTemporaryPowerLevels(powerLevelContent *gomatrixserverlib.PowerLevelC func (r *Upgrader) sendHeaderedEvent( ctx context.Context, serverName spec.ServerName, - headeredEvent *gomatrixserverlib.HeaderedEvent, + headeredEvent *types.HeaderedEvent, sendAsServer string, -) *api.PerformError { +) error { var inputs []api.InputRoomEvent inputs = append(inputs, api.InputRoomEvent{ Kind: api.KindNew, @@ -700,11 +617,5 @@ func (r *Upgrader) sendHeaderedEvent( Origin: serverName, SendAsServer: sendAsServer, }) - if err := api.SendInputRoomEvents(ctx, r.URSAPI, serverName, inputs, false); err != nil { - return &api.PerformError{ - Msg: fmt.Sprintf("Failed to send new %q event to roomserver: %s", headeredEvent.Type(), err), - } - } - - return nil + return api.SendInputRoomEvents(ctx, r.URSAPI, serverName, inputs, false) } diff --git a/roomserver/internal/query/query.go b/roomserver/internal/query/query.go index 8a5a99663..4bd648a9b 100644 --- a/roomserver/internal/query/query.go +++ b/roomserver/internal/query/query.go @@ -121,14 +121,17 @@ func (r *Queryer) QueryStateAfterEvents( return fmt.Errorf("getAuthChain: %w", err) } - stateEvents, err = gomatrixserverlib.ResolveConflicts(info.RoomVersion, stateEvents, authEvents) + stateEventsPDU, err := gomatrixserverlib.ResolveConflicts( + info.RoomVersion, gomatrixserverlib.ToPDUs(stateEvents), gomatrixserverlib.ToPDUs(authEvents), + ) if err != nil { return fmt.Errorf("state.ResolveConflictsAdhoc: %w", err) } + stateEvents = gomatrixserverlib.TempCastToEvents(stateEventsPDU) } for _, event := range stateEvents { - response.StateEvents = append(response.StateEvents, event.Headered(info.RoomVersion)) + response.StateEvents = append(response.StateEvents, &types.HeaderedEvent{Event: event}) } return nil @@ -173,7 +176,7 @@ func (r *Queryer) QueryEventsByID( } for _, event := range events { - response.Events = append(response.Events, event.Headered(roomInfo.RoomVersion)) + response.Events = append(response.Events, &types.HeaderedEvent{Event: event.Event}) } return nil @@ -231,7 +234,7 @@ func (r *Queryer) QueryMembershipAtEvent( request *api.QueryMembershipAtEventRequest, response *api.QueryMembershipAtEventResponse, ) error { - response.Membership = make(map[string]*gomatrixserverlib.HeaderedEvent) + response.Membership = make(map[string]*types.HeaderedEvent) info, err := r.DB.RoomInfo(ctx, request.RoomID) if err != nil { @@ -259,7 +262,7 @@ func (r *Queryer) QueryMembershipAtEvent( return err } - response.Membership = make(map[string]*gomatrixserverlib.HeaderedEvent) + response.Membership = make(map[string]*types.HeaderedEvent) stateEntries, err := helpers.MembershipAtEvent(ctx, r.DB, nil, request.EventIDs, stateKeyNIDs[request.UserID]) if err != nil { return fmt.Errorf("unable to get state before event: %w", err) @@ -307,7 +310,7 @@ func (r *Queryer) QueryMembershipAtEvent( for i := range memberships { ev := memberships[i] if ev.Type() == spec.MRoomMember && ev.StateKeyEquals(request.UserID) { - response.Membership[eventID] = ev.Event.Headered(info.RoomVersion) + response.Membership[eventID] = &types.HeaderedEvent{Event: ev.Event} } } } @@ -518,17 +521,13 @@ func (r *Queryer) QueryMissingEvents( return err } - response.Events = make([]*gomatrixserverlib.HeaderedEvent, 0, len(loadedEvents)-len(eventsToFilter)) + response.Events = make([]*types.HeaderedEvent, 0, len(loadedEvents)-len(eventsToFilter)) for _, event := range loadedEvents { if !eventsToFilter[event.EventID()] { - roomVersion, verr := r.roomVersion(event.RoomID()) - if verr != nil { - return verr - } if _, ok := redactEventIDs[event.EventID()]; ok { event.Redact() } - response.Events = append(response.Events, event.Headered(roomVersion)) + response.Events = append(response.Events, &types.HeaderedEvent{Event: event}) } } @@ -561,7 +560,7 @@ func (r *Queryer) QueryStateAndAuthChain( return err } for _, event := range authEvents { - response.AuthChainEvents = append(response.AuthChainEvents, event.Headered(info.RoomVersion)) + response.AuthChainEvents = append(response.AuthChainEvents, &types.HeaderedEvent{Event: event}) } return nil } @@ -589,19 +588,21 @@ func (r *Queryer) QueryStateAndAuthChain( } if request.ResolveState { - if stateEvents, err = gomatrixserverlib.ResolveConflicts( - info.RoomVersion, stateEvents, authEvents, - ); err != nil { - return err + stateEventsPDU, err2 := gomatrixserverlib.ResolveConflicts( + info.RoomVersion, gomatrixserverlib.ToPDUs(stateEvents), gomatrixserverlib.ToPDUs(authEvents), + ) + if err2 != nil { + return err2 } + stateEvents = gomatrixserverlib.TempCastToEvents(stateEventsPDU) } for _, event := range stateEvents { - response.StateEvents = append(response.StateEvents, event.Headered(info.RoomVersion)) + response.StateEvents = append(response.StateEvents, &types.HeaderedEvent{Event: event}) } for _, event := range authEvents { - response.AuthChainEvents = append(response.AuthChainEvents, event.Headered(info.RoomVersion)) + response.AuthChainEvents = append(response.AuthChainEvents, &types.HeaderedEvent{Event: event}) } return err @@ -696,34 +697,20 @@ func GetAuthChain( } // QueryRoomVersionForRoom implements api.RoomserverInternalAPI -func (r *Queryer) QueryRoomVersionForRoom( - ctx context.Context, - request *api.QueryRoomVersionForRoomRequest, - response *api.QueryRoomVersionForRoomResponse, -) error { - if roomVersion, ok := r.Cache.GetRoomVersion(request.RoomID); ok { - response.RoomVersion = roomVersion - return nil +func (r *Queryer) QueryRoomVersionForRoom(ctx context.Context, roomID string) (gomatrixserverlib.RoomVersion, error) { + if roomVersion, ok := r.Cache.GetRoomVersion(roomID); ok { + return roomVersion, nil } - info, err := r.DB.RoomInfo(ctx, request.RoomID) + info, err := r.DB.RoomInfo(ctx, roomID) if err != nil { - return err + return "", err } if info == nil { - return fmt.Errorf("QueryRoomVersionForRoom: missing room info for room %s", request.RoomID) + return "", fmt.Errorf("QueryRoomVersionForRoom: missing room info for room %s", roomID) } - response.RoomVersion = info.RoomVersion - r.Cache.StoreRoomVersion(request.RoomID, response.RoomVersion) - return nil -} - -func (r *Queryer) roomVersion(roomID string) (gomatrixserverlib.RoomVersion, error) { - var res api.QueryRoomVersionForRoomResponse - err := r.QueryRoomVersionForRoom(context.Background(), &api.QueryRoomVersionForRoomRequest{ - RoomID: roomID, - }, &res) - return res.RoomVersion, err + r.Cache.StoreRoomVersion(roomID, info.RoomVersion) + return info.RoomVersion, nil } func (r *Queryer) QueryPublishedRooms( @@ -748,7 +735,7 @@ func (r *Queryer) QueryPublishedRooms( } func (r *Queryer) QueryCurrentState(ctx context.Context, req *api.QueryCurrentStateRequest, res *api.QueryCurrentStateResponse) error { - res.StateEvents = make(map[gomatrixserverlib.StateKeyTuple]*gomatrixserverlib.HeaderedEvent) + res.StateEvents = make(map[gomatrixserverlib.StateKeyTuple]*types.HeaderedEvent) for _, tuple := range req.StateTuples { if tuple.StateKey == "*" && req.AllowWildcards { events, err := r.DB.GetStateEventsWithEventType(ctx, req.RoomID, tuple.EventType) @@ -865,9 +852,9 @@ func (r *Queryer) QueryAuthChain(ctx context.Context, req *api.QueryAuthChainReq if err != nil { return err } - hchain := make([]*gomatrixserverlib.HeaderedEvent, len(chain)) + hchain := make([]*types.HeaderedEvent, len(chain)) for i := range chain { - hchain[i] = chain[i].Headered(chain[i].Version()) + hchain[i] = &types.HeaderedEvent{Event: chain[i]} } res.AuthChain = hchain return nil @@ -910,8 +897,8 @@ func (r *Queryer) QueryRestrictedJoinAllowed(ctx context.Context, req *api.Query if err = json.Unmarshal(joinRulesEvent.Content(), &joinRules); err != nil { return fmt.Errorf("json.Unmarshal: %w", err) } - // If the join rule isn't "restricted" then there's nothing more to do. - res.Restricted = joinRules.JoinRule == spec.Restricted + // If the join rule isn't "restricted" or "knock_restricted" then there's nothing more to do. + res.Restricted = joinRules.JoinRule == spec.Restricted || joinRules.JoinRule == spec.KnockRestricted if !res.Restricted { return nil } @@ -932,9 +919,9 @@ func (r *Queryer) QueryRestrictedJoinAllowed(ctx context.Context, req *api.Query if err != nil { return fmt.Errorf("r.DB.GetStateEvent: %w", err) } - var powerLevels gomatrixserverlib.PowerLevelContent - if err = json.Unmarshal(powerLevelsEvent.Content(), &powerLevels); err != nil { - return fmt.Errorf("json.Unmarshal: %w", err) + powerLevels, err := powerLevelsEvent.PowerLevels() + if err != nil { + return fmt.Errorf("unable to get powerlevels: %w", err) } // Step through the join rules and see if the user matches any of them. for _, rule := range joinRules.Allow { diff --git a/roomserver/producers/roomevent.go b/roomserver/producers/roomevent.go index 9c4521986..0e1f4e1fc 100644 --- a/roomserver/producers/roomevent.go +++ b/roomserver/producers/roomevent.go @@ -74,7 +74,7 @@ func (r *RoomEventProducer) ProduceRoomEvents(roomID string, updates []api.Outpu } if eventType == "m.room.server_acl" && update.NewRoomEvent.Event.StateKeyEquals("") { - ev := update.NewRoomEvent.Event.Unwrap() + ev := update.NewRoomEvent.Event.Event defer r.ACLs.OnServerACLUpdate(ev) } } diff --git a/roomserver/roomserver_test.go b/roomserver/roomserver_test.go index 67d6db46f..4c88e12b2 100644 --- a/roomserver/roomserver_test.go +++ b/roomserver/roomserver_test.go @@ -8,10 +8,13 @@ import ( "time" "github.com/matrix-org/dendrite/internal/caching" + "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/sqlutil" + "github.com/matrix-org/dendrite/roomserver/version" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/stretchr/testify/assert" + "github.com/tidwall/gjson" "github.com/matrix-org/dendrite/roomserver/state" "github.com/matrix-org/dendrite/roomserver/types" @@ -136,7 +139,7 @@ func testKickUsers(t *testing.T, rsAPI api.RoomserverInternalAPI, usrAPI userAPI // revoke guest access revokeEvent := room.CreateAndInsert(t, alice, spec.MRoomGuestAccess, map[string]string{"guest_access": "forbidden"}, test.WithStateKey("")) - if err := api.SendEvents(ctx, rsAPI, api.KindNew, []*gomatrixserverlib.HeaderedEvent{revokeEvent}, "test", "test", "test", nil, false); err != nil { + if err := api.SendEvents(ctx, rsAPI, api.KindNew, []*types.HeaderedEvent{revokeEvent}, "test", "test", "test", nil, false); err != nil { t.Errorf("failed to send events: %v", err) } @@ -242,8 +245,8 @@ func TestPurgeRoom(t *testing.T) { // this starts the JetStream consumers syncapi.AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, userAPI, rsAPI, caches, caching.DisableMetrics) - federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, nil, rsAPI, caches, nil, true) - rsAPI.SetFederationAPI(nil, nil) + fsAPI := federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, nil, rsAPI, caches, nil, true) + rsAPI.SetFederationAPI(fsAPI, nil) // Create the room if err = api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil { @@ -251,13 +254,9 @@ func TestPurgeRoom(t *testing.T) { } // some dummy entries to validate after purging - publishResp := &api.PerformPublishResponse{} - if err = rsAPI.PerformPublish(ctx, &api.PerformPublishRequest{RoomID: room.ID, Visibility: "public"}, publishResp); err != nil { + if err = rsAPI.PerformPublish(ctx, &api.PerformPublishRequest{RoomID: room.ID, Visibility: spec.Public}); err != nil { t.Fatal(err) } - if publishResp.Error != nil { - t.Fatal(publishResp.Error) - } isPublished, err := db.GetPublishedRoom(ctx, room.ID) if err != nil { @@ -325,8 +324,7 @@ func TestPurgeRoom(t *testing.T) { } // purge the room from the database - purgeResp := &api.PerformAdminPurgeRoomResponse{} - if err = rsAPI.PerformAdminPurgeRoom(ctx, &api.PerformAdminPurgeRoomRequest{RoomID: room.ID}, purgeResp); err != nil { + if err = rsAPI.PerformAdminPurgeRoom(ctx, room.ID); err != nil { t.Fatal(err) } @@ -401,7 +399,7 @@ type fledglingEvent struct { PrevEvents []interface{} } -func mustCreateEvent(t *testing.T, ev fledglingEvent) (result *gomatrixserverlib.HeaderedEvent) { +func mustCreateEvent(t *testing.T, ev fledglingEvent) (result *types.HeaderedEvent) { t.Helper() roomVer := gomatrixserverlib.RoomVersionV9 seed := make([]byte, ed25519.SeedSize) // zero seed @@ -423,7 +421,7 @@ func mustCreateEvent(t *testing.T, ev fledglingEvent) (result *gomatrixserverlib if err != nil { t.Fatalf("mustCreateEvent: failed to sign event: %s", err) } - h := signedEvent.Headered(roomVer) + h := &types.HeaderedEvent{Event: signedEvent} return h } @@ -451,7 +449,7 @@ func TestRedaction(t *testing.T) { Depth: redactedEvent.Depth() + 1, PrevEvents: []interface{}{redactedEvent.EventID()}, }) - room.InsertEvent(t, builderEv.Headered(gomatrixserverlib.RoomVersionV9)) + room.InsertEvent(t, builderEv) }, }, { @@ -468,7 +466,7 @@ func TestRedaction(t *testing.T) { Depth: redactedEvent.Depth() + 1, PrevEvents: []interface{}{redactedEvent.EventID()}, }) - room.InsertEvent(t, builderEv.Headered(gomatrixserverlib.RoomVersionV9)) + room.InsertEvent(t, builderEv) }, }, { @@ -485,7 +483,7 @@ func TestRedaction(t *testing.T) { Depth: redactedEvent.Depth() + 1, PrevEvents: []interface{}{redactedEvent.EventID()}, }) - room.InsertEvent(t, builderEv.Headered(gomatrixserverlib.RoomVersionV9)) + room.InsertEvent(t, builderEv) }, }, { @@ -501,7 +499,7 @@ func TestRedaction(t *testing.T) { Depth: redactedEvent.Depth() + 1, PrevEvents: []interface{}{redactedEvent.EventID()}, }) - room.InsertEvent(t, builderEv.Headered(gomatrixserverlib.RoomVersionV9)) + room.InsertEvent(t, builderEv) }, }, } @@ -582,3 +580,506 @@ func TestRedaction(t *testing.T) { } }) } + +func TestQueryRestrictedJoinAllowed(t *testing.T) { + alice := test.NewUser(t) + bob := test.NewUser(t) + + // a room we don't create in the database + allowedByRoomNotExists := test.NewRoom(t, alice) + + // a room we create in the database, used for authorisation + allowedByRoomExists := test.NewRoom(t, alice) + allowedByRoomExists.CreateAndInsert(t, bob, spec.MRoomMember, map[string]interface{}{ + "membership": spec.Join, + }, test.WithStateKey(bob.ID)) + + testCases := []struct { + name string + prepareRoomFunc func(t *testing.T) *test.Room + wantResponse api.QueryRestrictedJoinAllowedResponse + }{ + { + name: "public room unrestricted", + prepareRoomFunc: func(t *testing.T) *test.Room { + return test.NewRoom(t, alice) + }, + wantResponse: api.QueryRestrictedJoinAllowedResponse{ + Resident: true, + }, + }, + { + name: "room version without restrictions", + prepareRoomFunc: func(t *testing.T) *test.Room { + return test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV7)) + }, + }, + { + name: "restricted only", // bob is not allowed to join + prepareRoomFunc: func(t *testing.T) *test.Room { + r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV8)) + r.CreateAndInsert(t, alice, spec.MRoomJoinRules, map[string]interface{}{ + "join_rule": spec.Restricted, + }, test.WithStateKey("")) + return r + }, + wantResponse: api.QueryRestrictedJoinAllowedResponse{ + Resident: true, + Restricted: true, + }, + }, + { + name: "knock_restricted", + prepareRoomFunc: func(t *testing.T) *test.Room { + r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV8)) + r.CreateAndInsert(t, alice, spec.MRoomJoinRules, map[string]interface{}{ + "join_rule": spec.KnockRestricted, + }, test.WithStateKey("")) + return r + }, + wantResponse: api.QueryRestrictedJoinAllowedResponse{ + Resident: true, + Restricted: true, + }, + }, + { + name: "restricted with pending invite", // bob should be allowed to join + prepareRoomFunc: func(t *testing.T) *test.Room { + r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV8)) + r.CreateAndInsert(t, alice, spec.MRoomJoinRules, map[string]interface{}{ + "join_rule": spec.Restricted, + }, test.WithStateKey("")) + r.CreateAndInsert(t, alice, spec.MRoomMember, map[string]interface{}{ + "membership": spec.Invite, + }, test.WithStateKey(bob.ID)) + return r + }, + wantResponse: api.QueryRestrictedJoinAllowedResponse{ + Resident: true, + Restricted: true, + Allowed: true, + }, + }, + { + name: "restricted with allowed room_id, but missing room", // bob should not be allowed to join, as we don't know about the room + prepareRoomFunc: func(t *testing.T) *test.Room { + r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV10)) + r.CreateAndInsert(t, alice, spec.MRoomJoinRules, map[string]interface{}{ + "join_rule": spec.KnockRestricted, + "allow": []map[string]interface{}{ + { + "room_id": allowedByRoomNotExists.ID, + "type": spec.MRoomMembership, + }, + }, + }, test.WithStateKey("")) + r.CreateAndInsert(t, bob, spec.MRoomMember, map[string]interface{}{ + "membership": spec.Join, + "join_authorised_via_users_server": alice.ID, + }, test.WithStateKey(bob.ID)) + return r + }, + wantResponse: api.QueryRestrictedJoinAllowedResponse{ + Restricted: true, + }, + }, + { + name: "restricted with allowed room_id", // bob should be allowed to join, as we know about the room + prepareRoomFunc: func(t *testing.T) *test.Room { + r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV10)) + r.CreateAndInsert(t, alice, spec.MRoomJoinRules, map[string]interface{}{ + "join_rule": spec.KnockRestricted, + "allow": []map[string]interface{}{ + { + "room_id": allowedByRoomExists.ID, + "type": spec.MRoomMembership, + }, + }, + }, test.WithStateKey("")) + r.CreateAndInsert(t, bob, spec.MRoomMember, map[string]interface{}{ + "membership": spec.Join, + "join_authorised_via_users_server": alice.ID, + }, test.WithStateKey(bob.ID)) + return r + }, + wantResponse: api.QueryRestrictedJoinAllowedResponse{ + Resident: true, + Restricted: true, + Allowed: true, + AuthorisedVia: alice.ID, + }, + }, + } + + test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { + cfg, processCtx, close := testrig.CreateConfig(t, dbType) + natsInstance := jetstream.NATSInstance{} + defer close() + + cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions) + caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics) + + rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics) + rsAPI.SetFederationAPI(nil, nil) + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.prepareRoomFunc == nil { + t.Fatal("missing prepareRoomFunc") + } + testRoom := tc.prepareRoomFunc(t) + // Create the room + if err := api.SendEvents(processCtx.Context(), rsAPI, api.KindNew, testRoom.Events(), "test", "test", "test", nil, false); err != nil { + t.Errorf("failed to send events: %v", err) + } + + if err := api.SendEvents(processCtx.Context(), rsAPI, api.KindNew, allowedByRoomExists.Events(), "test", "test", "test", nil, false); err != nil { + t.Errorf("failed to send events: %v", err) + } + + req := api.QueryRestrictedJoinAllowedRequest{ + UserID: bob.ID, + RoomID: testRoom.ID, + } + res := api.QueryRestrictedJoinAllowedResponse{} + if err := rsAPI.QueryRestrictedJoinAllowed(processCtx.Context(), &req, &res); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(tc.wantResponse, res) { + t.Fatalf("unexpected response, want %#v - got %#v", tc.wantResponse, res) + } + }) + } + }) +} + +func TestUpgrade(t *testing.T) { + alice := test.NewUser(t) + bob := test.NewUser(t) + charlie := test.NewUser(t) + ctx := context.Background() + + spaceChild := test.NewRoom(t, alice) + validateTuples := []gomatrixserverlib.StateKeyTuple{ + {EventType: spec.MRoomCreate}, + {EventType: spec.MRoomPowerLevels}, + {EventType: spec.MRoomJoinRules}, + {EventType: spec.MRoomName}, + {EventType: spec.MRoomCanonicalAlias}, + {EventType: "m.room.tombstone"}, + {EventType: "m.custom.event"}, + {EventType: "m.space.child", StateKey: spaceChild.ID}, + {EventType: "m.custom.event", StateKey: alice.ID}, + {EventType: spec.MRoomMember, StateKey: charlie.ID}, // ban should be transferred + } + + validate := func(t *testing.T, oldRoomID, newRoomID string, rsAPI api.RoomserverInternalAPI) { + + oldRoomState := &api.QueryCurrentStateResponse{} + if err := rsAPI.QueryCurrentState(ctx, &api.QueryCurrentStateRequest{ + RoomID: oldRoomID, + StateTuples: validateTuples, + }, oldRoomState); err != nil { + t.Fatal(err) + } + + newRoomState := &api.QueryCurrentStateResponse{} + if err := rsAPI.QueryCurrentState(ctx, &api.QueryCurrentStateRequest{ + RoomID: newRoomID, + StateTuples: validateTuples, + }, newRoomState); err != nil { + t.Fatal(err) + } + + // the old room should have a tombstone event + ev := oldRoomState.StateEvents[gomatrixserverlib.StateKeyTuple{EventType: "m.room.tombstone"}] + replacementRoom := gjson.GetBytes(ev.Content(), "replacement_room").Str + if replacementRoom != newRoomID { + t.Fatalf("tombstone event has replacement_room '%s', expected '%s'", replacementRoom, newRoomID) + } + + // the new room should have a predecessor equal to the old room + ev = newRoomState.StateEvents[gomatrixserverlib.StateKeyTuple{EventType: spec.MRoomCreate}] + predecessor := gjson.GetBytes(ev.Content(), "predecessor.room_id").Str + if predecessor != oldRoomID { + t.Fatalf("got predecessor room '%s', expected '%s'", predecessor, oldRoomID) + } + + for _, tuple := range validateTuples { + // Skip create and powerlevel event (new room has e.g. predecessor event, old room has restricted powerlevels) + switch tuple.EventType { + case spec.MRoomCreate, spec.MRoomPowerLevels, spec.MRoomCanonicalAlias: + continue + } + oldEv, ok := oldRoomState.StateEvents[tuple] + if !ok { + t.Logf("skipping tuple %#v as it doesn't exist in the old room", tuple) + continue + } + newEv, ok := newRoomState.StateEvents[tuple] + if !ok { + t.Logf("skipping tuple %#v as it doesn't exist in the new room", tuple) + continue + } + + if !reflect.DeepEqual(oldEv.Content(), newEv.Content()) { + t.Logf("OldEvent QueryCurrentState: %s", string(oldEv.Content())) + t.Logf("NewEvent QueryCurrentState: %s", string(newEv.Content())) + t.Errorf("event content mismatch") + } + } + } + + testCases := []struct { + name string + upgradeUser string + roomFunc func(rsAPI api.RoomserverInternalAPI) string + validateFunc func(t *testing.T, oldRoomID, newRoomID string, rsAPI api.RoomserverInternalAPI) + wantNewRoom bool + }{ + { + name: "invalid userID", + upgradeUser: "!notvalid:test", + roomFunc: func(rsAPI api.RoomserverInternalAPI) string { + room := test.NewRoom(t, alice) + if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil { + t.Errorf("failed to send events: %v", err) + } + return room.ID + }, + }, + { + name: "invalid roomID", + upgradeUser: alice.ID, + roomFunc: func(rsAPI api.RoomserverInternalAPI) string { + return "!doesnotexist:test" + }, + }, + { + name: "powerlevel too low", + upgradeUser: bob.ID, + roomFunc: func(rsAPI api.RoomserverInternalAPI) string { + room := test.NewRoom(t, alice) + if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil { + t.Errorf("failed to send events: %v", err) + } + return room.ID + }, + }, + { + name: "successful upgrade on new room", + upgradeUser: alice.ID, + roomFunc: func(rsAPI api.RoomserverInternalAPI) string { + room := test.NewRoom(t, alice) + if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil { + t.Errorf("failed to send events: %v", err) + } + return room.ID + }, + wantNewRoom: true, + validateFunc: validate, + }, + { + name: "successful upgrade on new room with other state events", + upgradeUser: alice.ID, + roomFunc: func(rsAPI api.RoomserverInternalAPI) string { + r := test.NewRoom(t, alice) + r.CreateAndInsert(t, alice, spec.MRoomName, map[string]interface{}{ + "name": "my new name", + }, test.WithStateKey("")) + r.CreateAndInsert(t, alice, spec.MRoomCanonicalAlias, eventutil.CanonicalAliasContent{ + Alias: "#myalias:test", + }, test.WithStateKey("")) + + // this will be transferred + r.CreateAndInsert(t, alice, "m.custom.event", map[string]interface{}{ + "random": "i should exist", + }, test.WithStateKey("")) + + // the following will be ignored + r.CreateAndInsert(t, alice, "m.custom.event", map[string]interface{}{ + "random": "i will be ignored", + }, test.WithStateKey(alice.ID)) + + if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil { + t.Errorf("failed to send events: %v", err) + } + return r.ID + }, + wantNewRoom: true, + validateFunc: validate, + }, + { + name: "with published room", + upgradeUser: alice.ID, + roomFunc: func(rsAPI api.RoomserverInternalAPI) string { + r := test.NewRoom(t, alice) + if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil { + t.Errorf("failed to send events: %v", err) + } + + if err := rsAPI.PerformPublish(ctx, &api.PerformPublishRequest{ + RoomID: r.ID, + Visibility: spec.Public, + }); err != nil { + t.Fatal(err) + } + + return r.ID + }, + wantNewRoom: true, + validateFunc: func(t *testing.T, oldRoomID, newRoomID string, rsAPI api.RoomserverInternalAPI) { + validate(t, oldRoomID, newRoomID, rsAPI) + // check that the new room is published + res := &api.QueryPublishedRoomsResponse{} + if err := rsAPI.QueryPublishedRooms(ctx, &api.QueryPublishedRoomsRequest{RoomID: newRoomID}, res); err != nil { + t.Fatal(err) + } + if len(res.RoomIDs) == 0 { + t.Fatalf("expected room to be published, but wasn't: %#v", res.RoomIDs) + } + }, + }, + { + name: "with alias", + upgradeUser: alice.ID, + roomFunc: func(rsAPI api.RoomserverInternalAPI) string { + r := test.NewRoom(t, alice) + if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil { + t.Errorf("failed to send events: %v", err) + } + + if err := rsAPI.SetRoomAlias(ctx, &api.SetRoomAliasRequest{ + RoomID: r.ID, + Alias: "#myroomalias:test", + }, &api.SetRoomAliasResponse{}); err != nil { + t.Fatal(err) + } + + return r.ID + }, + wantNewRoom: true, + validateFunc: func(t *testing.T, oldRoomID, newRoomID string, rsAPI api.RoomserverInternalAPI) { + validate(t, oldRoomID, newRoomID, rsAPI) + // check that the old room has no aliases + res := &api.GetAliasesForRoomIDResponse{} + if err := rsAPI.GetAliasesForRoomID(ctx, &api.GetAliasesForRoomIDRequest{RoomID: oldRoomID}, res); err != nil { + t.Fatal(err) + } + if len(res.Aliases) != 0 { + t.Fatalf("expected old room aliases to be empty, but wasn't: %#v", res.Aliases) + } + + // check that the new room has aliases + if err := rsAPI.GetAliasesForRoomID(ctx, &api.GetAliasesForRoomIDRequest{RoomID: newRoomID}, res); err != nil { + t.Fatal(err) + } + if len(res.Aliases) == 0 { + t.Fatalf("expected room aliases to be transferred, but wasn't: %#v", res.Aliases) + } + }, + }, + { + name: "bans are transferred", + upgradeUser: alice.ID, + roomFunc: func(rsAPI api.RoomserverInternalAPI) string { + r := test.NewRoom(t, alice) + r.CreateAndInsert(t, alice, spec.MRoomMember, map[string]interface{}{ + "membership": spec.Ban, + }, test.WithStateKey(charlie.ID)) + if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil { + t.Errorf("failed to send events: %v", err) + } + return r.ID + }, + wantNewRoom: true, + validateFunc: validate, + }, + { + name: "space childs are transferred", + upgradeUser: alice.ID, + roomFunc: func(rsAPI api.RoomserverInternalAPI) string { + r := test.NewRoom(t, alice) + + r.CreateAndInsert(t, alice, "m.space.child", map[string]interface{}{}, test.WithStateKey(spaceChild.ID)) + if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil { + t.Errorf("failed to send events: %v", err) + } + return r.ID + }, + wantNewRoom: true, + validateFunc: validate, + }, + { + name: "custom state is not taken to the new room", // https://github.com/matrix-org/dendrite/issues/2912 + upgradeUser: charlie.ID, + roomFunc: func(rsAPI api.RoomserverInternalAPI) string { + r := test.NewRoom(t, alice, test.RoomVersion(gomatrixserverlib.RoomVersionV6)) + // Bob and Charlie join + r.CreateAndInsert(t, bob, spec.MRoomMember, map[string]interface{}{"membership": spec.Join}, test.WithStateKey(bob.ID)) + r.CreateAndInsert(t, charlie, spec.MRoomMember, map[string]interface{}{"membership": spec.Join}, test.WithStateKey(charlie.ID)) + + // make Charlie an admin so the room can be upgraded + r.CreateAndInsert(t, alice, spec.MRoomPowerLevels, gomatrixserverlib.PowerLevelContent{ + Users: map[string]int64{ + charlie.ID: 100, + }, + }, test.WithStateKey("")) + + // Alice creates a custom event + r.CreateAndInsert(t, alice, "m.custom.event", map[string]interface{}{ + "random": "data", + }, test.WithStateKey(alice.ID)) + r.CreateAndInsert(t, alice, spec.MRoomMember, map[string]interface{}{"membership": spec.Leave}, test.WithStateKey(alice.ID)) + + if err := api.SendEvents(ctx, rsAPI, api.KindNew, r.Events(), "test", "test", "test", nil, false); err != nil { + t.Errorf("failed to send events: %v", err) + } + return r.ID + }, + wantNewRoom: true, + validateFunc: validate, + }, + } + + test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { + cfg, processCtx, close := testrig.CreateConfig(t, dbType) + natsInstance := jetstream.NATSInstance{} + defer close() + + cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions) + caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics) + + rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics) + userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil) + rsAPI.SetFederationAPI(nil, nil) + rsAPI.SetUserAPI(userAPI) + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.roomFunc == nil { + t.Fatalf("missing roomFunc") + } + if tc.upgradeUser == "" { + tc.upgradeUser = alice.ID + } + roomID := tc.roomFunc(rsAPI) + + newRoomID, err := rsAPI.PerformRoomUpgrade(processCtx.Context(), roomID, tc.upgradeUser, version.DefaultRoomVersion()) + if err != nil && tc.wantNewRoom { + t.Fatal(err) + } + + if tc.wantNewRoom && newRoomID == "" { + t.Fatalf("expected a new room, but the upgrade failed") + } + if !tc.wantNewRoom && newRoomID != "" { + t.Fatalf("expected no new room, but the upgrade succeeded") + } + if tc.validateFunc != nil { + tc.validateFunc(t, roomID, newRoomID, rsAPI) + } + }) + } + }) +} diff --git a/roomserver/state/state.go b/roomserver/state/state.go index d20877b48..d04b8f6c1 100644 --- a/roomserver/state/state.go +++ b/roomserver/state/state.go @@ -996,7 +996,7 @@ func (v *StateResolution) resolveConflictsV2( // For each conflicted event, we will add a new set of auth events. Auth // events may be duplicated across these sets but that's OK. authSets := make(map[string][]*gomatrixserverlib.Event, len(conflicted)) - authEvents := make([]*gomatrixserverlib.Event, 0, estimate*3) + authEvents := make([]gomatrixserverlib.PDU, 0, estimate*3) gotAuthEvents := make(map[string]struct{}, estimate*3) knownAuthEvents := make(map[string]types.Event, estimate*3) @@ -1046,7 +1046,7 @@ func (v *StateResolution) resolveConflictsV2( gotAuthEvents = nil // nolint:ineffassign // Resolve the conflicts. - resolvedEvents := func() []*gomatrixserverlib.Event { + resolvedEvents := func() []gomatrixserverlib.PDU { resolvedTrace, _ := internal.StartRegion(ctx, "StateResolution.ResolveStateConflictsV2") defer resolvedTrace.EndRegion() @@ -1119,11 +1119,11 @@ func (v *StateResolution) stateKeyTuplesNeeded(stateKeyNIDMap map[string]types.E // Returns an error if there was a problem talking to the database. func (v *StateResolution) loadStateEvents( ctx context.Context, entries []types.StateEntry, -) ([]*gomatrixserverlib.Event, map[string]types.StateEntry, error) { +) ([]gomatrixserverlib.PDU, map[string]types.StateEntry, error) { trace, ctx := internal.StartRegion(ctx, "StateResolution.loadStateEvents") defer trace.EndRegion() - result := make([]*gomatrixserverlib.Event, 0, len(entries)) + result := make([]gomatrixserverlib.PDU, 0, len(entries)) eventEntries := make([]types.StateEntry, 0, len(entries)) eventNIDs := make(types.EventNIDs, 0, len(entries)) for _, entry := range entries { @@ -1163,7 +1163,7 @@ type authEventLoader struct { // loadAuthEvents loads all of the auth events for a given event recursively, // along with a map that contains state entries for all of the auth events. func (l *authEventLoader) loadAuthEvents( - ctx context.Context, roomInfo *types.RoomInfo, event *gomatrixserverlib.Event, eventMap map[string]types.Event, + ctx context.Context, roomInfo *types.RoomInfo, event gomatrixserverlib.PDU, eventMap map[string]types.Event, ) ([]*gomatrixserverlib.Event, map[string]types.StateEntry, error) { l.Lock() defer l.Unlock() diff --git a/roomserver/storage/interface.go b/roomserver/storage/interface.go index b80184f9a..a2364e2e8 100644 --- a/roomserver/storage/interface.go +++ b/roomserver/storage/interface.go @@ -77,7 +77,7 @@ type Database interface { SnapshotNIDFromEventID(ctx context.Context, eventID string) (types.StateSnapshotNID, error) BulkSelectSnapshotsFromEventIDs(ctx context.Context, eventIDs []string) (map[types.StateSnapshotNID][]string, error) // Stores a matrix room event in the database. Returns the room NID, the state snapshot or an error. - StoreEvent(ctx context.Context, event *gomatrixserverlib.Event, roomInfo *types.RoomInfo, eventTypeNID types.EventTypeNID, eventStateKeyNID types.EventStateKeyNID, authEventNIDs []types.EventNID, isRejected bool) (types.EventNID, types.StateAtEvent, error) + StoreEvent(ctx context.Context, event gomatrixserverlib.PDU, roomInfo *types.RoomInfo, eventTypeNID types.EventTypeNID, eventStateKeyNID types.EventStateKeyNID, authEventNIDs []types.EventNID, isRejected bool) (types.EventNID, types.StateAtEvent, error) // Look up the state entries for a list of string event IDs // Returns an error if the there is an error talking to the database // Returns a types.MissingEventError if the event IDs aren't in the database. @@ -139,7 +139,7 @@ type Database interface { // not found. // Returns an error if the retrieval went wrong. EventsFromIDs(ctx context.Context, roomInfo *types.RoomInfo, eventIDs []string) ([]types.Event, error) - // Publish or unpublish a room from the room directory. + // PerformPublish publishes or unpublishes a room from the room directory. Returns a database error, if any. PublishRoom(ctx context.Context, roomID, appserviceID, networkID string, publish bool) error // Returns a list of room IDs for rooms which are published. GetPublishedRooms(ctx context.Context, networkID string, includeAllNetworks bool) ([]string, error) @@ -151,8 +151,8 @@ type Database interface { // GetStateEvent returns the state event of a given type for a given room with a given state key // If no event could be found, returns nil // If there was an issue during the retrieval, returns an error - GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*gomatrixserverlib.HeaderedEvent, error) - GetStateEventsWithEventType(ctx context.Context, roomID, evType string) ([]*gomatrixserverlib.HeaderedEvent, error) + GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*types.HeaderedEvent, error) + GetStateEventsWithEventType(ctx context.Context, roomID, evType string) ([]*types.HeaderedEvent, error) // GetRoomsByMembership returns a list of room IDs matching the provided membership and user ID (as state_key). GetRoomsByMembership(ctx context.Context, userID, membership string) ([]string, error) // GetBulkStateContent returns all state events which match a given room ID and a given state key tuple. Both must be satisfied for a match. @@ -181,8 +181,8 @@ type Database interface { // a membership of "leave" when calculating history visibility. GetMembershipForHistoryVisibility( ctx context.Context, userNID types.EventStateKeyNID, info *types.RoomInfo, eventIDs ...string, - ) (map[string]*gomatrixserverlib.HeaderedEvent, error) - GetOrCreateRoomInfo(ctx context.Context, event *gomatrixserverlib.Event) (*types.RoomInfo, error) + ) (map[string]*types.HeaderedEvent, error) + GetOrCreateRoomInfo(ctx context.Context, event gomatrixserverlib.PDU) (*types.RoomInfo, error) GetOrCreateEventTypeNID(ctx context.Context, eventType string) (eventTypeNID types.EventTypeNID, err error) GetOrCreateEventStateKeyNID(ctx context.Context, eventStateKey *string) (types.EventStateKeyNID, error) MaybeRedactEvent( @@ -207,10 +207,10 @@ type RoomDatabase interface { StateEntriesForTuples(ctx context.Context, stateBlockNIDs []types.StateBlockNID, stateKeyTuples []types.StateKeyTuple) ([]types.StateEntryList, error) AddState(ctx context.Context, roomNID types.RoomNID, stateBlockNIDs []types.StateBlockNID, state []types.StateEntry) (types.StateSnapshotNID, error) LatestEventIDs(ctx context.Context, roomNID types.RoomNID) ([]gomatrixserverlib.EventReference, types.StateSnapshotNID, int64, error) - GetOrCreateRoomInfo(ctx context.Context, event *gomatrixserverlib.Event) (*types.RoomInfo, error) + GetOrCreateRoomInfo(ctx context.Context, event gomatrixserverlib.PDU) (*types.RoomInfo, error) GetOrCreateEventTypeNID(ctx context.Context, eventType string) (eventTypeNID types.EventTypeNID, err error) GetOrCreateEventStateKeyNID(ctx context.Context, eventStateKey *string) (types.EventStateKeyNID, error) - GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*gomatrixserverlib.HeaderedEvent, error) + GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*types.HeaderedEvent, error) } type EventDatabase interface { @@ -230,5 +230,5 @@ type EventDatabase interface { MaybeRedactEvent( ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event *gomatrixserverlib.Event, plResolver state.PowerLevelResolver, ) (*gomatrixserverlib.Event, *gomatrixserverlib.Event, error) - StoreEvent(ctx context.Context, event *gomatrixserverlib.Event, roomInfo *types.RoomInfo, eventTypeNID types.EventTypeNID, eventStateKeyNID types.EventStateKeyNID, authEventNIDs []types.EventNID, isRejected bool) (types.EventNID, types.StateAtEvent, error) + StoreEvent(ctx context.Context, event gomatrixserverlib.PDU, roomInfo *types.RoomInfo, eventTypeNID types.EventTypeNID, eventStateKeyNID types.EventStateKeyNID, authEventNIDs []types.EventNID, isRejected bool) (types.EventNID, types.StateAtEvent, error) } diff --git a/roomserver/storage/postgres/state_snapshot_table.go b/roomserver/storage/postgres/state_snapshot_table.go index db6644154..25e1303eb 100644 --- a/roomserver/storage/postgres/state_snapshot_table.go +++ b/roomserver/storage/postgres/state_snapshot_table.go @@ -205,19 +205,19 @@ func (s *stateSnapshotStatements) BulkSelectStateForHistoryVisibility( func (s *stateSnapshotStatements) BulkSelectMembershipForHistoryVisibility( ctx context.Context, txn *sql.Tx, userNID types.EventStateKeyNID, roomInfo *types.RoomInfo, eventIDs ...string, -) (map[string]*gomatrixserverlib.HeaderedEvent, error) { +) (map[string]*types.HeaderedEvent, error) { stmt := sqlutil.TxStmt(txn, s.bulktSelectMembershipForHistoryVisibilityStmt) rows, err := stmt.QueryContext(ctx, userNID, pq.Array(eventIDs), roomInfo.RoomNID) if err != nil { return nil, err } defer rows.Close() // nolint: errcheck - result := make(map[string]*gomatrixserverlib.HeaderedEvent, len(eventIDs)) + result := make(map[string]*types.HeaderedEvent, len(eventIDs)) var evJson []byte var eventID string var membershipEventID string - knownEvents := make(map[string]*gomatrixserverlib.HeaderedEvent, len(eventIDs)) + knownEvents := make(map[string]*types.HeaderedEvent, len(eventIDs)) verImpl, err := gomatrixserverlib.GetRoomVersion(roomInfo.RoomVersion) if err != nil { return nil, err @@ -228,7 +228,7 @@ func (s *stateSnapshotStatements) BulkSelectMembershipForHistoryVisibility( return nil, err } if len(evJson) == 0 { - result[eventID] = &gomatrixserverlib.HeaderedEvent{} + result[eventID] = &types.HeaderedEvent{} continue } // If we already know this event, don't try to marshal the json again @@ -238,11 +238,11 @@ func (s *stateSnapshotStatements) BulkSelectMembershipForHistoryVisibility( } event, err := verImpl.NewEventFromTrustedJSON(evJson, false) if err != nil { - result[eventID] = &gomatrixserverlib.HeaderedEvent{} + result[eventID] = &types.HeaderedEvent{} // not fatal continue } - he := event.Headered(roomInfo.RoomVersion) + he := &types.HeaderedEvent{Event: event} result[eventID] = he knownEvents[membershipEventID] = he } diff --git a/roomserver/storage/shared/storage.go b/roomserver/storage/shared/storage.go index 8db116440..c31302cf9 100644 --- a/roomserver/storage/shared/storage.go +++ b/roomserver/storage/shared/storage.go @@ -63,7 +63,7 @@ func (d *Database) SupportsConcurrentRoomInputs() bool { func (d *Database) GetMembershipForHistoryVisibility( ctx context.Context, userNID types.EventStateKeyNID, roomInfo *types.RoomInfo, eventIDs ...string, -) (map[string]*gomatrixserverlib.HeaderedEvent, error) { +) (map[string]*types.HeaderedEvent, error) { return d.StateSnapshotTable.BulkSelectMembershipForHistoryVisibility(ctx, nil, userNID, roomInfo, eventIDs...) } @@ -658,7 +658,7 @@ func (d *Database) IsEventRejected(ctx context.Context, roomNID types.RoomNID, e } // GetOrCreateRoomInfo gets or creates a new RoomInfo, which is only safe to use with functions only needing a roomVersion or roomNID. -func (d *Database) GetOrCreateRoomInfo(ctx context.Context, event *gomatrixserverlib.Event) (roomInfo *types.RoomInfo, err error) { +func (d *Database) GetOrCreateRoomInfo(ctx context.Context, event gomatrixserverlib.PDU) (roomInfo *types.RoomInfo, err error) { // Get the default room version. If the client doesn't supply a room_version // then we will use our configured default to create the room. // https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-createroom @@ -669,13 +669,17 @@ func (d *Database) GetOrCreateRoomInfo(ctx context.Context, event *gomatrixserve if roomVersion, err = extractRoomVersionFromCreateEvent(event); err != nil { return nil, fmt.Errorf("extractRoomVersionFromCreateEvent: %w", err) } - if roomVersion == "" { - rv, ok := d.Cache.GetRoomVersion(event.RoomID()) - if ok { - roomVersion = rv - } + + roomNID, nidOK := d.Cache.GetRoomServerRoomNID(event.RoomID()) + cachedRoomVersion, versionOK := d.Cache.GetRoomVersion(event.RoomID()) + // if we found both, the roomNID and version in our cache, no need to query the database + if nidOK && versionOK { + return &types.RoomInfo{ + RoomNID: roomNID, + RoomVersion: cachedRoomVersion, + }, nil } - var roomNID types.RoomNID + err = d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error { roomNID, err = d.assignRoomNID(ctx, txn, event.RoomID(), roomVersion) if err != nil { @@ -721,7 +725,7 @@ func (d *Database) GetOrCreateEventStateKeyNID(ctx context.Context, eventStateKe } func (d *EventDatabase) StoreEvent( - ctx context.Context, event *gomatrixserverlib.Event, + ctx context.Context, event gomatrixserverlib.PDU, roomInfo *types.RoomInfo, eventTypeNID types.EventTypeNID, eventStateKeyNID types.EventStateKeyNID, authEventNIDs []types.EventNID, isRejected bool, ) (types.EventNID, types.StateAtEvent, error) { @@ -905,7 +909,7 @@ func (d *EventDatabase) assignStateKeyNID( return eventStateKeyNID, err } -func extractRoomVersionFromCreateEvent(event *gomatrixserverlib.Event) ( +func extractRoomVersionFromCreateEvent(event gomatrixserverlib.PDU) ( gomatrixserverlib.RoomVersion, error, ) { var err error @@ -1152,7 +1156,7 @@ func (d *Database) GetHistoryVisibilityState(ctx context.Context, roomInfo *type // GetStateEvent returns the current state event of a given type for a given room with a given state key // If no event could be found, returns nil // If there was an issue during the retrieval, returns an error -func (d *Database) GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*gomatrixserverlib.HeaderedEvent, error) { +func (d *Database) GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*types.HeaderedEvent, error) { roomInfo, err := d.roomInfo(ctx, nil, roomID) if err != nil { return nil, err @@ -1164,7 +1168,7 @@ func (d *Database) GetStateEvent(ctx context.Context, roomID, evType, stateKey s if roomInfo.IsStub() { return nil, nil } - eventTypeNID, err := d.EventTypesTable.SelectEventTypeNID(ctx, nil, evType) + eventTypeNID, err := d.GetOrCreateEventTypeNID(ctx, evType) if err == sql.ErrNoRows { // No rooms have an event of this type, otherwise we'd have an event type NID return nil, nil @@ -1172,7 +1176,7 @@ func (d *Database) GetStateEvent(ctx context.Context, roomID, evType, stateKey s if err != nil { return nil, err } - stateKeyNID, err := d.EventStateKeysTable.SelectEventStateKeyNID(ctx, nil, stateKey) + stateKeyNID, err := d.GetOrCreateEventStateKeyNID(ctx, &stateKey) if err == sql.ErrNoRows { // No rooms have a state event with this state key, otherwise we'd have an state key NID return nil, nil @@ -1201,6 +1205,10 @@ func (d *Database) GetStateEvent(ctx context.Context, roomID, evType, stateKey s // return the event requested for _, e := range entries { if e.EventTypeNID == eventTypeNID && e.EventStateKeyNID == stateKeyNID { + cachedEvent, ok := d.Cache.GetRoomServerEvent(e.EventNID) + if ok { + return &types.HeaderedEvent{Event: cachedEvent}, nil + } data, err := d.EventJSONTable.BulkSelectEventJSON(ctx, nil, []types.EventNID{e.EventNID}) if err != nil { return nil, err @@ -1212,7 +1220,7 @@ func (d *Database) GetStateEvent(ctx context.Context, roomID, evType, stateKey s if err != nil { return nil, err } - return ev.Headered(roomInfo.RoomVersion), nil + return &types.HeaderedEvent{Event: ev}, nil } } @@ -1221,7 +1229,7 @@ func (d *Database) GetStateEvent(ctx context.Context, roomID, evType, stateKey s // Same as GetStateEvent but returns all matching state events with this event type. Returns no error // if there are no events with this event type. -func (d *Database) GetStateEventsWithEventType(ctx context.Context, roomID, evType string) ([]*gomatrixserverlib.HeaderedEvent, error) { +func (d *Database) GetStateEventsWithEventType(ctx context.Context, roomID, evType string) ([]*types.HeaderedEvent, error) { roomInfo, err := d.roomInfo(ctx, nil, roomID) if err != nil { return nil, err @@ -1267,13 +1275,13 @@ func (d *Database) GetStateEventsWithEventType(ctx context.Context, roomID, evTy if err != nil { return nil, err } - var result []*gomatrixserverlib.HeaderedEvent + var result []*types.HeaderedEvent for _, pair := range eventPairs { ev, err := verImpl.NewEventFromTrustedJSONWithEventID(eventIDs[pair.EventNID], pair.EventJSON, false) if err != nil { return nil, err } - result = append(result, ev.Headered(roomInfo.RoomVersion)) + result = append(result, &types.HeaderedEvent{Event: ev}) } return result, nil @@ -1324,7 +1332,7 @@ func (d *Database) GetBulkStateContent(ctx context.Context, roomIDs []string, tu } // we don't bother failing the request if we get asked for event types we don't know about, as all that would result in is no matches which // isn't a failure. - eventTypeNIDMap, err := d.EventTypesTable.BulkSelectEventTypeNID(ctx, nil, eventTypes) + eventTypeNIDMap, err := d.eventTypeNIDs(ctx, nil, eventTypes) if err != nil { return nil, fmt.Errorf("GetBulkStateContent: failed to map event type nids: %w", err) } @@ -1401,7 +1409,7 @@ func (d *Database) GetBulkStateContent(ctx context.Context, roomIDs []string, tu EventType: ev.Type(), RoomID: ev.RoomID(), StateKey: *ev.StateKey(), - ContentValue: tables.ExtractContentValue(ev.Headered(roomVer)), + ContentValue: tables.ExtractContentValue(&types.HeaderedEvent{Event: ev}), } } diff --git a/roomserver/storage/sqlite3/state_snapshot_table.go b/roomserver/storage/sqlite3/state_snapshot_table.go index e57e1a4bf..2edff0ba8 100644 --- a/roomserver/storage/sqlite3/state_snapshot_table.go +++ b/roomserver/storage/sqlite3/state_snapshot_table.go @@ -26,7 +26,6 @@ import ( "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/roomserver/storage/tables" "github.com/matrix-org/dendrite/roomserver/types" - "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" ) @@ -153,7 +152,7 @@ func (s *stateSnapshotStatements) BulkSelectStateForHistoryVisibility( return nil, tables.OptimisationNotSupportedError } -func (s *stateSnapshotStatements) BulkSelectMembershipForHistoryVisibility(ctx context.Context, txn *sql.Tx, userNID types.EventStateKeyNID, roomInfo *types.RoomInfo, eventIDs ...string) (map[string]*gomatrixserverlib.HeaderedEvent, error) { +func (s *stateSnapshotStatements) BulkSelectMembershipForHistoryVisibility(ctx context.Context, txn *sql.Tx, userNID types.EventStateKeyNID, roomInfo *types.RoomInfo, eventIDs ...string) (map[string]*types.HeaderedEvent, error) { return nil, tables.OptimisationNotSupportedError } diff --git a/roomserver/storage/tables/interface.go b/roomserver/storage/tables/interface.go index 45dc0fc29..a9c5f8b11 100644 --- a/roomserver/storage/tables/interface.go +++ b/roomserver/storage/tables/interface.go @@ -95,7 +95,7 @@ type StateSnapshot interface { BulkSelectMembershipForHistoryVisibility( ctx context.Context, txn *sql.Tx, userNID types.EventStateKeyNID, roomInfo *types.RoomInfo, eventIDs ...string, - ) (map[string]*gomatrixserverlib.HeaderedEvent, error) + ) (map[string]*types.HeaderedEvent, error) } type StateBlock interface { @@ -196,7 +196,7 @@ type StrippedEvent struct { // ExtractContentValue from the given state event. For example, given an m.room.name event with: // content: { name: "Foo" } // this returns "Foo". -func ExtractContentValue(ev *gomatrixserverlib.HeaderedEvent) string { +func ExtractContentValue(ev *types.HeaderedEvent) string { content := ev.Content() key := "" switch ev.Type() { diff --git a/roomserver/types/headered_event.go b/roomserver/types/headered_event.go new file mode 100644 index 000000000..f160872ff --- /dev/null +++ b/roomserver/types/headered_event.go @@ -0,0 +1,47 @@ +// Copyright 2023 The Matrix.org Foundation C.I.C. +// +// 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 types + +import ( + "github.com/matrix-org/gomatrixserverlib" +) + +// HeaderedEvent is an Event which serialises to the headered form, which includes +// _room_version and _event_id fields. +type HeaderedEvent struct { + *gomatrixserverlib.Event + Visibility gomatrixserverlib.HistoryVisibility +} + +func (h *HeaderedEvent) MarshalJSON() ([]byte, error) { + return h.Event.ToHeaderedJSON() +} + +func (j *HeaderedEvent) UnmarshalJSON(data []byte) error { + ev, err := gomatrixserverlib.NewEventFromHeaderedJSON(data, false) + if err != nil { + return err + } + j.Event = ev + return nil +} + +func NewEventJSONsFromHeaderedEvents(hes []*HeaderedEvent) gomatrixserverlib.EventJSONs { + result := make(gomatrixserverlib.EventJSONs, len(hes)) + for i := range hes { + result[i] = hes[i].JSON() + } + return result +} diff --git a/setup/mscs/msc2836/msc2836.go b/setup/mscs/msc2836/msc2836.go index 8982e6e37..877a4a60b 100644 --- a/setup/mscs/msc2836/msc2836.go +++ b/setup/mscs/msc2836/msc2836.go @@ -33,6 +33,7 @@ import ( "github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/sqlutil" roomserver "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/syncapi/synctypes" userapi "github.com/matrix-org/dendrite/userapi/api" @@ -94,7 +95,7 @@ type MSC2836EventRelationshipsResponse struct { func toClientResponse(res *MSC2836EventRelationshipsResponse) *EventRelationshipResponse { out := &EventRelationshipResponse{ - Events: synctypes.ToClientEvents(res.ParsedEvents, synctypes.FormatAll), + Events: synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(res.ParsedEvents), synctypes.FormatAll), Limited: res.Limited, NextBatch: res.NextBatch, } @@ -112,7 +113,7 @@ func Enable( } hooks.Enable() hooks.Attach(hooks.KindNewEventPersisted, func(headeredEvent interface{}) { - he := headeredEvent.(*gomatrixserverlib.HeaderedEvent) + he := headeredEvent.(*types.HeaderedEvent) hookErr := db.StoreRelation(context.Background(), he) if hookErr != nil { util.GetLogger(context.Background()).WithError(hookErr).WithField("event_id", he.EventID()).Error( @@ -255,7 +256,7 @@ func federatedEventRelationship( func (rc *reqCtx) process() (*MSC2836EventRelationshipsResponse, *util.JSONResponse) { var res MSC2836EventRelationshipsResponse - var returnEvents []*gomatrixserverlib.HeaderedEvent + var returnEvents []*types.HeaderedEvent // Can the user see (according to history visibility) event_id? If no, reject the request, else continue. event := rc.getLocalEvent(rc.req.RoomID, rc.req.EventID) if event == nil { @@ -299,7 +300,7 @@ func (rc *reqCtx) process() (*MSC2836EventRelationshipsResponse, *util.JSONRespo for _, ev := range returnEvents { included[ev.EventID()] = true } - var events []*gomatrixserverlib.HeaderedEvent + var events []*types.HeaderedEvent events, walkLimited = walkThread( rc.ctx, rc.db, rc, included, remaining, ) @@ -309,7 +310,7 @@ func (rc *reqCtx) process() (*MSC2836EventRelationshipsResponse, *util.JSONRespo for i, ev := range returnEvents { // for each event, extract the children_count | hash and add it as unsigned data. rc.addChildMetadata(ev) - res.ParsedEvents[i] = ev.Unwrap() + res.ParsedEvents[i] = ev.Event } res.Limited = remaining == 0 || walkLimited return &res, nil @@ -318,17 +319,15 @@ func (rc *reqCtx) process() (*MSC2836EventRelationshipsResponse, *util.JSONRespo // fetchUnknownEvent retrieves an unknown event from the room specified. This server must // be joined to the room in question. This has the side effect of injecting surround threaded // events into the roomserver. -func (rc *reqCtx) fetchUnknownEvent(eventID, roomID string) *gomatrixserverlib.HeaderedEvent { +func (rc *reqCtx) fetchUnknownEvent(eventID, roomID string) *types.HeaderedEvent { if rc.isFederatedRequest || roomID == "" { // we don't do fed hits for fed requests, and we can't ask servers without a room ID! return nil } logger := util.GetLogger(rc.ctx).WithField("room_id", roomID) // if they supplied a room_id, check the room exists. - var queryVerRes roomserver.QueryRoomVersionForRoomResponse - err := rc.rsAPI.QueryRoomVersionForRoom(rc.ctx, &roomserver.QueryRoomVersionForRoomRequest{ - RoomID: roomID, - }, &queryVerRes) + + roomVersion, err := rc.rsAPI.QueryRoomVersionForRoom(rc.ctx, roomID) if err != nil { logger.WithError(err).Warn("failed to query room version for room, does this room exist?") return nil @@ -367,14 +366,14 @@ func (rc *reqCtx) fetchUnknownEvent(eventID, roomID string) *gomatrixserverlib.H // Inject the response into the roomserver to remember the event across multiple calls and to set // unexplored flags correctly. for _, srv := range serversToQuery { - res, err := rc.MSC2836EventRelationships(eventID, srv, queryVerRes.RoomVersion) + res, err := rc.MSC2836EventRelationships(eventID, srv, roomVersion) if err != nil { continue } rc.injectResponseToRoomserver(res) for _, ev := range res.ParsedEvents { if ev.EventID() == eventID { - return ev.Headered(ev.Version()) + return &types.HeaderedEvent{Event: ev} } } } @@ -384,7 +383,7 @@ func (rc *reqCtx) fetchUnknownEvent(eventID, roomID string) *gomatrixserverlib.H // If include_parent: true and there is a valid m.relationship field in the event, // retrieve the referenced event. Apply history visibility check to that event and if it passes, add it to the response array. -func (rc *reqCtx) includeParent(childEvent *gomatrixserverlib.HeaderedEvent) (parent *gomatrixserverlib.HeaderedEvent) { +func (rc *reqCtx) includeParent(childEvent *types.HeaderedEvent) (parent *types.HeaderedEvent) { parentID, _, _ := parentChildEventIDs(childEvent) if parentID == "" { return nil @@ -395,7 +394,7 @@ func (rc *reqCtx) includeParent(childEvent *gomatrixserverlib.HeaderedEvent) (pa // If include_children: true, lookup all events which have event_id as an m.relationship // Apply history visibility checks to all these events and add the ones which pass into the response array, // honouring the recent_first flag and the limit. -func (rc *reqCtx) includeChildren(db Database, parentID string, limit int, recentFirst bool) ([]*gomatrixserverlib.HeaderedEvent, *util.JSONResponse) { +func (rc *reqCtx) includeChildren(db Database, parentID string, limit int, recentFirst bool) ([]*types.HeaderedEvent, *util.JSONResponse) { if rc.hasUnexploredChildren(parentID) { // we need to do a remote request to pull in the children as we are missing them locally. serversToQuery := rc.getServersForEventID(parentID) @@ -432,7 +431,7 @@ func (rc *reqCtx) includeChildren(db Database, parentID string, limit int, recen resErr := jsonerror.InternalServerError() return nil, &resErr } - var childEvents []*gomatrixserverlib.HeaderedEvent + var childEvents []*types.HeaderedEvent for _, child := range children { childEvent := rc.lookForEvent(child.EventID) if childEvent != nil { @@ -449,8 +448,8 @@ func (rc *reqCtx) includeChildren(db Database, parentID string, limit int, recen // honouring the limit, max_depth and max_breadth values according to the following rules func walkThread( ctx context.Context, db Database, rc *reqCtx, included map[string]bool, limit int, -) ([]*gomatrixserverlib.HeaderedEvent, bool) { - var result []*gomatrixserverlib.HeaderedEvent +) ([]*types.HeaderedEvent, bool) { + var result []*types.HeaderedEvent eventWalker := walker{ ctx: ctx, req: rc.req, @@ -512,7 +511,7 @@ func (rc *reqCtx) MSC2836EventRelationships(eventID string, srv spec.ServerName, // authorisedToSeeEvent checks that the user or server is allowed to see this event. Returns true if allowed to // see this request. This only needs to be done once per room at present as we just check for joined status. -func (rc *reqCtx) authorisedToSeeEvent(event *gomatrixserverlib.HeaderedEvent) bool { +func (rc *reqCtx) authorisedToSeeEvent(event *types.HeaderedEvent) bool { if rc.isFederatedRequest { // make sure the server is in this room var res fs.QueryJoinedHostServerNamesInRoomResponse @@ -595,7 +594,7 @@ func (rc *reqCtx) remoteEventRelationships(eventID string) *MSC2836EventRelation // lookForEvent returns the event for the event ID given, by trying to query remote servers // if the event ID is unknown via /event_relationships. -func (rc *reqCtx) lookForEvent(eventID string) *gomatrixserverlib.HeaderedEvent { +func (rc *reqCtx) lookForEvent(eventID string) *types.HeaderedEvent { event := rc.getLocalEvent(rc.req.RoomID, eventID) if event == nil { queryRes := rc.remoteEventRelationships(eventID) @@ -604,7 +603,7 @@ func (rc *reqCtx) lookForEvent(eventID string) *gomatrixserverlib.HeaderedEvent rc.injectResponseToRoomserver(queryRes) for _, ev := range queryRes.ParsedEvents { if ev.EventID() == eventID && rc.req.RoomID == ev.RoomID() { - return ev.Headered(ev.Version()) + return &types.HeaderedEvent{Event: ev} } } } @@ -626,7 +625,7 @@ func (rc *reqCtx) lookForEvent(eventID string) *gomatrixserverlib.HeaderedEvent return nil } -func (rc *reqCtx) getLocalEvent(roomID, eventID string) *gomatrixserverlib.HeaderedEvent { +func (rc *reqCtx) getLocalEvent(roomID, eventID string) *types.HeaderedEvent { var queryEventsRes roomserver.QueryEventsByIDResponse err := rc.rsAPI.QueryEventsByID(rc.ctx, &roomserver.QueryEventsByIDRequest{ RoomID: roomID, @@ -647,7 +646,7 @@ func (rc *reqCtx) getLocalEvent(roomID, eventID string) *gomatrixserverlib.Heade // into the roomserver as KindOutlier, with auth chains. func (rc *reqCtx) injectResponseToRoomserver(res *MSC2836EventRelationshipsResponse) { var stateEvents gomatrixserverlib.EventJSONs - var messageEvents []*gomatrixserverlib.Event + var messageEvents []gomatrixserverlib.PDU for _, ev := range res.ParsedEvents { if ev.StateKey() != nil { stateEvents = append(stateEvents, ev.JSON()) @@ -666,7 +665,7 @@ func (rc *reqCtx) injectResponseToRoomserver(res *MSC2836EventRelationshipsRespo for _, outlier := range append(eventsInOrder, messageEvents...) { ires = append(ires, roomserver.InputRoomEvent{ Kind: roomserver.KindOutlier, - Event: outlier.Headered(outlier.Version()), + Event: &types.HeaderedEvent{Event: outlier.(*gomatrixserverlib.Event)}, }) } // we've got the data by this point so use a background context @@ -685,7 +684,7 @@ func (rc *reqCtx) injectResponseToRoomserver(res *MSC2836EventRelationshipsRespo } } -func (rc *reqCtx) addChildMetadata(ev *gomatrixserverlib.HeaderedEvent) { +func (rc *reqCtx) addChildMetadata(ev *types.HeaderedEvent) { count, hash := rc.getChildMetadata(ev.EventID()) if count == 0 { return diff --git a/setup/mscs/msc2836/msc2836_test.go b/setup/mscs/msc2836/msc2836_test.go index a06b7211f..78aff310c 100644 --- a/setup/mscs/msc2836/msc2836_test.go +++ b/setup/mscs/msc2836/msc2836_test.go @@ -24,6 +24,7 @@ import ( "github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/sqlutil" roomserver "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/mscs/msc2836" userapi "github.com/matrix-org/dendrite/userapi/api" @@ -171,7 +172,7 @@ func TestMSC2836(t *testing.T) { bob: {roomID}, charlie: {roomID}, }, - events: map[string]*gomatrixserverlib.HeaderedEvent{ + events: map[string]*types.HeaderedEvent{ eventA.EventID(): eventA, eventB.EventID(): eventB, eventC.EventID(): eventC, @@ -182,7 +183,7 @@ func TestMSC2836(t *testing.T) { eventH.EventID(): eventH, }, } - router := injectEvents(t, nopUserAPI, nopRsAPI, []*gomatrixserverlib.HeaderedEvent{ + router := injectEvents(t, nopUserAPI, nopRsAPI, []*types.HeaderedEvent{ eventA, eventB, eventC, eventD, eventE, eventF, eventG, eventH, }) cancel := runServer(t, router) @@ -521,7 +522,7 @@ type testRoomserverAPI struct { // We'll override the functions we care about. roomserver.RoomserverInternalAPI userToJoinedRooms map[string][]string - events map[string]*gomatrixserverlib.HeaderedEvent + events map[string]*types.HeaderedEvent } func (r *testRoomserverAPI) QueryEventsByID(ctx context.Context, req *roomserver.QueryEventsByIDRequest, res *roomserver.QueryEventsByIDResponse) error { @@ -547,7 +548,7 @@ func (r *testRoomserverAPI) QueryMembershipForUser(ctx context.Context, req *roo return nil } -func injectEvents(t *testing.T, userAPI userapi.UserInternalAPI, rsAPI roomserver.RoomserverInternalAPI, events []*gomatrixserverlib.HeaderedEvent) *mux.Router { +func injectEvents(t *testing.T, userAPI userapi.UserInternalAPI, rsAPI roomserver.RoomserverInternalAPI, events []*types.HeaderedEvent) *mux.Router { t.Helper() cfg := &config.Dendrite{} cfg.Defaults(config.DefaultOpts{ @@ -579,7 +580,7 @@ type fledglingEvent struct { RoomID string } -func mustCreateEvent(t *testing.T, ev fledglingEvent) (result *gomatrixserverlib.HeaderedEvent) { +func mustCreateEvent(t *testing.T, ev fledglingEvent) (result *types.HeaderedEvent) { t.Helper() roomVer := gomatrixserverlib.RoomVersionV6 seed := make([]byte, ed25519.SeedSize) // zero seed @@ -601,6 +602,6 @@ func mustCreateEvent(t *testing.T, ev fledglingEvent) (result *gomatrixserverlib if err != nil { t.Fatalf("mustCreateEvent: failed to sign event: %s", err) } - h := signedEvent.Headered(roomVer) + h := &types.HeaderedEvent{Event: signedEvent} return h } diff --git a/setup/mscs/msc2836/storage.go b/setup/mscs/msc2836/storage.go index 4f348192c..6a45f08a4 100644 --- a/setup/mscs/msc2836/storage.go +++ b/setup/mscs/msc2836/storage.go @@ -8,8 +8,8 @@ import ( "encoding/json" "github.com/matrix-org/dendrite/internal/sqlutil" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/util" ) @@ -23,7 +23,7 @@ type eventInfo struct { type Database interface { // StoreRelation stores the parent->child and child->parent relationship for later querying. // Also stores the event metadata e.g timestamp - StoreRelation(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error + StoreRelation(ctx context.Context, ev *types.HeaderedEvent) error // ChildrenForParent returns the events who have the given `eventID` as an m.relationship with the // provided `relType`. The returned slice is sorted by origin_server_ts according to whether // `recentFirst` is true or false. @@ -35,7 +35,7 @@ type Database interface { // UpdateChildMetadata persists the children_count and children_hash from this event if and only if // the count is greater than what was previously there. If the count is updated, the event will be // updated to be unexplored. - UpdateChildMetadata(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error + UpdateChildMetadata(ctx context.Context, ev *types.HeaderedEvent) error // ChildMetadata returns the children_count and children_hash for the event ID in question. // Also returns the `explored` flag, which is set to true when MarkChildrenExplored is called and is set // back to `false` when a larger count is inserted via UpdateChildMetadata. @@ -222,7 +222,7 @@ func newSQLiteDatabase(conMan sqlutil.Connections, dbOpts *config.DatabaseOption return &d, nil } -func (p *DB) StoreRelation(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error { +func (p *DB) StoreRelation(ctx context.Context, ev *types.HeaderedEvent) error { parent, child, relType := parentChildEventIDs(ev) if parent == "" || child == "" { return nil @@ -244,7 +244,7 @@ func (p *DB) StoreRelation(ctx context.Context, ev *gomatrixserverlib.HeaderedEv }) } -func (p *DB) UpdateChildMetadata(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error { +func (p *DB) UpdateChildMetadata(ctx context.Context, ev *types.HeaderedEvent) error { eventCount, eventHash := extractChildMetadata(ev) if eventCount == 0 { return nil // nothing to update with @@ -315,7 +315,7 @@ func (p *DB) ParentForChild(ctx context.Context, eventID, relType string) (*even return &ei, nil } -func parentChildEventIDs(ev *gomatrixserverlib.HeaderedEvent) (parent, child, relType string) { +func parentChildEventIDs(ev *types.HeaderedEvent) (parent, child, relType string) { if ev == nil { return } @@ -334,7 +334,7 @@ func parentChildEventIDs(ev *gomatrixserverlib.HeaderedEvent) (parent, child, re return body.Relationship.EventID, ev.EventID(), body.Relationship.RelType } -func roomIDAndServers(ev *gomatrixserverlib.HeaderedEvent) (roomID string, servers []string) { +func roomIDAndServers(ev *types.HeaderedEvent) (roomID string, servers []string) { servers = []string{} if ev == nil { return @@ -349,7 +349,7 @@ func roomIDAndServers(ev *gomatrixserverlib.HeaderedEvent) (roomID string, serve return body.RoomID, body.Servers } -func extractChildMetadata(ev *gomatrixserverlib.HeaderedEvent) (count int, hash []byte) { +func extractChildMetadata(ev *types.HeaderedEvent) (count int, hash []byte) { unsigned := struct { Counts map[string]int `json:"children"` Hash spec.Base64Bytes `json:"children_hash"` diff --git a/setup/mscs/msc2946/msc2946.go b/setup/mscs/msc2946/msc2946.go index 80d6c5980..1795858b3 100644 --- a/setup/mscs/msc2946/msc2946.go +++ b/setup/mscs/msc2946/msc2946.go @@ -33,6 +33,7 @@ import ( "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/httputil" roomserver "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" @@ -388,7 +389,7 @@ func (w *walker) walk() util.JSONResponse { } } -func (w *walker) stateEvent(roomID, evType, stateKey string) *gomatrixserverlib.HeaderedEvent { +func (w *walker) stateEvent(roomID, evType, stateKey string) *types.HeaderedEvent { var queryRes roomserver.QueryCurrentStateResponse tuple := gomatrixserverlib.StateKeyTuple{ EventType: evType, @@ -636,7 +637,7 @@ func (w *walker) authorisedUser(roomID, parentRoomID string) (authed bool, isJoi return false, false } -func (w *walker) restrictedJoinRuleAllowedRooms(joinRuleEv *gomatrixserverlib.HeaderedEvent, allowType string) (allows []string) { +func (w *walker) restrictedJoinRuleAllowedRooms(joinRuleEv *types.HeaderedEvent, allowType string) (allows []string) { rule, _ := joinRuleEv.JoinRule() if rule != spec.Restricted { return nil diff --git a/syncapi/consumers/roomserver.go b/syncapi/consumers/roomserver.go index c842c0c38..83ac82ffa 100644 --- a/syncapi/consumers/roomserver.go +++ b/syncapi/consumers/roomserver.go @@ -21,7 +21,6 @@ import ( "fmt" "github.com/getsentry/sentry-go" - "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/nats-io/nats.go" "github.com/sirupsen/logrus" @@ -31,6 +30,7 @@ import ( "github.com/matrix-org/dendrite/internal/fulltext" "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/process" @@ -318,7 +318,7 @@ func (s *OutputRoomEventConsumer) onOldRoomEvent( pduPos, err := s.db.WriteEvent( ctx, ev, - []*gomatrixserverlib.HeaderedEvent{}, + []*rstypes.HeaderedEvent{}, []string{}, // adds no state []string{}, // removes no state nil, // no transaction @@ -362,7 +362,7 @@ func (s *OutputRoomEventConsumer) onOldRoomEvent( return nil } -func (s *OutputRoomEventConsumer) notifyJoinedPeeks(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent, sp types.StreamPosition) (types.StreamPosition, error) { +func (s *OutputRoomEventConsumer) notifyJoinedPeeks(ctx context.Context, ev *rstypes.HeaderedEvent, sp types.StreamPosition) (types.StreamPosition, error) { if ev.Type() != spec.MRoomMember { return sp, nil } @@ -496,7 +496,7 @@ func (s *OutputRoomEventConsumer) onPurgeRoom( } } -func (s *OutputRoomEventConsumer) updateStateEvent(event *gomatrixserverlib.HeaderedEvent) (*gomatrixserverlib.HeaderedEvent, error) { +func (s *OutputRoomEventConsumer) updateStateEvent(event *rstypes.HeaderedEvent) (*rstypes.HeaderedEvent, error) { if event.StateKey() == nil { return event, nil } @@ -531,7 +531,7 @@ func (s *OutputRoomEventConsumer) updateStateEvent(event *gomatrixserverlib.Head return event, err } -func (s *OutputRoomEventConsumer) writeFTS(ev *gomatrixserverlib.HeaderedEvent, pduPosition types.StreamPosition) error { +func (s *OutputRoomEventConsumer) writeFTS(ev *rstypes.HeaderedEvent, pduPosition types.StreamPosition) error { if !s.cfg.Fulltext.Enabled { return nil } diff --git a/syncapi/internal/history_visibility.go b/syncapi/internal/history_visibility.go index 10d7383b2..7449b4647 100644 --- a/syncapi/internal/history_visibility.go +++ b/syncapi/internal/history_visibility.go @@ -26,6 +26,7 @@ import ( "github.com/tidwall/gjson" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage" ) @@ -98,16 +99,16 @@ func (ev eventVisibility) allowed() (allowed bool) { } } -// ApplyHistoryVisibilityFilter applies the room history visibility filter on gomatrixserverlib.HeaderedEvents. +// ApplyHistoryVisibilityFilter applies the room history visibility filter on types.HeaderedEvents. // Returns the filtered events and an error, if any. func ApplyHistoryVisibilityFilter( ctx context.Context, syncDB storage.DatabaseTransaction, rsAPI api.SyncRoomserverAPI, - events []*gomatrixserverlib.HeaderedEvent, + events []*types.HeaderedEvent, alwaysIncludeEventIDs map[string]struct{}, userID, endpoint string, -) ([]*gomatrixserverlib.HeaderedEvent, error) { +) ([]*types.HeaderedEvent, error) { if len(events) == 0 { return events, nil } @@ -120,7 +121,7 @@ func ApplyHistoryVisibilityFilter( } // Get the mapping from eventID -> eventVisibility - eventsFiltered := make([]*gomatrixserverlib.HeaderedEvent, 0, len(events)) + eventsFiltered := make([]*types.HeaderedEvent, 0, len(events)) visibilities := visibilityForEvents(ctx, rsAPI, events, userID, events[0].RoomID()) for _, ev := range events { evVis := visibilities[ev.EventID()] @@ -170,7 +171,7 @@ func ApplyHistoryVisibilityFilter( func visibilityForEvents( ctx context.Context, rsAPI api.SyncRoomserverAPI, - events []*gomatrixserverlib.HeaderedEvent, + events []*types.HeaderedEvent, userID, roomID string, ) map[string]eventVisibility { eventIDs := make([]string, len(events)) diff --git a/syncapi/notifier/notifier.go b/syncapi/notifier/notifier.go index 81b0e7f9e..b76bdce33 100644 --- a/syncapi/notifier/notifier.go +++ b/syncapi/notifier/notifier.go @@ -20,9 +20,9 @@ import ( "time" "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/types" - "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" log "github.com/sirupsen/logrus" ) @@ -87,7 +87,7 @@ func (n *Notifier) SetCurrentPosition(currPos types.StreamingToken) { // Typically a consumer supplies a posUpdate with the latest sync position for the // event type it handles, leaving other fields as 0. func (n *Notifier) OnNewEvent( - ev *gomatrixserverlib.HeaderedEvent, roomID string, userIDs []string, + ev *rstypes.HeaderedEvent, roomID string, userIDs []string, posUpdate types.StreamingToken, ) { // update the current position then notify relevant /sync streams. diff --git a/syncapi/notifier/notifier_test.go b/syncapi/notifier/notifier_test.go index b06313712..36577a0ee 100644 --- a/syncapi/notifier/notifier_test.go +++ b/syncapi/notifier/notifier_test.go @@ -22,16 +22,16 @@ import ( "testing" "time" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/types" userapi "github.com/matrix-org/dendrite/userapi/api" - "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" ) var ( - randomMessageEvent gomatrixserverlib.HeaderedEvent - aliceInviteBobEvent gomatrixserverlib.HeaderedEvent - bobLeaveEvent gomatrixserverlib.HeaderedEvent + randomMessageEvent rstypes.HeaderedEvent + aliceInviteBobEvent rstypes.HeaderedEvent + bobLeaveEvent rstypes.HeaderedEvent syncPositionVeryOld = types.StreamingToken{PDUPosition: 5} syncPositionBefore = types.StreamingToken{PDUPosition: 11} syncPositionAfter = types.StreamingToken{PDUPosition: 12} diff --git a/syncapi/routing/context.go b/syncapi/routing/context.go index afd61eae8..b85ab7f22 100644 --- a/syncapi/routing/context.go +++ b/syncapi/routing/context.go @@ -27,6 +27,7 @@ import ( "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/sqlutil" roomserver "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/internal" "github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/synctypes" @@ -122,7 +123,7 @@ func Context( // verify the user is allowed to see the context for this room/event startTime := time.Now() - filteredEvents, err := internal.ApplyHistoryVisibilityFilter(ctx, snapshot, rsAPI, []*gomatrixserverlib.HeaderedEvent{&requestedEvent}, nil, device.UserID, "context") + filteredEvents, err := internal.ApplyHistoryVisibilityFilter(ctx, snapshot, rsAPI, []*rstypes.HeaderedEvent{&requestedEvent}, nil, device.UserID, "context") if err != nil { logrus.WithError(err).Error("unable to apply history visibility filter") return jsonerror.InternalServerError() @@ -169,14 +170,14 @@ func Context( return jsonerror.InternalServerError() } - eventsBeforeClient := synctypes.HeaderedToClientEvents(eventsBeforeFiltered, synctypes.FormatAll) - eventsAfterClient := synctypes.HeaderedToClientEvents(eventsAfterFiltered, synctypes.FormatAll) + eventsBeforeClient := synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(eventsBeforeFiltered), synctypes.FormatAll) + eventsAfterClient := synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(eventsAfterFiltered), synctypes.FormatAll) newState := state if filter.LazyLoadMembers { allEvents := append(eventsBeforeFiltered, eventsAfterFiltered...) allEvents = append(allEvents, &requestedEvent) - evs := synctypes.HeaderedToClientEvents(allEvents, synctypes.FormatAll) + evs := synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(allEvents), synctypes.FormatAll) newState, err = applyLazyLoadMembers(ctx, device, snapshot, roomID, evs, lazyLoadCache) if err != nil { logrus.WithError(err).Error("unable to load membership events") @@ -184,12 +185,12 @@ func Context( } } - ev := synctypes.HeaderedToClientEvent(&requestedEvent, synctypes.FormatAll) + ev := synctypes.ToClientEvent(&requestedEvent, synctypes.FormatAll) response := ContextRespsonse{ Event: &ev, EventsAfter: eventsAfterClient, EventsBefore: eventsBeforeClient, - State: synctypes.HeaderedToClientEvents(newState, synctypes.FormatAll), + State: synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(newState), synctypes.FormatAll), } if len(response.State) > filter.Limit { @@ -212,9 +213,9 @@ func Context( // and an error, if any. func applyHistoryVisibilityOnContextEvents( ctx context.Context, snapshot storage.DatabaseTransaction, rsAPI roomserver.SyncRoomserverAPI, - eventsBefore, eventsAfter []*gomatrixserverlib.HeaderedEvent, + eventsBefore, eventsAfter []*rstypes.HeaderedEvent, userID string, -) (filteredBefore, filteredAfter []*gomatrixserverlib.HeaderedEvent, err error) { +) (filteredBefore, filteredAfter []*rstypes.HeaderedEvent, err error) { eventIDsBefore := make(map[string]struct{}, len(eventsBefore)) eventIDsAfter := make(map[string]struct{}, len(eventsAfter)) @@ -245,7 +246,7 @@ func applyHistoryVisibilityOnContextEvents( return filteredBefore, filteredAfter, nil } -func getStartEnd(ctx context.Context, snapshot storage.DatabaseTransaction, startEvents, endEvents []*gomatrixserverlib.HeaderedEvent) (start, end types.TopologyToken, err error) { +func getStartEnd(ctx context.Context, snapshot storage.DatabaseTransaction, startEvents, endEvents []*rstypes.HeaderedEvent) (start, end types.TopologyToken, err error) { if len(startEvents) > 0 { start, err = snapshot.EventPositionInTopology(ctx, startEvents[0].EventID()) if err != nil { @@ -265,7 +266,7 @@ func applyLazyLoadMembers( roomID string, events []synctypes.ClientEvent, lazyLoadCache caching.LazyLoadCache, -) ([]*gomatrixserverlib.HeaderedEvent, error) { +) ([]*rstypes.HeaderedEvent, error) { eventSenders := make(map[string]struct{}) // get members who actually send an event for _, e := range events { diff --git a/syncapi/routing/getevent.go b/syncapi/routing/getevent.go index 84986d3b3..7775598ee 100644 --- a/syncapi/routing/getevent.go +++ b/syncapi/routing/getevent.go @@ -97,6 +97,6 @@ func GetEvent( return util.JSONResponse{ Code: http.StatusOK, - JSON: synctypes.HeaderedToClientEvent(events[0], synctypes.FormatAll), + JSON: synctypes.ToClientEvent(events[0], synctypes.FormatAll), } } diff --git a/syncapi/routing/memberships.go b/syncapi/routing/memberships.go index 9ea660f59..a23f1525b 100644 --- a/syncapi/routing/memberships.go +++ b/syncapi/routing/memberships.go @@ -25,6 +25,7 @@ import ( "github.com/matrix-org/dendrite/syncapi/synctypes" "github.com/matrix-org/dendrite/syncapi/types" userapi "github.com/matrix-org/dendrite/userapi/api" + "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" ) @@ -134,6 +135,6 @@ func GetMemberships( } return util.JSONResponse{ Code: http.StatusOK, - JSON: getMembershipResponse{synctypes.HeaderedToClientEvents(result, synctypes.FormatAll)}, + JSON: getMembershipResponse{synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(result), synctypes.FormatAll)}, } } diff --git a/syncapi/routing/messages.go b/syncapi/routing/messages.go index 6e508a92c..54b72c64d 100644 --- a/syncapi/routing/messages.go +++ b/syncapi/routing/messages.go @@ -31,6 +31,7 @@ import ( "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/syncapi/internal" "github.com/matrix-org/dendrite/syncapi/storage" @@ -255,7 +256,7 @@ func OnIncomingMessagesRequest( util.GetLogger(req.Context()).WithError(err).Error("failed to apply lazy loading") return jsonerror.InternalServerError() } - res.State = append(res.State, synctypes.HeaderedToClientEvents(membershipEvents, synctypes.FormatAll)...) + res.State = append(res.State, synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(membershipEvents), synctypes.FormatAll)...) } // If we didn't return any events, set the end to an empty string, so it will be omitted @@ -303,7 +304,7 @@ func (r *messagesReq) retrieveEvents() ( return } - var events []*gomatrixserverlib.HeaderedEvent + var events []*rstypes.HeaderedEvent util.GetLogger(r.ctx).WithFields(logrus.Fields{ "start": r.from, "end": r.to, @@ -342,8 +343,8 @@ func (r *messagesReq) retrieveEvents() ( // Sort the events to ensure we send them in the right order. if r.backwardOrdering { // This reverses the array from old->new to new->old - reversed := func(in []*gomatrixserverlib.HeaderedEvent) []*gomatrixserverlib.HeaderedEvent { - out := make([]*gomatrixserverlib.HeaderedEvent, len(in)) + reversed := func(in []*rstypes.HeaderedEvent) []*rstypes.HeaderedEvent { + out := make([]*rstypes.HeaderedEvent, len(in)) for i := 0; i < len(in); i++ { out[i] = in[len(in)-i-1] } @@ -364,10 +365,10 @@ func (r *messagesReq) retrieveEvents() ( "events_before": len(events), "events_after": len(filteredEvents), }).Debug("applied history visibility (messages)") - return synctypes.HeaderedToClientEvents(filteredEvents, synctypes.FormatAll), start, end, err + return synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(filteredEvents), synctypes.FormatAll), start, end, err } -func (r *messagesReq) getStartEnd(events []*gomatrixserverlib.HeaderedEvent) (start, end types.TopologyToken, err error) { +func (r *messagesReq) getStartEnd(events []*rstypes.HeaderedEvent) (start, end types.TopologyToken, err error) { if r.backwardOrdering { start = *r.from if events[len(events)-1].Type() == spec.MRoomCreate { @@ -406,7 +407,7 @@ func (r *messagesReq) getStartEnd(events []*gomatrixserverlib.HeaderedEvent) (st // Returns an error if there was an issue talking with the database or // backfilling. func (r *messagesReq) handleEmptyEventsSlice() ( - events []*gomatrixserverlib.HeaderedEvent, err error, + events []*rstypes.HeaderedEvent, err error, ) { backwardExtremities, err := r.snapshot.BackwardExtremitiesForRoom(r.ctx, r.roomID) @@ -420,7 +421,7 @@ func (r *messagesReq) handleEmptyEventsSlice() ( } else { // If not, it means the slice was empty because we reached the room's // creation, so return an empty slice. - events = []*gomatrixserverlib.HeaderedEvent{} + events = []*rstypes.HeaderedEvent{} } return @@ -432,7 +433,7 @@ func (r *messagesReq) handleEmptyEventsSlice() ( // through backfilling if needed. // Returns an error if there was an issue while backfilling. func (r *messagesReq) handleNonEmptyEventsSlice(streamEvents []types.StreamEvent) ( - events []*gomatrixserverlib.HeaderedEvent, err error, + events []*rstypes.HeaderedEvent, err error, ) { // Check if we have enough events. isSetLargeEnough := len(streamEvents) >= r.filter.Limit @@ -460,7 +461,7 @@ func (r *messagesReq) handleNonEmptyEventsSlice(streamEvents []types.StreamEvent // Backfill is needed if we've reached a backward extremity and need more // events. It's only needed if the direction is backward. if len(backwardExtremities) > 0 && !isSetLargeEnough && r.backwardOrdering { - var pdus []*gomatrixserverlib.HeaderedEvent + var pdus []*rstypes.HeaderedEvent // Only ask the remote server for enough events to reach the limit. pdus, err = r.backfill(r.roomID, backwardExtremities, r.filter.Limit-len(streamEvents)) if err != nil { @@ -478,7 +479,7 @@ func (r *messagesReq) handleNonEmptyEventsSlice(streamEvents []types.StreamEvent return } -type eventsByDepth []*gomatrixserverlib.HeaderedEvent +type eventsByDepth []*rstypes.HeaderedEvent func (e eventsByDepth) Len() int { return len(e) @@ -499,7 +500,7 @@ func (e eventsByDepth) Less(i, j int) bool { // event, or if there is no remote homeserver to contact. // Returns an error if there was an issue with retrieving the list of servers in // the room or sending the request. -func (r *messagesReq) backfill(roomID string, backwardsExtremities map[string][]string, limit int) ([]*gomatrixserverlib.HeaderedEvent, error) { +func (r *messagesReq) backfill(roomID string, backwardsExtremities map[string][]string, limit int) ([]*rstypes.HeaderedEvent, error) { var res api.PerformBackfillResponse err := r.rsAPI.PerformBackfill(context.Background(), &api.PerformBackfillRequest{ RoomID: roomID, @@ -532,7 +533,7 @@ func (r *messagesReq) backfill(roomID string, backwardsExtremities map[string][] _, err = r.db.WriteEvent( context.Background(), res.Events[i], - []*gomatrixserverlib.HeaderedEvent{}, + []*rstypes.HeaderedEvent{}, []string{}, []string{}, nil, true, diff --git a/syncapi/routing/relations.go b/syncapi/routing/relations.go index 79533883f..275ab65c0 100644 --- a/syncapi/routing/relations.go +++ b/syncapi/routing/relations.go @@ -18,13 +18,13 @@ import ( "net/http" "strconv" - "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" "github.com/sirupsen/logrus" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/internal" "github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/synctypes" @@ -96,7 +96,7 @@ func Relations( return util.ErrorResponse(err) } - headeredEvents := make([]*gomatrixserverlib.HeaderedEvent, 0, len(events)) + headeredEvents := make([]*rstypes.HeaderedEvent, 0, len(events)) for _, event := range events { headeredEvents = append(headeredEvents, event.HeaderedEvent) } diff --git a/syncapi/routing/search.go b/syncapi/routing/search.go index 224c68072..5f0373926 100644 --- a/syncapi/routing/search.go +++ b/syncapi/routing/search.go @@ -32,6 +32,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/internal/fulltext" "github.com/matrix-org/dendrite/internal/sqlutil" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/synctypes" "github.com/matrix-org/dendrite/userapi/api" @@ -206,12 +207,12 @@ func Search(req *http.Request, device *api.Device, syncDB storage.Database, fts Context: SearchContextResponse{ Start: startToken.String(), End: endToken.String(), - EventsAfter: synctypes.HeaderedToClientEvents(eventsAfter, synctypes.FormatSync), - EventsBefore: synctypes.HeaderedToClientEvents(eventsBefore, synctypes.FormatSync), + EventsAfter: synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(eventsAfter), synctypes.FormatSync), + EventsBefore: synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(eventsBefore), synctypes.FormatSync), ProfileInfo: profileInfos, }, Rank: eventScore[event.EventID()].Score, - Result: synctypes.HeaderedToClientEvent(event, synctypes.FormatAll), + Result: synctypes.ToClientEvent(event, synctypes.FormatAll), }) roomGroup := groups[event.RoomID()] roomGroup.Results = append(roomGroup.Results, event.EventID()) @@ -223,7 +224,7 @@ func Search(req *http.Request, device *api.Device, syncDB storage.Database, fts logrus.WithError(err).Error("unable to get current state") return jsonerror.InternalServerError() } - stateForRooms[event.RoomID()] = synctypes.HeaderedToClientEvents(state, synctypes.FormatSync) + stateForRooms[event.RoomID()] = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(state), synctypes.FormatSync) } } @@ -263,10 +264,10 @@ func Search(req *http.Request, device *api.Device, syncDB storage.Database, fts func contextEvents( ctx context.Context, snapshot storage.DatabaseTransaction, - event *gomatrixserverlib.HeaderedEvent, + event *types.HeaderedEvent, roomFilter *synctypes.RoomEventFilter, searchReq SearchRequest, -) ([]*gomatrixserverlib.HeaderedEvent, []*gomatrixserverlib.HeaderedEvent, error) { +) ([]*types.HeaderedEvent, []*types.HeaderedEvent, error) { id, _, err := snapshot.SelectContextEvent(ctx, event.RoomID(), event.EventID()) if err != nil { logrus.WithError(err).Error("failed to query context event") diff --git a/syncapi/routing/search_test.go b/syncapi/routing/search_test.go index c8b9c604c..1cc95a873 100644 --- a/syncapi/routing/search_test.go +++ b/syncapi/routing/search_test.go @@ -9,6 +9,7 @@ import ( "github.com/matrix-org/dendrite/internal/fulltext" "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/synctypes" "github.com/matrix-org/dendrite/syncapi/types" @@ -215,7 +216,7 @@ func TestSearch(t *testing.T) { // store the events in the database var sp types.StreamPosition for _, x := range room.Events() { - var stateEvents []*gomatrixserverlib.HeaderedEvent + var stateEvents []*rstypes.HeaderedEvent var stateEventIDs []string if x.Type() == spec.MRoomMember { stateEvents = append(stateEvents, x) diff --git a/syncapi/storage/interface.go b/syncapi/storage/interface.go index f5c1223a7..302b9bad8 100644 --- a/syncapi/storage/interface.go +++ b/syncapi/storage/interface.go @@ -23,6 +23,7 @@ import ( "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage/shared" "github.com/matrix-org/dendrite/syncapi/synctypes" "github.com/matrix-org/dendrite/syncapi/types" @@ -42,16 +43,16 @@ type DatabaseTransaction interface { MaxStreamPositionForPresence(ctx context.Context) (types.StreamPosition, error) MaxStreamPositionForRelations(ctx context.Context) (types.StreamPosition, error) - CurrentState(ctx context.Context, roomID string, stateFilterPart *synctypes.StateFilter, excludeEventIDs []string) ([]*gomatrixserverlib.HeaderedEvent, error) + CurrentState(ctx context.Context, roomID string, stateFilterPart *synctypes.StateFilter, excludeEventIDs []string) ([]*rstypes.HeaderedEvent, error) GetStateDeltasForFullStateSync(ctx context.Context, device *userapi.Device, r types.Range, userID string, stateFilter *synctypes.StateFilter) ([]types.StateDelta, []string, error) GetStateDeltas(ctx context.Context, device *userapi.Device, r types.Range, userID string, stateFilter *synctypes.StateFilter) ([]types.StateDelta, []string, error) RoomIDsWithMembership(ctx context.Context, userID string, membership string) ([]string, error) MembershipCount(ctx context.Context, roomID, membership string, pos types.StreamPosition) (int, error) GetRoomSummary(ctx context.Context, roomID, userID string) (summary *types.Summary, err error) RecentEvents(ctx context.Context, roomIDs []string, r types.Range, eventFilter *synctypes.RoomEventFilter, chronologicalOrder bool, onlySyncEvents bool) (map[string]types.RecentEvents, error) - GetBackwardTopologyPos(ctx context.Context, events []*gomatrixserverlib.HeaderedEvent) (types.TopologyToken, error) + GetBackwardTopologyPos(ctx context.Context, events []*rstypes.HeaderedEvent) (types.TopologyToken, error) PositionInTopology(ctx context.Context, eventID string) (pos types.StreamPosition, spos types.StreamPosition, err error) - InviteEventsInRange(ctx context.Context, targetUserID string, r types.Range) (map[string]*gomatrixserverlib.HeaderedEvent, map[string]*gomatrixserverlib.HeaderedEvent, types.StreamPosition, error) + InviteEventsInRange(ctx context.Context, targetUserID string, r types.Range) (map[string]*rstypes.HeaderedEvent, map[string]*rstypes.HeaderedEvent, types.StreamPosition, error) PeeksInRange(ctx context.Context, userID, deviceID string, r types.Range) (peeks []types.Peek, err error) RoomReceiptsAfter(ctx context.Context, roomIDs []string, streamPos types.StreamPosition) (types.StreamPosition, []types.OutputReceiptEvent, error) // AllJoinedUsersInRooms returns a map of room ID to a list of all joined user IDs. @@ -65,15 +66,15 @@ type DatabaseTransaction interface { // If an event is not found in the database then it will be omitted from the list. // Returns an error if there was a problem talking with the database. // Does not include any transaction IDs in the returned events. - Events(ctx context.Context, eventIDs []string) ([]*gomatrixserverlib.HeaderedEvent, error) + Events(ctx context.Context, eventIDs []string) ([]*rstypes.HeaderedEvent, error) // GetStateEvent returns the Matrix state event of a given type for a given room with a given state key // If no event could be found, returns nil // If there was an issue during the retrieval, returns an error - GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*gomatrixserverlib.HeaderedEvent, error) + GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*rstypes.HeaderedEvent, error) // GetStateEventsForRoom fetches the state events for a given room. // Returns an empty slice if no state events could be found for this room. // Returns an error if there was an issue with the retrieval. - GetStateEventsForRoom(ctx context.Context, roomID string, stateFilterPart *synctypes.StateFilter) (stateEvents []*gomatrixserverlib.HeaderedEvent, err error) + GetStateEventsForRoom(ctx context.Context, roomID string, stateFilterPart *synctypes.StateFilter) (stateEvents []*rstypes.HeaderedEvent, err error) // GetAccountDataInRange returns all account data for a given user inserted or // updated between two given positions // Returns a map following the format data[roomID] = []dataTypes @@ -89,15 +90,15 @@ type DatabaseTransaction interface { // StreamEventsToEvents converts streamEvent to Event. If device is non-nil and // matches the streamevent.transactionID device then the transaction ID gets // added to the unsigned section of the output event. - StreamEventsToEvents(device *userapi.Device, in []types.StreamEvent) []*gomatrixserverlib.HeaderedEvent + StreamEventsToEvents(device *userapi.Device, in []types.StreamEvent) []*rstypes.HeaderedEvent // SendToDeviceUpdatesForSync returns a list of send-to-device updates. It returns the // relevant events within the given ranges for the supplied user ID and device ID. SendToDeviceUpdatesForSync(ctx context.Context, userID, deviceID string, from, to types.StreamPosition) (pos types.StreamPosition, events []types.SendToDeviceEvent, err error) // GetRoomReceipts gets all receipts for a given roomID GetRoomReceipts(ctx context.Context, roomIDs []string, streamPos types.StreamPosition) ([]types.OutputReceiptEvent, error) - SelectContextEvent(ctx context.Context, roomID, eventID string) (int, gomatrixserverlib.HeaderedEvent, error) - SelectContextBeforeEvent(ctx context.Context, id int, roomID string, filter *synctypes.RoomEventFilter) ([]*gomatrixserverlib.HeaderedEvent, error) - SelectContextAfterEvent(ctx context.Context, id int, roomID string, filter *synctypes.RoomEventFilter) (int, []*gomatrixserverlib.HeaderedEvent, error) + SelectContextEvent(ctx context.Context, roomID, eventID string) (int, rstypes.HeaderedEvent, error) + SelectContextBeforeEvent(ctx context.Context, id int, roomID string, filter *synctypes.RoomEventFilter) ([]*rstypes.HeaderedEvent, error) + SelectContextAfterEvent(ctx context.Context, id int, roomID string, filter *synctypes.RoomEventFilter) (int, []*rstypes.HeaderedEvent, error) StreamToTopologicalPosition(ctx context.Context, roomID string, streamPos types.StreamPosition, backwardOrdering bool) (types.TopologyToken, error) IgnoresForUser(ctx context.Context, userID string) (*types.IgnoredUsers, error) // SelectMembershipForUser returns the membership of the user before and including the given position. If no membership can be found @@ -123,11 +124,11 @@ type Database interface { // If an event is not found in the database then it will be omitted from the list. // Returns an error if there was a problem talking with the database. // Does not include any transaction IDs in the returned events. - Events(ctx context.Context, eventIDs []string) ([]*gomatrixserverlib.HeaderedEvent, error) + Events(ctx context.Context, eventIDs []string) ([]*rstypes.HeaderedEvent, error) // WriteEvent into the database. It is not safe to call this function from multiple goroutines, as it would create races // when generating the sync stream position for this event. Returns the sync stream position for the inserted event. // Returns an error if there was a problem inserting this event. - WriteEvent(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent, addStateEvents []*gomatrixserverlib.HeaderedEvent, + WriteEvent(ctx context.Context, ev *rstypes.HeaderedEvent, addStateEvents []*rstypes.HeaderedEvent, addStateEventIDs []string, removeStateEventIDs []string, transactionID *api.TransactionID, excludeFromSync bool, historyVisibility gomatrixserverlib.HistoryVisibility, ) (types.StreamPosition, error) @@ -146,7 +147,7 @@ type Database interface { // AddInviteEvent stores a new invite event for a user. // If the invite was successfully stored this returns the stream ID it was stored at. // Returns an error if there was a problem communicating with the database. - AddInviteEvent(ctx context.Context, inviteEvent *gomatrixserverlib.HeaderedEvent) (types.StreamPosition, error) + AddInviteEvent(ctx context.Context, inviteEvent *rstypes.HeaderedEvent) (types.StreamPosition, error) // RetireInviteEvent removes an old invite event from the database. Returns the new position of the retired invite. // Returns an error if there was a problem communicating with the database. RetireInviteEvent(ctx context.Context, inviteEventID string) (types.StreamPosition, error) @@ -173,12 +174,12 @@ type Database interface { // goes wrong. PutFilter(ctx context.Context, localpart string, filter *synctypes.Filter) (string, error) // RedactEvent wipes an event in the database and sets the unsigned.redacted_because key to the redaction event - RedactEvent(ctx context.Context, redactedEventID string, redactedBecause *gomatrixserverlib.HeaderedEvent) error + RedactEvent(ctx context.Context, redactedEventID string, redactedBecause *rstypes.HeaderedEvent) error // StoreReceipt stores new receipt events StoreReceipt(ctx context.Context, roomId, receiptType, userId, eventId string, timestamp spec.Timestamp) (pos types.StreamPosition, err error) UpdateIgnoresForUser(ctx context.Context, userID string, ignores *types.IgnoredUsers) error - ReIndex(ctx context.Context, limit, afterID int64) (map[int64]gomatrixserverlib.HeaderedEvent, error) - UpdateRelations(ctx context.Context, event *gomatrixserverlib.HeaderedEvent) error + ReIndex(ctx context.Context, limit, afterID int64) (map[int64]rstypes.HeaderedEvent, error) + UpdateRelations(ctx context.Context, event *rstypes.HeaderedEvent) error RedactRelations(ctx context.Context, roomID, redactedEventID string) error SelectMemberships( ctx context.Context, diff --git a/syncapi/storage/postgres/current_room_state_table.go b/syncapi/storage/postgres/current_room_state_table.go index c2a870c07..0cc963731 100644 --- a/syncapi/storage/postgres/current_room_state_table.go +++ b/syncapi/storage/postgres/current_room_state_table.go @@ -24,6 +24,7 @@ import ( "github.com/lib/pq" "github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage/postgres/deltas" "github.com/matrix-org/dendrite/syncapi/storage/tables" "github.com/matrix-org/dendrite/syncapi/synctypes" @@ -274,7 +275,7 @@ func (s *currentRoomStateStatements) SelectCurrentState( ctx context.Context, txn *sql.Tx, roomID string, stateFilter *synctypes.StateFilter, excludeEventIDs []string, -) ([]*gomatrixserverlib.HeaderedEvent, error) { +) ([]*rstypes.HeaderedEvent, error) { stmt := sqlutil.TxStmt(txn, s.selectCurrentStateStmt) senders, notSenders := getSendersStateFilterFilter(stateFilter) // We're going to query members later, so remove them from this request @@ -320,7 +321,7 @@ func (s *currentRoomStateStatements) DeleteRoomStateForRoom( func (s *currentRoomStateStatements) UpsertRoomState( ctx context.Context, txn *sql.Tx, - event *gomatrixserverlib.HeaderedEvent, membership *string, addedAt types.StreamPosition, + event *rstypes.HeaderedEvent, membership *string, addedAt types.StreamPosition, ) error { // Parse content as JSON and search for an "url" key containsURL := false @@ -378,8 +379,8 @@ func currentRoomStateRowsToStreamEvents(rows *sql.Rows) ([]types.StreamEvent, er return nil, err } // TODO: Handle redacted events - var ev gomatrixserverlib.HeaderedEvent - if err := ev.UnmarshalJSONWithEventID(eventBytes, eventID); err != nil { + var ev rstypes.HeaderedEvent + if err := json.Unmarshal(eventBytes, &ev); err != nil { return nil, err } @@ -394,8 +395,8 @@ func currentRoomStateRowsToStreamEvents(rows *sql.Rows) ([]types.StreamEvent, er return events, nil } -func rowsToEvents(rows *sql.Rows) ([]*gomatrixserverlib.HeaderedEvent, error) { - result := []*gomatrixserverlib.HeaderedEvent{} +func rowsToEvents(rows *sql.Rows) ([]*rstypes.HeaderedEvent, error) { + result := []*rstypes.HeaderedEvent{} for rows.Next() { var eventID string var eventBytes []byte @@ -403,8 +404,8 @@ func rowsToEvents(rows *sql.Rows) ([]*gomatrixserverlib.HeaderedEvent, error) { return nil, err } // TODO: Handle redacted events - var ev gomatrixserverlib.HeaderedEvent - if err := ev.UnmarshalJSONWithEventID(eventBytes, eventID); err != nil { + var ev rstypes.HeaderedEvent + if err := json.Unmarshal(eventBytes, &ev); err != nil { return nil, err } result = append(result, &ev) @@ -414,7 +415,7 @@ func rowsToEvents(rows *sql.Rows) ([]*gomatrixserverlib.HeaderedEvent, error) { func (s *currentRoomStateStatements) SelectStateEvent( ctx context.Context, txn *sql.Tx, roomID, evType, stateKey string, -) (*gomatrixserverlib.HeaderedEvent, error) { +) (*rstypes.HeaderedEvent, error) { stmt := sqlutil.TxStmt(txn, s.selectStateEventStmt) var res []byte err := stmt.QueryRowContext(ctx, roomID, evType, stateKey).Scan(&res) @@ -424,7 +425,7 @@ func (s *currentRoomStateStatements) SelectStateEvent( if err != nil { return nil, err } - var ev gomatrixserverlib.HeaderedEvent + var ev rstypes.HeaderedEvent if err = json.Unmarshal(res, &ev); err != nil { return nil, err } diff --git a/syncapi/storage/postgres/deltas/2022061412000000_history_visibility_column.go b/syncapi/storage/postgres/deltas/2022061412000000_history_visibility_column.go index d68ed8d5f..37660ee9d 100644 --- a/syncapi/storage/postgres/deltas/2022061412000000_history_visibility_column.go +++ b/syncapi/storage/postgres/deltas/2022061412000000_history_visibility_column.go @@ -20,6 +20,7 @@ import ( "encoding/json" "fmt" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" ) @@ -79,7 +80,7 @@ func currentHistoryVisibilities(ctx context.Context, tx *sql.Tx) (map[string]gom defer rows.Close() // nolint: errcheck var eventBytes []byte var roomID string - var event gomatrixserverlib.HeaderedEvent + var event types.HeaderedEvent var hisVis gomatrixserverlib.HistoryVisibility historyVisibilities := make(map[string]gomatrixserverlib.HistoryVisibility) for rows.Next() { diff --git a/syncapi/storage/postgres/invites_table.go b/syncapi/storage/postgres/invites_table.go index 151bffa5d..267209bba 100644 --- a/syncapi/storage/postgres/invites_table.go +++ b/syncapi/storage/postgres/invites_table.go @@ -22,9 +22,9 @@ import ( "github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage/tables" "github.com/matrix-org/dendrite/syncapi/types" - "github.com/matrix-org/gomatrixserverlib" ) const inviteEventsSchema = ` @@ -89,7 +89,7 @@ func NewPostgresInvitesTable(db *sql.DB) (tables.Invites, error) { } func (s *inviteEventsStatements) InsertInviteEvent( - ctx context.Context, txn *sql.Tx, inviteEvent *gomatrixserverlib.HeaderedEvent, + ctx context.Context, txn *sql.Tx, inviteEvent *rstypes.HeaderedEvent, ) (streamPos types.StreamPosition, err error) { var headeredJSON []byte headeredJSON, err = json.Marshal(inviteEvent) @@ -119,7 +119,7 @@ func (s *inviteEventsStatements) DeleteInviteEvent( // active invites for the target user ID in the supplied range. func (s *inviteEventsStatements) SelectInviteEventsInRange( ctx context.Context, txn *sql.Tx, targetUserID string, r types.Range, -) (map[string]*gomatrixserverlib.HeaderedEvent, map[string]*gomatrixserverlib.HeaderedEvent, types.StreamPosition, error) { +) (map[string]*rstypes.HeaderedEvent, map[string]*rstypes.HeaderedEvent, types.StreamPosition, error) { var lastPos types.StreamPosition stmt := sqlutil.TxStmt(txn, s.selectInviteEventsInRangeStmt) rows, err := stmt.QueryContext(ctx, targetUserID, r.Low(), r.High()) @@ -127,8 +127,8 @@ func (s *inviteEventsStatements) SelectInviteEventsInRange( return nil, nil, lastPos, err } defer internal.CloseAndLogIfError(ctx, rows, "selectInviteEventsInRange: rows.close() failed") - result := map[string]*gomatrixserverlib.HeaderedEvent{} - retired := map[string]*gomatrixserverlib.HeaderedEvent{} + result := map[string]*rstypes.HeaderedEvent{} + retired := map[string]*rstypes.HeaderedEvent{} for rows.Next() { var ( id types.StreamPosition @@ -151,7 +151,7 @@ func (s *inviteEventsStatements) SelectInviteEventsInRange( continue } - var event *gomatrixserverlib.HeaderedEvent + var event *rstypes.HeaderedEvent if err := json.Unmarshal(eventJSON, &event); err != nil { return nil, nil, lastPos, err } diff --git a/syncapi/storage/postgres/memberships_table.go b/syncapi/storage/postgres/memberships_table.go index 47833893a..3905f9abb 100644 --- a/syncapi/storage/postgres/memberships_table.go +++ b/syncapi/storage/postgres/memberships_table.go @@ -19,9 +19,8 @@ import ( "database/sql" "fmt" - "github.com/matrix-org/gomatrixserverlib" - "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage/tables" "github.com/matrix-org/dendrite/syncapi/types" ) @@ -100,7 +99,7 @@ func NewPostgresMembershipsTable(db *sql.DB) (tables.Memberships, error) { } func (s *membershipsStatements) UpsertMembership( - ctx context.Context, txn *sql.Tx, event *gomatrixserverlib.HeaderedEvent, + ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, streamPos, topologicalPos types.StreamPosition, ) error { membership, err := event.Membership() diff --git a/syncapi/storage/postgres/output_room_events_table.go b/syncapi/storage/postgres/output_room_events_table.go index 8ee5098c7..3aadbccf8 100644 --- a/syncapi/storage/postgres/output_room_events_table.go +++ b/syncapi/storage/postgres/output_room_events_table.go @@ -26,6 +26,7 @@ import ( "github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage/postgres/deltas" "github.com/matrix-org/dendrite/syncapi/storage/tables" "github.com/matrix-org/dendrite/syncapi/synctypes" @@ -264,7 +265,7 @@ func NewPostgresEventsTable(db *sql.DB) (tables.Events, error) { }.Prepare(db) } -func (s *outputRoomEventsStatements) UpdateEventJSON(ctx context.Context, txn *sql.Tx, event *gomatrixserverlib.HeaderedEvent) error { +func (s *outputRoomEventsStatements) UpdateEventJSON(ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent) error { headeredJSON, err := json.Marshal(event) if err != nil { return err @@ -329,8 +330,8 @@ func (s *outputRoomEventsStatements) SelectStateInRange( } // TODO: Handle redacted events - var ev gomatrixserverlib.HeaderedEvent - if err := ev.UnmarshalJSONWithEventID(eventBytes, eventID); err != nil { + var ev rstypes.HeaderedEvent + if err := json.Unmarshal(eventBytes, &ev); err != nil { return nil, nil, err } needSet := stateNeeded[ev.RoomID()] @@ -375,7 +376,7 @@ func (s *outputRoomEventsStatements) SelectMaxEventID( // of the inserted event. func (s *outputRoomEventsStatements) InsertEvent( ctx context.Context, txn *sql.Tx, - event *gomatrixserverlib.HeaderedEvent, addState, removeState []string, + event *rstypes.HeaderedEvent, addState, removeState []string, transactionID *api.TransactionID, excludeFromSync bool, historyVisibility gomatrixserverlib.HistoryVisibility, ) (streamPos types.StreamPosition, err error) { var txnID *string @@ -465,8 +466,8 @@ func (s *outputRoomEventsStatements) SelectRecentEvents( return nil, err } // TODO: Handle redacted events - var ev gomatrixserverlib.HeaderedEvent - if err := ev.UnmarshalJSONWithEventID(eventBytes, eventID); err != nil { + var ev rstypes.HeaderedEvent + if err := json.Unmarshal(eventBytes, &ev); err != nil { return nil, err } @@ -577,7 +578,7 @@ func (s *outputRoomEventsStatements) DeleteEventsForRoom( return err } -func (s *outputRoomEventsStatements) SelectContextEvent(ctx context.Context, txn *sql.Tx, roomID, eventID string) (id int, evt gomatrixserverlib.HeaderedEvent, err error) { +func (s *outputRoomEventsStatements) SelectContextEvent(ctx context.Context, txn *sql.Tx, roomID, eventID string) (id int, evt rstypes.HeaderedEvent, err error) { row := sqlutil.TxStmt(txn, s.selectContextEventStmt).QueryRowContext(ctx, roomID, eventID) var eventAsString string @@ -595,7 +596,7 @@ func (s *outputRoomEventsStatements) SelectContextEvent(ctx context.Context, txn func (s *outputRoomEventsStatements) SelectContextBeforeEvent( ctx context.Context, txn *sql.Tx, id int, roomID string, filter *synctypes.RoomEventFilter, -) (evts []*gomatrixserverlib.HeaderedEvent, err error) { +) (evts []*rstypes.HeaderedEvent, err error) { senders, notSenders := getSendersRoomEventFilter(filter) rows, err := sqlutil.TxStmt(txn, s.selectContextBeforeEventStmt).QueryContext( ctx, roomID, id, filter.Limit, @@ -612,7 +613,7 @@ func (s *outputRoomEventsStatements) SelectContextBeforeEvent( for rows.Next() { var ( eventBytes []byte - evt *gomatrixserverlib.HeaderedEvent + evt *rstypes.HeaderedEvent historyVisibility gomatrixserverlib.HistoryVisibility ) if err = rows.Scan(&eventBytes, &historyVisibility); err != nil { @@ -630,7 +631,7 @@ func (s *outputRoomEventsStatements) SelectContextBeforeEvent( func (s *outputRoomEventsStatements) SelectContextAfterEvent( ctx context.Context, txn *sql.Tx, id int, roomID string, filter *synctypes.RoomEventFilter, -) (lastID int, evts []*gomatrixserverlib.HeaderedEvent, err error) { +) (lastID int, evts []*rstypes.HeaderedEvent, err error) { senders, notSenders := getSendersRoomEventFilter(filter) rows, err := sqlutil.TxStmt(txn, s.selectContextAfterEventStmt).QueryContext( ctx, roomID, id, filter.Limit, @@ -647,7 +648,7 @@ func (s *outputRoomEventsStatements) SelectContextAfterEvent( for rows.Next() { var ( eventBytes []byte - evt *gomatrixserverlib.HeaderedEvent + evt *rstypes.HeaderedEvent historyVisibility gomatrixserverlib.HistoryVisibility ) if err = rows.Scan(&lastID, &eventBytes, &historyVisibility); err != nil { @@ -680,8 +681,8 @@ func rowsToStreamEvents(rows *sql.Rows) ([]types.StreamEvent, error) { return nil, err } // TODO: Handle redacted events - var ev gomatrixserverlib.HeaderedEvent - if err := ev.UnmarshalJSONWithEventID(eventBytes, eventID); err != nil { + var ev rstypes.HeaderedEvent + if err := json.Unmarshal(eventBytes, &ev); err != nil { return nil, err } @@ -709,7 +710,7 @@ func (s *outputRoomEventsStatements) PurgeEvents( return err } -func (s *outputRoomEventsStatements) ReIndex(ctx context.Context, txn *sql.Tx, limit, afterID int64, types []string) (map[int64]gomatrixserverlib.HeaderedEvent, error) { +func (s *outputRoomEventsStatements) ReIndex(ctx context.Context, txn *sql.Tx, limit, afterID int64, types []string) (map[int64]rstypes.HeaderedEvent, error) { rows, err := sqlutil.TxStmt(txn, s.selectSearchStmt).QueryContext(ctx, afterID, pq.StringArray(types), limit) if err != nil { return nil, err @@ -718,14 +719,14 @@ func (s *outputRoomEventsStatements) ReIndex(ctx context.Context, txn *sql.Tx, l var eventID string var id int64 - result := make(map[int64]gomatrixserverlib.HeaderedEvent) + result := make(map[int64]rstypes.HeaderedEvent) for rows.Next() { - var ev gomatrixserverlib.HeaderedEvent + var ev rstypes.HeaderedEvent var eventBytes []byte if err = rows.Scan(&id, &eventID, &eventBytes); err != nil { return nil, err } - if err = ev.UnmarshalJSONWithEventID(eventBytes, eventID); err != nil { + if err = json.Unmarshal(eventBytes, &ev); err != nil { return nil, err } result[id] = ev diff --git a/syncapi/storage/postgres/output_room_events_topology_table.go b/syncapi/storage/postgres/output_room_events_topology_table.go index 2382fca5c..7140a92fc 100644 --- a/syncapi/storage/postgres/output_room_events_topology_table.go +++ b/syncapi/storage/postgres/output_room_events_topology_table.go @@ -18,10 +18,9 @@ import ( "context" "database/sql" - "github.com/matrix-org/gomatrixserverlib" - "github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage/tables" "github.com/matrix-org/dendrite/syncapi/types" ) @@ -105,7 +104,7 @@ func NewPostgresTopologyTable(db *sql.DB) (tables.Topology, error) { // InsertEventInTopology inserts the given event in the room's topology, based // on the event's depth. func (s *outputRoomEventsTopologyStatements) InsertEventInTopology( - ctx context.Context, txn *sql.Tx, event *gomatrixserverlib.HeaderedEvent, pos types.StreamPosition, + ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, pos types.StreamPosition, ) (topoPos types.StreamPosition, err error) { err = sqlutil.TxStmt(txn, s.insertEventInTopologyStmt).QueryRowContext( ctx, event.EventID(), event.Depth(), event.RoomID(), pos, diff --git a/syncapi/storage/shared/storage_consumer.go b/syncapi/storage/shared/storage_consumer.go index 47490fb03..05c7eec6e 100644 --- a/syncapi/storage/shared/storage_consumer.go +++ b/syncapi/storage/shared/storage_consumer.go @@ -22,6 +22,7 @@ import ( "github.com/tidwall/gjson" + rstypes "github.com/matrix-org/dendrite/roomserver/types" userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib/spec" @@ -90,7 +91,7 @@ func (d *Database) NewDatabaseTransaction(ctx context.Context) (*DatabaseTransac }, nil } -func (d *Database) Events(ctx context.Context, eventIDs []string) ([]*gomatrixserverlib.HeaderedEvent, error) { +func (d *Database) Events(ctx context.Context, eventIDs []string) ([]*rstypes.HeaderedEvent, error) { streamEvents, err := d.OutputEvents.SelectEvents(ctx, nil, eventIDs, nil, false) if err != nil { return nil, err @@ -105,7 +106,7 @@ func (d *Database) Events(ctx context.Context, eventIDs []string) ([]*gomatrixse // If the invite was successfully stored this returns the stream ID it was stored at. // Returns an error if there was a problem communicating with the database. func (d *Database) AddInviteEvent( - ctx context.Context, inviteEvent *gomatrixserverlib.HeaderedEvent, + ctx context.Context, inviteEvent *rstypes.HeaderedEvent, ) (sp types.StreamPosition, err error) { _ = d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error { sp, err = d.Invites.InsertInviteEvent(ctx, txn, inviteEvent) @@ -189,8 +190,8 @@ func (d *Database) UpsertAccountData( return } -func (d *Database) StreamEventsToEvents(device *userapi.Device, in []types.StreamEvent) []*gomatrixserverlib.HeaderedEvent { - out := make([]*gomatrixserverlib.HeaderedEvent, len(in)) +func (d *Database) StreamEventsToEvents(device *userapi.Device, in []types.StreamEvent) []*rstypes.HeaderedEvent { + out := make([]*rstypes.HeaderedEvent, len(in)) for i := 0; i < len(in); i++ { out[i] = in[i].HeaderedEvent if device != nil && in[i].TransactionID != nil { @@ -213,7 +214,7 @@ func (d *Database) StreamEventsToEvents(device *userapi.Device, in []types.Strea // the events listed in the event's 'prev_events'. This function also updates the backwards extremities table // to account for the fact that the given event is no longer a backwards extremity, but may be marked as such. // This function should always be called within a sqlutil.Writer for safety in SQLite. -func (d *Database) handleBackwardExtremities(ctx context.Context, txn *sql.Tx, ev *gomatrixserverlib.HeaderedEvent) error { +func (d *Database) handleBackwardExtremities(ctx context.Context, txn *sql.Tx, ev *rstypes.HeaderedEvent) error { if err := d.BackwardExtremities.DeleteBackwardExtremity(ctx, txn, ev.RoomID(), ev.EventID()); err != nil { return err } @@ -246,8 +247,8 @@ func (d *Database) handleBackwardExtremities(ctx context.Context, txn *sql.Tx, e func (d *Database) WriteEvent( ctx context.Context, - ev *gomatrixserverlib.HeaderedEvent, - addStateEvents []*gomatrixserverlib.HeaderedEvent, + ev *rstypes.HeaderedEvent, + addStateEvents []*rstypes.HeaderedEvent, addStateEventIDs, removeStateEventIDs []string, transactionID *api.TransactionID, excludeFromSync bool, historyVisibility gomatrixserverlib.HistoryVisibility, @@ -288,7 +289,7 @@ func (d *Database) WriteEvent( func (d *Database) updateRoomState( ctx context.Context, txn *sql.Tx, removedEventIDs []string, - addedEvents []*gomatrixserverlib.HeaderedEvent, + addedEvents []*rstypes.HeaderedEvent, pduPosition types.StreamPosition, topoPosition types.StreamPosition, ) error { @@ -342,7 +343,7 @@ func (d *Database) PutFilter( return filterID, err } -func (d *Database) RedactEvent(ctx context.Context, redactedEventID string, redactedBecause *gomatrixserverlib.HeaderedEvent) error { +func (d *Database) RedactEvent(ctx context.Context, redactedEventID string, redactedBecause *rstypes.HeaderedEvent) error { redactedEvents, err := d.Events(ctx, []string{redactedEventID}) if err != nil { return err @@ -351,13 +352,13 @@ func (d *Database) RedactEvent(ctx context.Context, redactedEventID string, reda logrus.WithField("event_id", redactedEventID).WithField("redaction_event", redactedBecause.EventID()).Warnf("missing redacted event for redaction") return nil } - eventToRedact := redactedEvents[0].Unwrap() - redactionEvent := redactedBecause.Unwrap() + eventToRedact := redactedEvents[0].Event + redactionEvent := redactedBecause.Event if err = eventutil.RedactEvent(redactionEvent, eventToRedact); err != nil { return err } - newEvent := eventToRedact.Headered(redactedBecause.RoomVersion) + newEvent := &rstypes.HeaderedEvent{Event: eventToRedact} err = d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error { return d.OutputEvents.UpdateEventJSON(ctx, txn, newEvent) }) @@ -521,14 +522,14 @@ func (d *Database) UpsertRoomUnreadNotificationCounts(ctx context.Context, userI return } -func (d *Database) SelectContextEvent(ctx context.Context, roomID, eventID string) (int, gomatrixserverlib.HeaderedEvent, error) { +func (d *Database) SelectContextEvent(ctx context.Context, roomID, eventID string) (int, rstypes.HeaderedEvent, error) { return d.OutputEvents.SelectContextEvent(ctx, nil, roomID, eventID) } -func (d *Database) SelectContextBeforeEvent(ctx context.Context, id int, roomID string, filter *synctypes.RoomEventFilter) ([]*gomatrixserverlib.HeaderedEvent, error) { +func (d *Database) SelectContextBeforeEvent(ctx context.Context, id int, roomID string, filter *synctypes.RoomEventFilter) ([]*rstypes.HeaderedEvent, error) { return d.OutputEvents.SelectContextBeforeEvent(ctx, nil, id, roomID, filter) } -func (d *Database) SelectContextAfterEvent(ctx context.Context, id int, roomID string, filter *synctypes.RoomEventFilter) (int, []*gomatrixserverlib.HeaderedEvent, error) { +func (d *Database) SelectContextAfterEvent(ctx context.Context, id int, roomID string, filter *synctypes.RoomEventFilter) (int, []*rstypes.HeaderedEvent, error) { return d.OutputEvents.SelectContextAfterEvent(ctx, nil, id, roomID, filter) } @@ -560,7 +561,7 @@ func (d *Database) SelectMembershipForUser(ctx context.Context, roomID, userID s return d.Memberships.SelectMembershipForUser(ctx, nil, roomID, userID, pos) } -func (d *Database) ReIndex(ctx context.Context, limit, afterID int64) (map[int64]gomatrixserverlib.HeaderedEvent, error) { +func (d *Database) ReIndex(ctx context.Context, limit, afterID int64) (map[int64]rstypes.HeaderedEvent, error) { return d.OutputEvents.ReIndex(ctx, nil, limit, afterID, []string{ spec.MRoomName, spec.MRoomTopic, @@ -568,7 +569,7 @@ func (d *Database) ReIndex(ctx context.Context, limit, afterID int64) (map[int64 }) } -func (d *Database) UpdateRelations(ctx context.Context, event *gomatrixserverlib.HeaderedEvent) error { +func (d *Database) UpdateRelations(ctx context.Context, event *rstypes.HeaderedEvent) error { // No need to unmarshal if the event is a redaction if event.Type() == spec.MRoomRedaction { return nil diff --git a/syncapi/storage/shared/storage_sync.go b/syncapi/storage/shared/storage_sync.go index f11cbb574..e8ba3e25a 100644 --- a/syncapi/storage/shared/storage_sync.go +++ b/syncapi/storage/shared/storage_sync.go @@ -6,11 +6,11 @@ import ( "fmt" "math" - "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/tidwall/gjson" "github.com/matrix-org/dendrite/internal/eventutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/synctypes" "github.com/matrix-org/dendrite/syncapi/types" userapi "github.com/matrix-org/dendrite/userapi/api" @@ -84,7 +84,7 @@ func (d *DatabaseTransaction) MaxStreamPositionForNotificationData(ctx context.C return types.StreamPosition(id), nil } -func (d *DatabaseTransaction) CurrentState(ctx context.Context, roomID string, stateFilterPart *synctypes.StateFilter, excludeEventIDs []string) ([]*gomatrixserverlib.HeaderedEvent, error) { +func (d *DatabaseTransaction) CurrentState(ctx context.Context, roomID string, stateFilterPart *synctypes.StateFilter, excludeEventIDs []string) ([]*rstypes.HeaderedEvent, error) { return d.CurrentRoomState.SelectCurrentState(ctx, d.txn, roomID, stateFilterPart, excludeEventIDs) } @@ -161,7 +161,7 @@ func (d *DatabaseTransaction) PositionInTopology(ctx context.Context, eventID st return d.Topology.SelectPositionInTopology(ctx, d.txn, eventID) } -func (d *DatabaseTransaction) InviteEventsInRange(ctx context.Context, targetUserID string, r types.Range) (map[string]*gomatrixserverlib.HeaderedEvent, map[string]*gomatrixserverlib.HeaderedEvent, types.StreamPosition, error) { +func (d *DatabaseTransaction) InviteEventsInRange(ctx context.Context, targetUserID string, r types.Range) (map[string]*rstypes.HeaderedEvent, map[string]*rstypes.HeaderedEvent, types.StreamPosition, error) { return d.Invites.SelectInviteEventsInRange(ctx, d.txn, targetUserID, r) } @@ -178,7 +178,7 @@ func (d *DatabaseTransaction) RoomReceiptsAfter(ctx context.Context, roomIDs []s // If an event is not found in the database then it will be omitted from the list. // Returns an error if there was a problem talking with the database. // Does not include any transaction IDs in the returned events. -func (d *DatabaseTransaction) Events(ctx context.Context, eventIDs []string) ([]*gomatrixserverlib.HeaderedEvent, error) { +func (d *DatabaseTransaction) Events(ctx context.Context, eventIDs []string) ([]*rstypes.HeaderedEvent, error) { streamEvents, err := d.OutputEvents.SelectEvents(ctx, d.txn, eventIDs, nil, false) if err != nil { return nil, err @@ -207,13 +207,13 @@ func (d *DatabaseTransaction) SharedUsers(ctx context.Context, userID string, ot func (d *DatabaseTransaction) GetStateEvent( ctx context.Context, roomID, evType, stateKey string, -) (*gomatrixserverlib.HeaderedEvent, error) { +) (*rstypes.HeaderedEvent, error) { return d.CurrentRoomState.SelectStateEvent(ctx, d.txn, roomID, evType, stateKey) } func (d *DatabaseTransaction) GetStateEventsForRoom( ctx context.Context, roomID string, stateFilter *synctypes.StateFilter, -) (stateEvents []*gomatrixserverlib.HeaderedEvent, err error) { +) (stateEvents []*rstypes.HeaderedEvent, err error) { stateEvents, err = d.CurrentRoomState.SelectCurrentState(ctx, d.txn, roomID, stateFilter, nil) return } @@ -302,7 +302,7 @@ func (d *DatabaseTransaction) StreamToTopologicalPosition( // oldest event in the room's topology. func (d *DatabaseTransaction) GetBackwardTopologyPos( ctx context.Context, - events []*gomatrixserverlib.HeaderedEvent, + events []*rstypes.HeaderedEvent, ) (types.TopologyToken, error) { zeroToken := types.TopologyToken{} if len(events) == 0 { diff --git a/syncapi/storage/sqlite3/current_room_state_table.go b/syncapi/storage/sqlite3/current_room_state_table.go index 01dcff693..1b8632eb6 100644 --- a/syncapi/storage/sqlite3/current_room_state_table.go +++ b/syncapi/storage/sqlite3/current_room_state_table.go @@ -25,6 +25,7 @@ import ( "github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage/sqlite3/deltas" "github.com/matrix-org/dendrite/syncapi/storage/tables" "github.com/matrix-org/dendrite/syncapi/synctypes" @@ -268,7 +269,7 @@ func (s *currentRoomStateStatements) SelectCurrentState( ctx context.Context, txn *sql.Tx, roomID string, stateFilter *synctypes.StateFilter, excludeEventIDs []string, -) ([]*gomatrixserverlib.HeaderedEvent, error) { +) ([]*rstypes.HeaderedEvent, error) { // We're going to query members later, so remove them from this request if stateFilter.LazyLoadMembers && !stateFilter.IncludeRedundantMembers { notTypes := &[]string{spec.MRoomMember} @@ -319,7 +320,7 @@ func (s *currentRoomStateStatements) DeleteRoomStateForRoom( func (s *currentRoomStateStatements) UpsertRoomState( ctx context.Context, txn *sql.Tx, - event *gomatrixserverlib.HeaderedEvent, membership *string, addedAt types.StreamPosition, + event *rstypes.HeaderedEvent, membership *string, addedAt types.StreamPosition, ) error { // Parse content as JSON and search for an "url" key containsURL := false @@ -405,8 +406,8 @@ func currentRoomStateRowsToStreamEvents(rows *sql.Rows) ([]types.StreamEvent, er return nil, err } // TODO: Handle redacted events - var ev gomatrixserverlib.HeaderedEvent - if err := ev.UnmarshalJSONWithEventID(eventBytes, eventID); err != nil { + var ev rstypes.HeaderedEvent + if err := json.Unmarshal(eventBytes, &ev); err != nil { return nil, err } @@ -421,8 +422,8 @@ func currentRoomStateRowsToStreamEvents(rows *sql.Rows) ([]types.StreamEvent, er return events, nil } -func rowsToEvents(rows *sql.Rows) ([]*gomatrixserverlib.HeaderedEvent, error) { - result := []*gomatrixserverlib.HeaderedEvent{} +func rowsToEvents(rows *sql.Rows) ([]*rstypes.HeaderedEvent, error) { + result := []*rstypes.HeaderedEvent{} for rows.Next() { var eventID string var eventBytes []byte @@ -430,8 +431,8 @@ func rowsToEvents(rows *sql.Rows) ([]*gomatrixserverlib.HeaderedEvent, error) { return nil, err } // TODO: Handle redacted events - var ev gomatrixserverlib.HeaderedEvent - if err := ev.UnmarshalJSONWithEventID(eventBytes, eventID); err != nil { + var ev rstypes.HeaderedEvent + if err := json.Unmarshal(eventBytes, &ev); err != nil { return nil, err } result = append(result, &ev) @@ -441,7 +442,7 @@ func rowsToEvents(rows *sql.Rows) ([]*gomatrixserverlib.HeaderedEvent, error) { func (s *currentRoomStateStatements) SelectStateEvent( ctx context.Context, txn *sql.Tx, roomID, evType, stateKey string, -) (*gomatrixserverlib.HeaderedEvent, error) { +) (*rstypes.HeaderedEvent, error) { stmt := sqlutil.TxStmt(txn, s.selectStateEventStmt) var res []byte err := stmt.QueryRowContext(ctx, roomID, evType, stateKey).Scan(&res) @@ -451,7 +452,7 @@ func (s *currentRoomStateStatements) SelectStateEvent( if err != nil { return nil, err } - var ev gomatrixserverlib.HeaderedEvent + var ev rstypes.HeaderedEvent if err = json.Unmarshal(res, &ev); err != nil { return nil, err } diff --git a/syncapi/storage/sqlite3/deltas/2022061412000000_history_visibility_column.go b/syncapi/storage/sqlite3/deltas/2022061412000000_history_visibility_column.go index d23f07566..f7ce6531e 100644 --- a/syncapi/storage/sqlite3/deltas/2022061412000000_history_visibility_column.go +++ b/syncapi/storage/sqlite3/deltas/2022061412000000_history_visibility_column.go @@ -20,6 +20,7 @@ import ( "encoding/json" "fmt" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" ) @@ -91,7 +92,7 @@ func currentHistoryVisibilities(ctx context.Context, tx *sql.Tx) (map[string]gom defer rows.Close() // nolint: errcheck var eventBytes []byte var roomID string - var event gomatrixserverlib.HeaderedEvent + var event types.HeaderedEvent var hisVis gomatrixserverlib.HistoryVisibility historyVisibilities := make(map[string]gomatrixserverlib.HistoryVisibility) for rows.Next() { diff --git a/syncapi/storage/sqlite3/invites_table.go b/syncapi/storage/sqlite3/invites_table.go index 19450099a..347523cf7 100644 --- a/syncapi/storage/sqlite3/invites_table.go +++ b/syncapi/storage/sqlite3/invites_table.go @@ -22,9 +22,9 @@ import ( "github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage/tables" "github.com/matrix-org/dendrite/syncapi/types" - "github.com/matrix-org/gomatrixserverlib" ) const inviteEventsSchema = ` @@ -89,7 +89,7 @@ func NewSqliteInvitesTable(db *sql.DB, streamID *StreamIDStatements) (tables.Inv } func (s *inviteEventsStatements) InsertInviteEvent( - ctx context.Context, txn *sql.Tx, inviteEvent *gomatrixserverlib.HeaderedEvent, + ctx context.Context, txn *sql.Tx, inviteEvent *rstypes.HeaderedEvent, ) (streamPos types.StreamPosition, err error) { streamPos, err = s.streamIDStatements.nextInviteID(ctx, txn) if err != nil { @@ -130,7 +130,7 @@ func (s *inviteEventsStatements) DeleteInviteEvent( // active invites for the target user ID in the supplied range. func (s *inviteEventsStatements) SelectInviteEventsInRange( ctx context.Context, txn *sql.Tx, targetUserID string, r types.Range, -) (map[string]*gomatrixserverlib.HeaderedEvent, map[string]*gomatrixserverlib.HeaderedEvent, types.StreamPosition, error) { +) (map[string]*rstypes.HeaderedEvent, map[string]*rstypes.HeaderedEvent, types.StreamPosition, error) { var lastPos types.StreamPosition stmt := sqlutil.TxStmt(txn, s.selectInviteEventsInRangeStmt) rows, err := stmt.QueryContext(ctx, targetUserID, r.Low(), r.High()) @@ -138,8 +138,8 @@ func (s *inviteEventsStatements) SelectInviteEventsInRange( return nil, nil, lastPos, err } defer internal.CloseAndLogIfError(ctx, rows, "selectInviteEventsInRange: rows.close() failed") - result := map[string]*gomatrixserverlib.HeaderedEvent{} - retired := map[string]*gomatrixserverlib.HeaderedEvent{} + result := map[string]*rstypes.HeaderedEvent{} + retired := map[string]*rstypes.HeaderedEvent{} for rows.Next() { var ( id types.StreamPosition @@ -162,7 +162,7 @@ func (s *inviteEventsStatements) SelectInviteEventsInRange( continue } - var event *gomatrixserverlib.HeaderedEvent + var event *rstypes.HeaderedEvent if err := json.Unmarshal(eventJSON, &event); err != nil { return nil, nil, lastPos, err } diff --git a/syncapi/storage/sqlite3/memberships_table.go b/syncapi/storage/sqlite3/memberships_table.go index 2cc46a10a..c09fa1510 100644 --- a/syncapi/storage/sqlite3/memberships_table.go +++ b/syncapi/storage/sqlite3/memberships_table.go @@ -19,9 +19,8 @@ import ( "database/sql" "fmt" - "github.com/matrix-org/gomatrixserverlib" - "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage/tables" "github.com/matrix-org/dendrite/syncapi/types" ) @@ -103,7 +102,7 @@ func NewSqliteMembershipsTable(db *sql.DB) (tables.Memberships, error) { } func (s *membershipsStatements) UpsertMembership( - ctx context.Context, txn *sql.Tx, event *gomatrixserverlib.HeaderedEvent, + ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, streamPos, topologicalPos types.StreamPosition, ) error { membership, err := event.Membership() diff --git a/syncapi/storage/sqlite3/output_room_events_table.go b/syncapi/storage/sqlite3/output_room_events_table.go index b5b6ea883..d63e76067 100644 --- a/syncapi/storage/sqlite3/output_room_events_table.go +++ b/syncapi/storage/sqlite3/output_room_events_table.go @@ -25,6 +25,7 @@ import ( "github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage/sqlite3/deltas" "github.com/matrix-org/dendrite/syncapi/storage/tables" "github.com/matrix-org/dendrite/syncapi/synctypes" @@ -166,7 +167,7 @@ func NewSqliteEventsTable(db *sql.DB, streamID *StreamIDStatements) (tables.Even }.Prepare(db) } -func (s *outputRoomEventsStatements) UpdateEventJSON(ctx context.Context, txn *sql.Tx, event *gomatrixserverlib.HeaderedEvent) error { +func (s *outputRoomEventsStatements) UpdateEventJSON(ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent) error { headeredJSON, err := json.Marshal(event) if err != nil { return err @@ -249,8 +250,8 @@ func (s *outputRoomEventsStatements) SelectStateInRange( } // TODO: Handle redacted events - var ev gomatrixserverlib.HeaderedEvent - if err := ev.UnmarshalJSONWithEventID(eventBytes, eventID); err != nil { + var ev rstypes.HeaderedEvent + if err := json.Unmarshal(eventBytes, &ev); err != nil { return nil, nil, err } needSet := stateNeeded[ev.RoomID()] @@ -296,7 +297,7 @@ func (s *outputRoomEventsStatements) SelectMaxEventID( // of the inserted event. func (s *outputRoomEventsStatements) InsertEvent( ctx context.Context, txn *sql.Tx, - event *gomatrixserverlib.HeaderedEvent, addState, removeState []string, + event *rstypes.HeaderedEvent, addState, removeState []string, transactionID *api.TransactionID, excludeFromSync bool, historyVisibility gomatrixserverlib.HistoryVisibility, ) (types.StreamPosition, error) { var txnID *string @@ -498,8 +499,8 @@ func rowsToStreamEvents(rows *sql.Rows) ([]types.StreamEvent, error) { return nil, err } // TODO: Handle redacted events - var ev gomatrixserverlib.HeaderedEvent - if err := ev.UnmarshalJSONWithEventID(eventBytes, eventID); err != nil { + var ev rstypes.HeaderedEvent + if err := json.Unmarshal(eventBytes, &ev); err != nil { return nil, err } @@ -523,7 +524,7 @@ func rowsToStreamEvents(rows *sql.Rows) ([]types.StreamEvent, error) { } func (s *outputRoomEventsStatements) SelectContextEvent( ctx context.Context, txn *sql.Tx, roomID, eventID string, -) (id int, evt gomatrixserverlib.HeaderedEvent, err error) { +) (id int, evt rstypes.HeaderedEvent, err error) { row := sqlutil.TxStmt(txn, s.selectContextEventStmt).QueryRowContext(ctx, roomID, eventID) var eventAsString string var historyVisibility gomatrixserverlib.HistoryVisibility @@ -540,7 +541,7 @@ func (s *outputRoomEventsStatements) SelectContextEvent( func (s *outputRoomEventsStatements) SelectContextBeforeEvent( ctx context.Context, txn *sql.Tx, id int, roomID string, filter *synctypes.RoomEventFilter, -) (evts []*gomatrixserverlib.HeaderedEvent, err error) { +) (evts []*rstypes.HeaderedEvent, err error) { stmt, params, err := prepareWithFilters( s.db, txn, selectContextBeforeEventSQL, []interface{}{ @@ -564,7 +565,7 @@ func (s *outputRoomEventsStatements) SelectContextBeforeEvent( for rows.Next() { var ( eventBytes []byte - evt *gomatrixserverlib.HeaderedEvent + evt *rstypes.HeaderedEvent historyVisibility gomatrixserverlib.HistoryVisibility ) if err = rows.Scan(&eventBytes, &historyVisibility); err != nil { @@ -582,7 +583,7 @@ func (s *outputRoomEventsStatements) SelectContextBeforeEvent( func (s *outputRoomEventsStatements) SelectContextAfterEvent( ctx context.Context, txn *sql.Tx, id int, roomID string, filter *synctypes.RoomEventFilter, -) (lastID int, evts []*gomatrixserverlib.HeaderedEvent, err error) { +) (lastID int, evts []*rstypes.HeaderedEvent, err error) { stmt, params, err := prepareWithFilters( s.db, txn, selectContextAfterEventSQL, []interface{}{ @@ -606,7 +607,7 @@ func (s *outputRoomEventsStatements) SelectContextAfterEvent( for rows.Next() { var ( eventBytes []byte - evt *gomatrixserverlib.HeaderedEvent + evt *rstypes.HeaderedEvent historyVisibility gomatrixserverlib.HistoryVisibility ) if err = rows.Scan(&lastID, &eventBytes, &historyVisibility); err != nil { @@ -642,7 +643,7 @@ func (s *outputRoomEventsStatements) PurgeEvents( return err } -func (s *outputRoomEventsStatements) ReIndex(ctx context.Context, txn *sql.Tx, limit, afterID int64, types []string) (map[int64]gomatrixserverlib.HeaderedEvent, error) { +func (s *outputRoomEventsStatements) ReIndex(ctx context.Context, txn *sql.Tx, limit, afterID int64, types []string) (map[int64]rstypes.HeaderedEvent, error) { params := make([]interface{}, len(types)+1) params[0] = afterID for i := range types { @@ -664,14 +665,14 @@ func (s *outputRoomEventsStatements) ReIndex(ctx context.Context, txn *sql.Tx, l var eventID string var id int64 - result := make(map[int64]gomatrixserverlib.HeaderedEvent) + result := make(map[int64]rstypes.HeaderedEvent) for rows.Next() { - var ev gomatrixserverlib.HeaderedEvent + var ev rstypes.HeaderedEvent var eventBytes []byte if err = rows.Scan(&id, &eventID, &eventBytes); err != nil { return nil, err } - if err = ev.UnmarshalJSONWithEventID(eventBytes, eventID); err != nil { + if err = json.Unmarshal(eventBytes, &ev); err != nil { return nil, err } result[id] = ev diff --git a/syncapi/storage/sqlite3/output_room_events_topology_table.go b/syncapi/storage/sqlite3/output_room_events_topology_table.go index dc698de2d..68b75f5b1 100644 --- a/syncapi/storage/sqlite3/output_room_events_topology_table.go +++ b/syncapi/storage/sqlite3/output_room_events_topology_table.go @@ -18,9 +18,8 @@ import ( "context" "database/sql" - "github.com/matrix-org/gomatrixserverlib" - "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/storage/tables" "github.com/matrix-org/dendrite/syncapi/types" ) @@ -104,7 +103,7 @@ func NewSqliteTopologyTable(db *sql.DB) (tables.Topology, error) { // insertEventInTopology inserts the given event in the room's topology, based // on the event's depth. func (s *outputRoomEventsTopologyStatements) InsertEventInTopology( - ctx context.Context, txn *sql.Tx, event *gomatrixserverlib.HeaderedEvent, pos types.StreamPosition, + ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, pos types.StreamPosition, ) (types.StreamPosition, error) { _, err := sqlutil.TxStmt(txn, s.insertEventInTopologyStmt).ExecContext( ctx, event.EventID(), event.Depth(), event.RoomID(), pos, diff --git a/syncapi/storage/storage_test.go b/syncapi/storage/storage_test.go index 2cc1378bf..08ca99a76 100644 --- a/syncapi/storage/storage_test.go +++ b/syncapi/storage/storage_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/synctypes" @@ -34,9 +35,9 @@ func MustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, fun return db, close } -func MustWriteEvents(t *testing.T, db storage.Database, events []*gomatrixserverlib.HeaderedEvent) (positions []types.StreamPosition) { +func MustWriteEvents(t *testing.T, db storage.Database, events []*rstypes.HeaderedEvent) (positions []types.StreamPosition) { for _, ev := range events { - var addStateEvents []*gomatrixserverlib.HeaderedEvent + var addStateEvents []*rstypes.HeaderedEvent var addStateEventIDs []string var removeStateEventIDs []string if ev.StateKey() != nil { @@ -106,7 +107,7 @@ func TestRecentEventsPDU(t *testing.T) { To types.StreamPosition Limit int ReverseOrder bool - WantEvents []*gomatrixserverlib.HeaderedEvent + WantEvents []*rstypes.HeaderedEvent WantLimited bool }{ // The purpose of this test is to make sure that incremental syncs are including up to the latest events. @@ -316,7 +317,7 @@ func TestGetEventsInRangeWithEventsSameDepth(t *testing.T) { t.Parallel() db := MustCreateDatabase(t) - var events []*gomatrixserverlib.HeaderedEvent + var events []*types.HeaderedEvent events = append(events, MustCreateEvent(t, testRoomID, nil, &gomatrixserverlib.EventBuilder{ Content: []byte(fmt.Sprintf(`{"room_version":"4","creator":"%s"}`, testUserIDA)), Type: "m.room.create", @@ -324,7 +325,7 @@ func TestGetEventsInRangeWithEventsSameDepth(t *testing.T) { Sender: testUserIDA, Depth: int64(len(events) + 1), })) - events = append(events, MustCreateEvent(t, testRoomID, []*gomatrixserverlib.HeaderedEvent{events[len(events)-1]}, &gomatrixserverlib.EventBuilder{ + events = append(events, MustCreateEvent(t, testRoomID, []*types.HeaderedEvent{events[len(events)-1]}, &gomatrixserverlib.EventBuilder{ Content: []byte(`{"membership":"join"}`), Type: "m.room.member", StateKey: &testUserIDA, @@ -332,7 +333,7 @@ func TestGetEventsInRangeWithEventsSameDepth(t *testing.T) { Depth: int64(len(events) + 1), })) // fork the dag into three, same prev_events and depth - parent := []*gomatrixserverlib.HeaderedEvent{events[len(events)-1]} + parent := []*types.HeaderedEvent{events[len(events)-1]} depth := int64(len(events) + 1) for i := 0; i < 3; i++ { events = append(events, MustCreateEvent(t, testRoomID, parent, &gomatrixserverlib.EventBuilder{ @@ -365,7 +366,7 @@ func TestGetEventsInRangeWithEventsSameDepth(t *testing.T) { Name string From types.TopologyToken Limit int - Wants []*gomatrixserverlib.HeaderedEvent + Wants []*types.HeaderedEvent }{ { Name: "Pagination over the whole fork", @@ -406,7 +407,7 @@ func TestGetEventsInTopologicalRangeMultiRoom(t *testing.T) { t.Parallel() db := MustCreateDatabase(t) - makeEvents := func(roomID string) (events []*gomatrixserverlib.HeaderedEvent) { + makeEvents := func(roomID string) (events []*types.HeaderedEvent) { events = append(events, MustCreateEvent(t, roomID, nil, &gomatrixserverlib.EventBuilder{ Content: []byte(fmt.Sprintf(`{"room_version":"4","creator":"%s"}`, testUserIDA)), Type: "m.room.create", @@ -414,7 +415,7 @@ func TestGetEventsInTopologicalRangeMultiRoom(t *testing.T) { Sender: testUserIDA, Depth: int64(len(events) + 1), })) - events = append(events, MustCreateEvent(t, roomID, []*gomatrixserverlib.HeaderedEvent{events[len(events)-1]}, &gomatrixserverlib.EventBuilder{ + events = append(events, MustCreateEvent(t, roomID, []*types.HeaderedEvent{events[len(events)-1]}, &gomatrixserverlib.EventBuilder{ Content: []byte(`{"membership":"join"}`), Type: "m.room.member", StateKey: &testUserIDA, @@ -460,14 +461,14 @@ func TestGetEventsInRangeWithEventsInsertedLikeBackfill(t *testing.T) { // "federation" join userC := fmt.Sprintf("@radiance:%s", testOrigin) - joinEvent := MustCreateEvent(t, testRoomID, []*gomatrixserverlib.HeaderedEvent{events[len(events)-1]}, &gomatrixserverlib.EventBuilder{ + joinEvent := MustCreateEvent(t, testRoomID, []*types.HeaderedEvent{events[len(events)-1]}, &gomatrixserverlib.EventBuilder{ Content: []byte(`{"membership":"join"}`), Type: "m.room.member", StateKey: &userC, Sender: userC, Depth: int64(len(events) + 1), }) - MustWriteEvents(t, db, []*gomatrixserverlib.HeaderedEvent{joinEvent}) + MustWriteEvents(t, db, []*types.HeaderedEvent{joinEvent}) // Sync will return this for the prev_batch from := topologyTokenBefore(t, db, joinEvent.EventID()) @@ -638,7 +639,7 @@ func TestInviteBehaviour(t *testing.T) { StateKey: &testUserIDA, Sender: "@inviteUser2:somewhere", }) - for _, ev := range []*gomatrixserverlib.HeaderedEvent{inviteEvent1, inviteEvent2} { + for _, ev := range []*types.HeaderedEvent{inviteEvent1, inviteEvent2} { _, err := db.AddInviteEvent(ctx, ev) if err != nil { t.Fatalf("Failed to AddInviteEvent: %s", err) @@ -695,7 +696,7 @@ func assertInvitedToRooms(t *testing.T, res *types.Response, roomIDs []string) { } } -func assertEventsEqual(t *testing.T, msg string, checkRoomID bool, gots []gomatrixserverlib.ClientEvent, wants []*gomatrixserverlib.HeaderedEvent) { +func assertEventsEqual(t *testing.T, msg string, checkRoomID bool, gots []gomatrixserverlib.ClientEvent, wants []*types.HeaderedEvent) { t.Helper() if len(gots) != len(wants) { t.Fatalf("%s response returned %d events, want %d", msg, len(gots), len(wants)) diff --git a/syncapi/storage/tables/interface.go b/syncapi/storage/tables/interface.go index 6384fb914..854292bd2 100644 --- a/syncapi/storage/tables/interface.go +++ b/syncapi/storage/tables/interface.go @@ -23,6 +23,7 @@ import ( "github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/synctypes" "github.com/matrix-org/dendrite/syncapi/types" ) @@ -35,11 +36,11 @@ type AccountData interface { } type Invites interface { - InsertInviteEvent(ctx context.Context, txn *sql.Tx, inviteEvent *gomatrixserverlib.HeaderedEvent) (streamPos types.StreamPosition, err error) + InsertInviteEvent(ctx context.Context, txn *sql.Tx, inviteEvent *rstypes.HeaderedEvent) (streamPos types.StreamPosition, err error) DeleteInviteEvent(ctx context.Context, txn *sql.Tx, inviteEventID string) (types.StreamPosition, error) // SelectInviteEventsInRange returns a map of room ID to invite events. If multiple invite/retired invites exist in the given range, return the latest value // for the room. - SelectInviteEventsInRange(ctx context.Context, txn *sql.Tx, targetUserID string, r types.Range) (invites map[string]*gomatrixserverlib.HeaderedEvent, retired map[string]*gomatrixserverlib.HeaderedEvent, maxID types.StreamPosition, err error) + SelectInviteEventsInRange(ctx context.Context, txn *sql.Tx, targetUserID string, r types.Range) (invites map[string]*rstypes.HeaderedEvent, retired map[string]*rstypes.HeaderedEvent, maxID types.StreamPosition, err error) SelectMaxInviteID(ctx context.Context, txn *sql.Tx) (id int64, err error) PurgeInvites(ctx context.Context, txn *sql.Tx, roomID string) error } @@ -59,7 +60,7 @@ type Events interface { SelectMaxEventID(ctx context.Context, txn *sql.Tx) (id int64, err error) InsertEvent( ctx context.Context, txn *sql.Tx, - event *gomatrixserverlib.HeaderedEvent, + event *rstypes.HeaderedEvent, addState, removeState []string, transactionID *api.TransactionID, excludeFromSync bool, @@ -70,16 +71,16 @@ type Events interface { // Returns up to `limit` events. Returns `limited=true` if there are more events in this range but we hit the `limit`. SelectRecentEvents(ctx context.Context, txn *sql.Tx, roomIDs []string, r types.Range, eventFilter *synctypes.RoomEventFilter, chronologicalOrder bool, onlySyncEvents bool) (map[string]types.RecentEvents, error) SelectEvents(ctx context.Context, txn *sql.Tx, eventIDs []string, filter *synctypes.RoomEventFilter, preserveOrder bool) ([]types.StreamEvent, error) - UpdateEventJSON(ctx context.Context, txn *sql.Tx, event *gomatrixserverlib.HeaderedEvent) error + UpdateEventJSON(ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent) error // DeleteEventsForRoom removes all event information for a room. This should only be done when removing the room entirely. DeleteEventsForRoom(ctx context.Context, txn *sql.Tx, roomID string) (err error) - SelectContextEvent(ctx context.Context, txn *sql.Tx, roomID, eventID string) (int, gomatrixserverlib.HeaderedEvent, error) - SelectContextBeforeEvent(ctx context.Context, txn *sql.Tx, id int, roomID string, filter *synctypes.RoomEventFilter) ([]*gomatrixserverlib.HeaderedEvent, error) - SelectContextAfterEvent(ctx context.Context, txn *sql.Tx, id int, roomID string, filter *synctypes.RoomEventFilter) (int, []*gomatrixserverlib.HeaderedEvent, error) + SelectContextEvent(ctx context.Context, txn *sql.Tx, roomID, eventID string) (int, rstypes.HeaderedEvent, error) + SelectContextBeforeEvent(ctx context.Context, txn *sql.Tx, id int, roomID string, filter *synctypes.RoomEventFilter) ([]*rstypes.HeaderedEvent, error) + SelectContextAfterEvent(ctx context.Context, txn *sql.Tx, id int, roomID string, filter *synctypes.RoomEventFilter) (int, []*rstypes.HeaderedEvent, error) PurgeEvents(ctx context.Context, txn *sql.Tx, roomID string) error - ReIndex(ctx context.Context, txn *sql.Tx, limit, offset int64, types []string) (map[int64]gomatrixserverlib.HeaderedEvent, error) + ReIndex(ctx context.Context, txn *sql.Tx, limit, offset int64, types []string) (map[int64]rstypes.HeaderedEvent, error) } // Topology keeps track of the depths and stream positions for all events. @@ -87,7 +88,7 @@ type Events interface { type Topology interface { // InsertEventInTopology inserts the given event in the room's topology, based on the event's depth. // `pos` is the stream position of this event in the events table, and is used to order events which have the same depth. - InsertEventInTopology(ctx context.Context, txn *sql.Tx, event *gomatrixserverlib.HeaderedEvent, pos types.StreamPosition) (topoPos types.StreamPosition, err error) + InsertEventInTopology(ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, pos types.StreamPosition) (topoPos types.StreamPosition, err error) // SelectEventIDsInRange selects the IDs of events whose depths are within a given range in a given room's topological order. // Events with `minDepth` are *exclusive*, as is the event which has exactly `minDepth`,`maxStreamPos`. // `maxStreamPos` is only used when events have the same depth as `maxDepth`, which results in events less than `maxStreamPos` being returned. @@ -101,13 +102,13 @@ type Topology interface { } type CurrentRoomState interface { - SelectStateEvent(ctx context.Context, txn *sql.Tx, roomID, evType, stateKey string) (*gomatrixserverlib.HeaderedEvent, error) + SelectStateEvent(ctx context.Context, txn *sql.Tx, roomID, evType, stateKey string) (*rstypes.HeaderedEvent, error) SelectEventsWithEventIDs(ctx context.Context, txn *sql.Tx, eventIDs []string) ([]types.StreamEvent, error) - UpsertRoomState(ctx context.Context, txn *sql.Tx, event *gomatrixserverlib.HeaderedEvent, membership *string, addedAt types.StreamPosition) error + UpsertRoomState(ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, membership *string, addedAt types.StreamPosition) error DeleteRoomStateByEventID(ctx context.Context, txn *sql.Tx, eventID string) error DeleteRoomStateForRoom(ctx context.Context, txn *sql.Tx, roomID string) error // SelectCurrentState returns all the current state events for the given room. - SelectCurrentState(ctx context.Context, txn *sql.Tx, roomID string, stateFilter *synctypes.StateFilter, excludeEventIDs []string) ([]*gomatrixserverlib.HeaderedEvent, error) + SelectCurrentState(ctx context.Context, txn *sql.Tx, roomID string, stateFilter *synctypes.StateFilter, excludeEventIDs []string) ([]*rstypes.HeaderedEvent, error) // SelectRoomIDsWithMembership returns the list of room IDs which have the given user in the given membership state. SelectRoomIDsWithMembership(ctx context.Context, txn *sql.Tx, userID string, membership string) ([]string, error) // SelectRoomIDsWithAnyMembership returns a map of all memberships for the given user. @@ -191,7 +192,7 @@ type Receipts interface { } type Memberships interface { - UpsertMembership(ctx context.Context, txn *sql.Tx, event *gomatrixserverlib.HeaderedEvent, streamPos, topologicalPos types.StreamPosition) error + UpsertMembership(ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, streamPos, topologicalPos types.StreamPosition) error SelectMembershipCount(ctx context.Context, txn *sql.Tx, roomID, membership string, pos types.StreamPosition) (count int, err error) SelectMembershipForUser(ctx context.Context, txn *sql.Tx, roomID, userID string, pos int64) (membership string, topologicalPos int, err error) PurgeMemberships(ctx context.Context, txn *sql.Tx, roomID string) error diff --git a/syncapi/storage/tables/memberships_test.go b/syncapi/storage/tables/memberships_test.go index 2e8375c3d..4afa2ac5b 100644 --- a/syncapi/storage/tables/memberships_test.go +++ b/syncapi/storage/tables/memberships_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" - "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/dendrite/internal/sqlutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/syncapi/storage/postgres" "github.com/matrix-org/dendrite/syncapi/storage/sqlite3" @@ -47,7 +47,7 @@ func TestMembershipsTable(t *testing.T) { room := test.NewRoom(t, alice) // Create users - var userEvents []*gomatrixserverlib.HeaderedEvent + var userEvents []*rstypes.HeaderedEvent users := []string{alice.ID} for _, x := range room.CurrentState() { if x.StateKeyEquals(alice.ID) { @@ -114,7 +114,7 @@ func testMembershipCount(t *testing.T, ctx context.Context, table tables.Members }) } -func testUpsert(t *testing.T, ctx context.Context, table tables.Memberships, membershipEvent *gomatrixserverlib.HeaderedEvent, user *test.User, room *test.Room) { +func testUpsert(t *testing.T, ctx context.Context, table tables.Memberships, membershipEvent *rstypes.HeaderedEvent, user *test.User, room *test.Room) { t.Run("upserting works as expected", func(t *testing.T) { if err := table.UpsertMembership(ctx, nil, membershipEvent, 1, 1); err != nil { t.Fatalf("failed to upsert membership: %s", err) diff --git a/syncapi/streams/stream_pdu.go b/syncapi/streams/stream_pdu.go index 41c584812..b5fd5be8e 100644 --- a/syncapi/streams/stream_pdu.go +++ b/syncapi/streams/stream_pdu.go @@ -8,6 +8,7 @@ import ( "github.com/matrix-org/dendrite/internal/caching" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/internal" "github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/synctypes" @@ -273,10 +274,14 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse( recentStreamEvents := dbEvents[delta.RoomID].Events limited := dbEvents[delta.RoomID].Limited - recentEvents := gomatrixserverlib.HeaderedReverseTopologicalOrdering( - snapshot.StreamEventsToEvents(device, recentStreamEvents), + recEvents := gomatrixserverlib.ReverseTopologicalOrdering( + gomatrixserverlib.ToPDUs(snapshot.StreamEventsToEvents(device, recentStreamEvents)), gomatrixserverlib.TopologicalOrderByPrevEvents, ) + recentEvents := make([]*rstypes.HeaderedEvent, len(recEvents)) + for i := range recEvents { + recentEvents[i] = recEvents[i].(*rstypes.HeaderedEvent) + } // If we didn't return any events at all then don't bother doing anything else. if len(recentEvents) == 0 && len(delta.StateEvents) == 0 { @@ -341,10 +346,14 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse( // Now that we've filtered the timeline, work out which state events are still // left. Anything that appears in the filtered timeline will be removed from the // "state" section and kept in "timeline". - delta.StateEvents = gomatrixserverlib.HeaderedReverseTopologicalOrdering( - removeDuplicates(delta.StateEvents, events), + sEvents := gomatrixserverlib.HeaderedReverseTopologicalOrdering( + gomatrixserverlib.ToPDUs(removeDuplicates(delta.StateEvents, events)), gomatrixserverlib.TopologicalOrderByAuthEvents, ) + delta.StateEvents = make([]*rstypes.HeaderedEvent, len(sEvents)) + for i := range sEvents { + delta.StateEvents[i] = sEvents[i].(*rstypes.HeaderedEvent) + } if len(delta.StateEvents) > 0 { if last := delta.StateEvents[len(delta.StateEvents)-1]; last != nil { @@ -367,20 +376,20 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse( } } jr.Timeline.PrevBatch = &prevBatch - jr.Timeline.Events = synctypes.HeaderedToClientEvents(events, synctypes.FormatSync) + jr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), synctypes.FormatSync) // If we are limited by the filter AND the history visibility filter // didn't "remove" events, return that the response is limited. jr.Timeline.Limited = (limited && len(events) == len(recentEvents)) || delta.NewlyJoined - jr.State.Events = synctypes.HeaderedToClientEvents(delta.StateEvents, synctypes.FormatSync) + jr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(delta.StateEvents), synctypes.FormatSync) req.Response.Rooms.Join[delta.RoomID] = jr case spec.Peek: jr := types.NewJoinResponse() jr.Timeline.PrevBatch = &prevBatch // TODO: Apply history visibility on peeked rooms - jr.Timeline.Events = synctypes.HeaderedToClientEvents(recentEvents, synctypes.FormatSync) + jr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(recentEvents), synctypes.FormatSync) jr.Timeline.Limited = limited - jr.State.Events = synctypes.HeaderedToClientEvents(delta.StateEvents, synctypes.FormatSync) + jr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(delta.StateEvents), synctypes.FormatSync) req.Response.Rooms.Peek[delta.RoomID] = jr case spec.Leave: @@ -389,11 +398,11 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse( case spec.Ban: lr := types.NewLeaveResponse() lr.Timeline.PrevBatch = &prevBatch - lr.Timeline.Events = synctypes.HeaderedToClientEvents(events, synctypes.FormatSync) + lr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), synctypes.FormatSync) // If we are limited by the filter AND the history visibility filter // didn't "remove" events, return that the response is limited. lr.Timeline.Limited = limited && len(events) == len(recentEvents) - lr.State.Events = synctypes.HeaderedToClientEvents(delta.StateEvents, synctypes.FormatSync) + lr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(delta.StateEvents), synctypes.FormatSync) req.Response.Rooms.Leave[delta.RoomID] = lr } @@ -407,8 +416,8 @@ func applyHistoryVisibilityFilter( snapshot storage.DatabaseTransaction, rsAPI roomserverAPI.SyncRoomserverAPI, roomID, userID string, - recentEvents []*gomatrixserverlib.HeaderedEvent, -) ([]*gomatrixserverlib.HeaderedEvent, error) { + recentEvents []*rstypes.HeaderedEvent, +) ([]*rstypes.HeaderedEvent, error) { // We need to make sure we always include the latest state events, if they are in the timeline. alwaysIncludeIDs := make(map[string]struct{}) var stateTypes []string @@ -543,11 +552,11 @@ func (p *PDUStreamProvider) getJoinResponseForCompleteSync( } jr.Timeline.PrevBatch = prevBatch - jr.Timeline.Events = synctypes.HeaderedToClientEvents(events, synctypes.FormatSync) + jr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), synctypes.FormatSync) // If we are limited by the filter AND the history visibility filter // didn't "remove" events, return that the response is limited. jr.Timeline.Limited = limited && len(events) == len(recentEvents) - jr.State.Events = synctypes.HeaderedToClientEvents(stateEvents, synctypes.FormatSync) + jr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(stateEvents), synctypes.FormatSync) return jr, nil } @@ -555,8 +564,8 @@ func (p *PDUStreamProvider) lazyLoadMembers( ctx context.Context, snapshot storage.DatabaseTransaction, roomID string, incremental, limited bool, stateFilter *synctypes.StateFilter, device *userapi.Device, - timelineEvents, stateEvents []*gomatrixserverlib.HeaderedEvent, -) ([]*gomatrixserverlib.HeaderedEvent, error) { + timelineEvents, stateEvents []*rstypes.HeaderedEvent, +) ([]*rstypes.HeaderedEvent, error) { if len(timelineEvents) == 0 { return stateEvents, nil } @@ -573,7 +582,7 @@ func (p *PDUStreamProvider) lazyLoadMembers( } } // Preallocate with the same amount, even if it will end up with fewer values - newStateEvents := make([]*gomatrixserverlib.HeaderedEvent, 0, len(stateEvents)) + newStateEvents := make([]*rstypes.HeaderedEvent, 0, len(stateEvents)) // Remove existing membership events we don't care about, e.g. users not in the timeline.events for _, event := range stateEvents { if event.Type() == spec.MRoomMember && event.StateKey() != nil { @@ -633,7 +642,7 @@ func (p *PDUStreamProvider) addIgnoredUsersToFilter(ctx context.Context, snapsho return nil } -func removeDuplicates(stateEvents, recentEvents []*gomatrixserverlib.HeaderedEvent) []*gomatrixserverlib.HeaderedEvent { +func removeDuplicates[T gomatrixserverlib.PDU](stateEvents, recentEvents []T) []T { for _, recentEv := range recentEvents { if recentEv.StateKey() == nil { continue // not a state event diff --git a/syncapi/syncapi_test.go b/syncapi/syncapi_test.go index c120f8828..bc766e663 100644 --- a/syncapi/syncapi_test.go +++ b/syncapi/syncapi_test.go @@ -19,6 +19,7 @@ import ( "github.com/nats-io/nats.go" "github.com/tidwall/gjson" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/routing" "github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/synctypes" @@ -490,7 +491,7 @@ func testHistoryVisibility(t *testing.T, dbType test.DBType) { afterJoinBody := fmt.Sprintf("After join in a %s room", tc.historyVisibility) msgEv := room.CreateAndInsert(t, alice, "m.room.message", map[string]interface{}{"body": afterJoinBody}) - eventsToSend = append([]*gomatrixserverlib.HeaderedEvent{}, inviteEv, afterInviteEv, joinEv, msgEv) + eventsToSend = append([]*rstypes.HeaderedEvent{}, inviteEv, afterInviteEv, joinEv, msgEv) if err := api.SendEvents(ctx, rsAPI, api.KindNew, eventsToSend, "test", "test", "test", nil, false); err != nil { t.Fatalf("failed to send events: %v", err) @@ -523,7 +524,7 @@ func testHistoryVisibility(t *testing.T, dbType test.DBType) { } } -func verifyEventVisible(t *testing.T, wantVisible bool, wantVisibleEvent *gomatrixserverlib.HeaderedEvent, chunk []synctypes.ClientEvent) { +func verifyEventVisible(t *testing.T, wantVisible bool, wantVisibleEvent *rstypes.HeaderedEvent, chunk []synctypes.ClientEvent) { t.Helper() if wantVisible { for _, ev := range chunk { @@ -1228,7 +1229,7 @@ func syncUntil(t *testing.T, } } -func toNATSMsgs(t *testing.T, cfg *config.Dendrite, input ...*gomatrixserverlib.HeaderedEvent) []*nats.Msg { +func toNATSMsgs(t *testing.T, cfg *config.Dendrite, input ...*rstypes.HeaderedEvent) []*nats.Msg { result := make([]*nats.Msg, len(input)) for i, ev := range input { var addsStateIDs []string diff --git a/syncapi/synctypes/clientevent.go b/syncapi/synctypes/clientevent.go index 0bf04cdb9..c722fe60a 100644 --- a/syncapi/synctypes/clientevent.go +++ b/syncapi/synctypes/clientevent.go @@ -44,7 +44,7 @@ type ClientEvent struct { } // ToClientEvents converts server events to client events. -func ToClientEvents(serverEvs []*gomatrixserverlib.Event, format ClientEventFormat) []ClientEvent { +func ToClientEvents(serverEvs []gomatrixserverlib.PDU, format ClientEventFormat) []ClientEvent { evs := make([]ClientEvent, 0, len(serverEvs)) for _, se := range serverEvs { if se == nil { @@ -55,20 +55,8 @@ func ToClientEvents(serverEvs []*gomatrixserverlib.Event, format ClientEventForm return evs } -// HeaderedToClientEvents converts headered server events to client events. -func HeaderedToClientEvents(serverEvs []*gomatrixserverlib.HeaderedEvent, format ClientEventFormat) []ClientEvent { - evs := make([]ClientEvent, 0, len(serverEvs)) - for _, se := range serverEvs { - if se == nil { - continue // TODO: shouldn't happen? - } - evs = append(evs, HeaderedToClientEvent(se, format)) - } - return evs -} - // ToClientEvent converts a single server event to a client event. -func ToClientEvent(se *gomatrixserverlib.Event, format ClientEventFormat) ClientEvent { +func ToClientEvent(se gomatrixserverlib.PDU, format ClientEventFormat) ClientEvent { ce := ClientEvent{ Content: spec.RawJSON(se.Content()), Sender: se.Sender(), @@ -84,8 +72,3 @@ func ToClientEvent(se *gomatrixserverlib.Event, format ClientEventFormat) Client } return ce } - -// HeaderedToClientEvent converts a single headered server event to a client event. -func HeaderedToClientEvent(se *gomatrixserverlib.HeaderedEvent, format ClientEventFormat) ClientEvent { - return ToClientEvent(se.Event, format) -} diff --git a/syncapi/types/types.go b/syncapi/types/types.go index ed17eb560..983bf48a3 100644 --- a/syncapi/types/types.go +++ b/syncapi/types/types.go @@ -26,6 +26,7 @@ import ( "github.com/tidwall/gjson" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/synctypes" ) @@ -38,7 +39,7 @@ var ( type StateDelta struct { RoomID string - StateEvents []*gomatrixserverlib.HeaderedEvent + StateEvents []*types.HeaderedEvent NewlyJoined bool Membership string // The PDU stream position of the latest membership event for this user, if applicable. @@ -59,7 +60,7 @@ func NewStreamPositionFromString(s string) (StreamPosition, error) { // StreamEvent is the same as gomatrixserverlib.Event but also has the PDU stream position for this event. type StreamEvent struct { - *gomatrixserverlib.HeaderedEvent + *types.HeaderedEvent StreamPosition StreamPosition TransactionID *api.TransactionID ExcludeFromSync bool @@ -538,7 +539,7 @@ type InviteResponse struct { } // NewInviteResponse creates an empty response with initialised arrays. -func NewInviteResponse(event *gomatrixserverlib.HeaderedEvent) *InviteResponse { +func NewInviteResponse(event *types.HeaderedEvent) *InviteResponse { res := InviteResponse{} res.InviteState.Events = []json.RawMessage{} @@ -551,7 +552,7 @@ func NewInviteResponse(event *gomatrixserverlib.HeaderedEvent) *InviteResponse { // Then we'll see if we can create a partial of the invite event itself. // This is needed for clients to work out *who* sent the invite. - inviteEvent := synctypes.ToClientEvent(event.Unwrap(), synctypes.FormatSync) + inviteEvent := synctypes.ToClientEvent(event.Event, synctypes.FormatSync) inviteEvent.Unsigned = nil if ev, err := json.Marshal(inviteEvent); err == nil { res.InviteState.Events = append(res.InviteState.Events, ev) diff --git a/syncapi/types/types_test.go b/syncapi/types/types_test.go index a864c6f4d..60ff02bd4 100644 --- a/syncapi/types/types_test.go +++ b/syncapi/types/types_test.go @@ -5,6 +5,7 @@ import ( "reflect" "testing" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/syncapi/synctypes" "github.com/matrix-org/gomatrixserverlib" ) @@ -55,7 +56,7 @@ func TestNewInviteResponse(t *testing.T) { t.Fatal(err) } - res := NewInviteResponse(ev.Headered(gomatrixserverlib.RoomVersionV5)) + res := NewInviteResponse(&types.HeaderedEvent{Event: ev}) j, err := json.Marshal(res) if err != nil { t.Fatal(err) diff --git a/test/event.go b/test/event.go index 77c44700c..197f80e13 100644 --- a/test/event.go +++ b/test/event.go @@ -20,6 +20,7 @@ import ( "testing" "time" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" ) @@ -79,15 +80,15 @@ func WithOrigin(origin spec.ServerName) eventModifier { } // Reverse a list of events -func Reversed(in []*gomatrixserverlib.HeaderedEvent) []*gomatrixserverlib.HeaderedEvent { - out := make([]*gomatrixserverlib.HeaderedEvent, len(in)) +func Reversed(in []*types.HeaderedEvent) []*types.HeaderedEvent { + out := make([]*types.HeaderedEvent, len(in)) for i := 0; i < len(in); i++ { out[i] = in[len(in)-i-1] } return out } -func AssertEventIDsEqual(t *testing.T, gotEventIDs []string, wants []*gomatrixserverlib.HeaderedEvent) { +func AssertEventIDsEqual(t *testing.T, gotEventIDs []string, wants []*types.HeaderedEvent) { t.Helper() if len(gotEventIDs) != len(wants) { t.Errorf("length mismatch: got %d events, want %d", len(gotEventIDs), len(wants)) @@ -102,7 +103,7 @@ func AssertEventIDsEqual(t *testing.T, gotEventIDs []string, wants []*gomatrixse } } -func AssertEventsEqual(t *testing.T, gots, wants []*gomatrixserverlib.HeaderedEvent) { +func AssertEventsEqual(t *testing.T, gots, wants []*types.HeaderedEvent) { t.Helper() if len(gots) != len(wants) { t.Fatalf("length mismatch: got %d events, want %d", len(gots), len(wants)) diff --git a/test/memory_federation_db.go b/test/memory_federation_db.go index c29162fe1..76034143f 100644 --- a/test/memory_federation_db.go +++ b/test/memory_federation_db.go @@ -23,6 +23,7 @@ import ( "github.com/matrix-org/dendrite/federationapi/storage/shared/receipt" "github.com/matrix-org/dendrite/federationapi/types" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" ) @@ -36,7 +37,7 @@ type InMemoryFederationDatabase struct { pendingEDUServers map[spec.ServerName]struct{} blacklistedServers map[spec.ServerName]struct{} assumedOffline map[spec.ServerName]struct{} - pendingPDUs map[*receipt.Receipt]*gomatrixserverlib.HeaderedEvent + pendingPDUs map[*receipt.Receipt]*rstypes.HeaderedEvent pendingEDUs map[*receipt.Receipt]*gomatrixserverlib.EDU associatedPDUs map[spec.ServerName]map[*receipt.Receipt]struct{} associatedEDUs map[spec.ServerName]map[*receipt.Receipt]struct{} @@ -49,7 +50,7 @@ func NewInMemoryFederationDatabase() *InMemoryFederationDatabase { pendingEDUServers: make(map[spec.ServerName]struct{}), blacklistedServers: make(map[spec.ServerName]struct{}), assumedOffline: make(map[spec.ServerName]struct{}), - pendingPDUs: make(map[*receipt.Receipt]*gomatrixserverlib.HeaderedEvent), + pendingPDUs: make(map[*receipt.Receipt]*rstypes.HeaderedEvent), pendingEDUs: make(map[*receipt.Receipt]*gomatrixserverlib.EDU), associatedPDUs: make(map[spec.ServerName]map[*receipt.Receipt]struct{}), associatedEDUs: make(map[spec.ServerName]map[*receipt.Receipt]struct{}), @@ -64,7 +65,7 @@ func (d *InMemoryFederationDatabase) StoreJSON( d.dbMutex.Lock() defer d.dbMutex.Unlock() - var event gomatrixserverlib.HeaderedEvent + var event rstypes.HeaderedEvent if err := json.Unmarshal([]byte(js), &event); err == nil { nidMutex.Lock() defer nidMutex.Unlock() @@ -91,12 +92,12 @@ func (d *InMemoryFederationDatabase) GetPendingPDUs( ctx context.Context, serverName spec.ServerName, limit int, -) (pdus map[*receipt.Receipt]*gomatrixserverlib.HeaderedEvent, err error) { +) (pdus map[*receipt.Receipt]*rstypes.HeaderedEvent, err error) { d.dbMutex.Lock() defer d.dbMutex.Unlock() pduCount := 0 - pdus = make(map[*receipt.Receipt]*gomatrixserverlib.HeaderedEvent) + pdus = make(map[*receipt.Receipt]*rstypes.HeaderedEvent) if receipts, ok := d.associatedPDUs[serverName]; ok { for dbReceipt := range receipts { if event, ok := d.pendingPDUs[dbReceipt]; ok { diff --git a/test/room.go b/test/room.go index 0d80a5940..140c100ed 100644 --- a/test/room.go +++ b/test/room.go @@ -25,6 +25,7 @@ import ( "github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/dendrite/internal/eventutil" + rstypes "github.com/matrix-org/dendrite/roomserver/types" ) type Preset int @@ -47,8 +48,8 @@ type Room struct { creator *User authEvents gomatrixserverlib.AuthEvents - currentState map[string]*gomatrixserverlib.HeaderedEvent - events []*gomatrixserverlib.HeaderedEvent + currentState map[string]*rstypes.HeaderedEvent + events []*rstypes.HeaderedEvent } // Create a new test room. Automatically creates the initial create events. @@ -64,7 +65,7 @@ func NewRoom(t *testing.T, creator *User, modifiers ...roomModifier) *Room { authEvents: gomatrixserverlib.NewAuthEvents(nil), preset: PresetPublicChat, Version: gomatrixserverlib.RoomVersionV9, - currentState: make(map[string]*gomatrixserverlib.HeaderedEvent), + currentState: make(map[string]*rstypes.HeaderedEvent), visibility: gomatrixserverlib.HistoryVisibilityShared, } for _, m := range modifiers { @@ -130,7 +131,7 @@ func (r *Room) insertCreateEvents(t *testing.T) { } // Create an event in this room but do not insert it. Does not modify the room in any way (depth, fwd extremities, etc) so is thread-safe. -func (r *Room) CreateEvent(t *testing.T, creator *User, eventType string, content interface{}, mods ...eventModifier) *gomatrixserverlib.HeaderedEvent { +func (r *Room) CreateEvent(t *testing.T, creator *User, eventType string, content interface{}, mods ...eventModifier) *rstypes.HeaderedEvent { t.Helper() depth := 1 + len(r.events) // depth starts at 1 @@ -203,18 +204,18 @@ func (r *Room) CreateEvent(t *testing.T, creator *User, eventType string, conten if err = gomatrixserverlib.Allowed(ev, &r.authEvents); err != nil { t.Fatalf("CreateEvent[%s]: failed to verify event was allowed: %s", eventType, err) } - headeredEvent := ev.Headered(r.Version) + headeredEvent := &rstypes.HeaderedEvent{Event: ev} headeredEvent.Visibility = r.visibility return headeredEvent } // Add a new event to this room DAG. Not thread-safe. -func (r *Room) InsertEvent(t *testing.T, he *gomatrixserverlib.HeaderedEvent) { +func (r *Room) InsertEvent(t *testing.T, he *rstypes.HeaderedEvent) { t.Helper() // Add the event to the list of auth/state events r.events = append(r.events, he) if he.StateKey() != nil { - err := r.authEvents.AddEvent(he.Unwrap()) + err := r.authEvents.AddEvent(he.Event) if err != nil { t.Fatalf("InsertEvent: failed to add event to auth events: %s", err) } @@ -222,12 +223,12 @@ func (r *Room) InsertEvent(t *testing.T, he *gomatrixserverlib.HeaderedEvent) { } } -func (r *Room) Events() []*gomatrixserverlib.HeaderedEvent { +func (r *Room) Events() []*rstypes.HeaderedEvent { return r.events } -func (r *Room) CurrentState() []*gomatrixserverlib.HeaderedEvent { - events := make([]*gomatrixserverlib.HeaderedEvent, len(r.currentState)) +func (r *Room) CurrentState() []*rstypes.HeaderedEvent { + events := make([]*rstypes.HeaderedEvent, len(r.currentState)) i := 0 for _, e := range r.currentState { events[i] = e @@ -236,7 +237,7 @@ func (r *Room) CurrentState() []*gomatrixserverlib.HeaderedEvent { return events } -func (r *Room) CreateAndInsert(t *testing.T, creator *User, eventType string, content interface{}, mods ...eventModifier) *gomatrixserverlib.HeaderedEvent { +func (r *Room) CreateAndInsert(t *testing.T, creator *User, eventType string, content interface{}, mods ...eventModifier) *rstypes.HeaderedEvent { t.Helper() he := r.CreateEvent(t, creator, eventType, content, mods...) r.InsertEvent(t, he) diff --git a/userapi/api/api.go b/userapi/api/api.go index 3fe6a383d..4e13a3b94 100644 --- a/userapi/api/api.go +++ b/userapi/api/api.go @@ -87,6 +87,7 @@ type ClientUserAPI interface { UserLoginAPI ClientKeyAPI ProfileAPI + KeyBackupAPI QueryNumericLocalpart(ctx context.Context, req *QueryNumericLocalpartRequest, res *QueryNumericLocalpartResponse) error QueryDevices(ctx context.Context, req *QueryDevicesRequest, res *QueryDevicesResponse) error QueryAccountData(ctx context.Context, req *QueryAccountDataRequest, res *QueryAccountDataResponse) error @@ -105,8 +106,6 @@ type ClientUserAPI interface { PerformOpenIDTokenCreation(ctx context.Context, req *PerformOpenIDTokenCreationRequest, res *PerformOpenIDTokenCreationResponse) error QueryNotifications(ctx context.Context, req *QueryNotificationsRequest, res *QueryNotificationsResponse) error InputAccountData(ctx context.Context, req *InputAccountDataRequest, res *InputAccountDataResponse) error - PerformKeyBackup(ctx context.Context, req *PerformKeyBackupRequest, res *PerformKeyBackupResponse) error - QueryKeyBackup(ctx context.Context, req *QueryKeyBackupRequest, res *QueryKeyBackupResponse) error QueryThreePIDsForLocalpart(ctx context.Context, req *QueryThreePIDsForLocalpartRequest, res *QueryThreePIDsForLocalpartResponse) error QueryLocalpartForThreePID(ctx context.Context, req *QueryLocalpartForThreePIDRequest, res *QueryLocalpartForThreePIDResponse) error @@ -114,6 +113,13 @@ type ClientUserAPI interface { PerformSaveThreePIDAssociation(ctx context.Context, req *PerformSaveThreePIDAssociationRequest, res *struct{}) error } +type KeyBackupAPI interface { + DeleteKeyBackup(ctx context.Context, userID, version string) (bool, error) + PerformKeyBackup(ctx context.Context, req *PerformKeyBackupRequest) (string, error) + QueryKeyBackup(ctx context.Context, req *QueryKeyBackupRequest) (*QueryKeyBackupResponse, error) + UpdateBackupKeyAuthData(ctx context.Context, req *PerformKeyBackupRequest) (*PerformKeyBackupResponse, error) +} + type ProfileAPI interface { QueryProfile(ctx context.Context, userID string) (*authtypes.Profile, error) SetAvatarURL(ctx context.Context, localpart string, serverName spec.ServerName, avatarURL string) (*authtypes.Profile, bool, error) @@ -135,11 +141,10 @@ type UserLoginAPI interface { } type PerformKeyBackupRequest struct { - UserID string - Version string // optional if modifying a key backup - AuthData json.RawMessage - Algorithm string - DeleteBackup bool // if true will delete the backup based on 'Version'. + UserID string + Version string // optional if modifying a key backup + AuthData json.RawMessage + Algorithm string // The keys to upload, if any. If blank, creates/updates/deletes key version metadata only. Keys struct { @@ -180,9 +185,6 @@ type InternalKeyBackupSession struct { } type PerformKeyBackupResponse struct { - Error string // set if there was a problem performing the request - BadInput bool // if set, the Error was due to bad input (HTTP 400) - Exists bool // set to true if the Version exists Version string // the newly created version @@ -200,7 +202,6 @@ type QueryKeyBackupRequest struct { } type QueryKeyBackupResponse struct { - Error string Exists bool Algorithm string `json:"algorithm"` diff --git a/userapi/consumers/roomserver.go b/userapi/consumers/roomserver.go index 834964ce8..6201aa813 100644 --- a/userapi/consumers/roomserver.go +++ b/userapi/consumers/roomserver.go @@ -21,6 +21,7 @@ import ( "github.com/matrix-org/dendrite/internal/pushgateway" "github.com/matrix-org/dendrite/internal/pushrules" rsapi "github.com/matrix-org/dendrite/roomserver/api" + rstypes "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/process" @@ -292,7 +293,7 @@ func (s *OutputRoomEventConsumer) copyTags(ctx context.Context, oldRoomID, newRo return s.db.SaveAccountData(ctx, localpart, serverName, newRoomID, "m.tag", tag) } -func (s *OutputRoomEventConsumer) processMessage(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, streamPos uint64) error { +func (s *OutputRoomEventConsumer) processMessage(ctx context.Context, event *rstypes.HeaderedEvent, streamPos uint64) error { members, roomSize, err := s.localRoomMembers(ctx, event.RoomID()) if err != nil { return fmt.Errorf("s.localRoomMembers: %w", err) @@ -300,7 +301,7 @@ func (s *OutputRoomEventConsumer) processMessage(ctx context.Context, event *gom switch { case event.Type() == spec.MRoomMember: - cevent := synctypes.HeaderedToClientEvent(event, synctypes.FormatAll) + cevent := synctypes.ToClientEvent(event, synctypes.FormatAll) var member *localMembership member, err = newLocalMembership(&cevent) if err != nil { @@ -436,7 +437,7 @@ func (s *OutputRoomEventConsumer) localRoomMembers(ctx context.Context, roomID s // looks it up in roomserver. If there is no name, // m.room.canonical_alias is consulted. Returns an empty string if the // room has no name. -func (s *OutputRoomEventConsumer) roomName(ctx context.Context, event *gomatrixserverlib.HeaderedEvent) (string, error) { +func (s *OutputRoomEventConsumer) roomName(ctx context.Context, event *rstypes.HeaderedEvent) (string, error) { if event.Type() == spec.MRoomName { name, err := unmarshalRoomName(event) if err != nil { @@ -485,7 +486,7 @@ var ( roomNameTuple = gomatrixserverlib.StateKeyTuple{EventType: spec.MRoomName} ) -func unmarshalRoomName(event *gomatrixserverlib.HeaderedEvent) (string, error) { +func unmarshalRoomName(event *rstypes.HeaderedEvent) (string, error) { var nc eventutil.NameContent if err := json.Unmarshal(event.Content(), &nc); err != nil { return "", fmt.Errorf("unmarshaling NameContent: %w", err) @@ -494,7 +495,7 @@ func unmarshalRoomName(event *gomatrixserverlib.HeaderedEvent) (string, error) { return nc.Name, nil } -func unmarshalCanonicalAlias(event *gomatrixserverlib.HeaderedEvent) (string, error) { +func unmarshalCanonicalAlias(event *rstypes.HeaderedEvent) (string, error) { var cac eventutil.CanonicalAliasContent if err := json.Unmarshal(event.Content(), &cac); err != nil { return "", fmt.Errorf("unmarshaling CanonicalAliasContent: %w", err) @@ -504,7 +505,7 @@ func unmarshalCanonicalAlias(event *gomatrixserverlib.HeaderedEvent) (string, er } // notifyLocal finds the right push actions for a local user, given an event. -func (s *OutputRoomEventConsumer) notifyLocal(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, mem *localMembership, roomSize int, roomName string, streamPos uint64) error { +func (s *OutputRoomEventConsumer) notifyLocal(ctx context.Context, event *rstypes.HeaderedEvent, mem *localMembership, roomSize int, roomName string, streamPos uint64) error { actions, err := s.evaluatePushRules(ctx, event, mem, roomSize) if err != nil { return fmt.Errorf("s.evaluatePushRules: %w", err) @@ -533,7 +534,7 @@ func (s *OutputRoomEventConsumer) notifyLocal(ctx context.Context, event *gomatr // UNSPEC: the spec doesn't say this is a ClientEvent, but the // fields seem to match. room_id should be missing, which // matches the behaviour of FormatSync. - Event: synctypes.HeaderedToClientEvent(event, synctypes.FormatSync), + Event: synctypes.ToClientEvent(event, synctypes.FormatSync), // TODO: this is per-device, but it's not part of the primary // key. So inserting one notification per profile tag doesn't // make sense. What is this supposed to be? Sytests require it @@ -613,7 +614,7 @@ func (s *OutputRoomEventConsumer) notifyLocal(ctx context.Context, event *gomatr // evaluatePushRules fetches and evaluates the push rules of a local // user. Returns actions (including dont_notify). -func (s *OutputRoomEventConsumer) evaluatePushRules(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, mem *localMembership, roomSize int) ([]*pushrules.Action, error) { +func (s *OutputRoomEventConsumer) evaluatePushRules(ctx context.Context, event *rstypes.HeaderedEvent, mem *localMembership, roomSize int) ([]*pushrules.Action, error) { if event.Sender() == mem.UserID { // SPEC: Homeservers MUST NOT notify the Push Gateway for // events that the user has sent themselves. @@ -732,7 +733,7 @@ func (s *OutputRoomEventConsumer) localPushDevices(ctx context.Context, localpar } // notifyHTTP performs a notificatation to a Push Gateway. -func (s *OutputRoomEventConsumer) notifyHTTP(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, url, format string, devices []*pushgateway.Device, localpart, roomName string, userNumUnreadNotifs int) ([]*pushgateway.Device, error) { +func (s *OutputRoomEventConsumer) notifyHTTP(ctx context.Context, event *rstypes.HeaderedEvent, url, format string, devices []*pushgateway.Device, localpart, roomName string, userNumUnreadNotifs int) ([]*pushgateway.Device, error) { logger := log.WithFields(log.Fields{ "event_id": event.EventID(), "url": url, diff --git a/userapi/consumers/roomserver_test.go b/userapi/consumers/roomserver_test.go index 465ec21aa..0a24c4f44 100644 --- a/userapi/consumers/roomserver_test.go +++ b/userapi/consumers/roomserver_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/matrix-org/dendrite/internal/sqlutil" + "github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/stretchr/testify/assert" @@ -34,13 +35,13 @@ func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.UserDatabase, } } -func mustCreateEvent(t *testing.T, content string) *gomatrixserverlib.HeaderedEvent { +func mustCreateEvent(t *testing.T, content string) *types.HeaderedEvent { t.Helper() ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionV10).NewEventFromTrustedJSON([]byte(content), false) if err != nil { t.Fatalf("failed to create event: %v", err) } - return ev.Headered(gomatrixserverlib.RoomVersionV10) + return &types.HeaderedEvent{Event: ev} } func Test_evaluatePushRules(t *testing.T) { diff --git a/userapi/internal/user_api.go b/userapi/internal/user_api.go index 1b6a4ebfa..ea97fd353 100644 --- a/userapi/internal/user_api.go +++ b/userapi/internal/user_api.go @@ -25,6 +25,7 @@ import ( appserviceAPI "github.com/matrix-org/dendrite/appservice/api" "github.com/matrix-org/dendrite/clientapi/auth/authtypes" + "github.com/matrix-org/dendrite/clientapi/jsonerror" fedsenderapi "github.com/matrix-org/dendrite/federationapi/api" "github.com/matrix-org/dendrite/internal/pushrules" "github.com/matrix-org/gomatrixserverlib" @@ -172,8 +173,8 @@ func addUserToRoom( UserID: userID, Content: addGroupContent, } - joinRes := rsapi.PerformJoinResponse{} - return rsAPI.PerformJoin(ctx, &joinReq, &joinRes) + _, _, err := rsAPI.PerformJoin(ctx, &joinReq) + return err } func (a *UserInternalAPI) PerformAccountCreation(ctx context.Context, req *api.PerformAccountCreationRequest, res *api.PerformAccountCreationResponse) error { @@ -624,33 +625,28 @@ func (a *UserInternalAPI) PerformAccountDeactivation(ctx context.Context, req *a return fmt.Errorf("server name %q not locally configured", serverName) } - evacuateReq := &rsapi.PerformAdminEvacuateUserRequest{ - UserID: fmt.Sprintf("@%s:%s", req.Localpart, serverName), - } - evacuateRes := &rsapi.PerformAdminEvacuateUserResponse{} - if err := a.RSAPI.PerformAdminEvacuateUser(ctx, evacuateReq, evacuateRes); err != nil { - return err - } - if err := evacuateRes.Error; err != nil { - logrus.WithError(err).Errorf("Failed to evacuate user after account deactivation") + userID := fmt.Sprintf("@%s:%s", req.Localpart, serverName) + _, err := a.RSAPI.PerformAdminEvacuateUser(ctx, userID) + if err != nil { + logrus.WithError(err).WithField("userID", userID).Errorf("Failed to evacuate user after account deactivation") } deviceReq := &api.PerformDeviceDeletionRequest{ UserID: fmt.Sprintf("@%s:%s", req.Localpart, serverName), } deviceRes := &api.PerformDeviceDeletionResponse{} - if err := a.PerformDeviceDeletion(ctx, deviceReq, deviceRes); err != nil { + if err = a.PerformDeviceDeletion(ctx, deviceReq, deviceRes); err != nil { return err } pusherReq := &api.PerformPusherDeletionRequest{ Localpart: req.Localpart, } - if err := a.PerformPusherDeletion(ctx, pusherReq, &struct{}{}); err != nil { + if err = a.PerformPusherDeletion(ctx, pusherReq, &struct{}{}); err != nil { return err } - err := a.DB.DeactivateAccount(ctx, req.Localpart, serverName) + err = a.DB.DeactivateAccount(ctx, req.Localpart, serverName) res.AccountDeactivated = err == nil return err } @@ -683,62 +679,43 @@ func (a *UserInternalAPI) QueryOpenIDToken(ctx context.Context, req *api.QueryOp return nil } -func (a *UserInternalAPI) PerformKeyBackup(ctx context.Context, req *api.PerformKeyBackupRequest, res *api.PerformKeyBackupResponse) error { - // Delete metadata - if req.DeleteBackup { - if req.Version == "" { - res.BadInput = true - res.Error = "must specify a version to delete" - return nil - } - exists, err := a.DB.DeleteKeyBackup(ctx, req.UserID, req.Version) - if err != nil { - res.Error = fmt.Sprintf("failed to delete backup: %s", err) - } - res.Exists = exists - res.Version = req.Version - return nil - } +func (a *UserInternalAPI) DeleteKeyBackup(ctx context.Context, userID, version string) (bool, error) { + return a.DB.DeleteKeyBackup(ctx, userID, version) +} + +func (a *UserInternalAPI) PerformKeyBackup(ctx context.Context, req *api.PerformKeyBackupRequest) (string, error) { // Create metadata - if req.Version == "" { - version, err := a.DB.CreateKeyBackup(ctx, req.UserID, req.Algorithm, req.AuthData) - if err != nil { - res.Error = fmt.Sprintf("failed to create backup: %s", err) - } - res.Exists = err == nil - res.Version = version - return nil - } + return a.DB.CreateKeyBackup(ctx, req.UserID, req.Algorithm, req.AuthData) +} + +func (a *UserInternalAPI) UpdateBackupKeyAuthData(ctx context.Context, req *api.PerformKeyBackupRequest) (*api.PerformKeyBackupResponse, error) { + res := &api.PerformKeyBackupResponse{} // Update metadata if len(req.Keys.Rooms) == 0 { err := a.DB.UpdateKeyBackupAuthData(ctx, req.UserID, req.Version, req.AuthData) - if err != nil { - res.Error = fmt.Sprintf("failed to update backup: %s", err) - } res.Exists = err == nil res.Version = req.Version - return nil + if err != nil { + return res, fmt.Errorf("failed to update backup: %w", err) + } + return res, nil } // Upload Keys for a specific version metadata - a.uploadBackupKeys(ctx, req, res) - return nil + return a.uploadBackupKeys(ctx, req) } -func (a *UserInternalAPI) uploadBackupKeys(ctx context.Context, req *api.PerformKeyBackupRequest, res *api.PerformKeyBackupResponse) { +func (a *UserInternalAPI) uploadBackupKeys(ctx context.Context, req *api.PerformKeyBackupRequest) (*api.PerformKeyBackupResponse, error) { + res := &api.PerformKeyBackupResponse{} // you can only upload keys for the CURRENT version version, _, _, _, deleted, err := a.DB.GetKeyBackup(ctx, req.UserID, "") if err != nil { - res.Error = fmt.Sprintf("failed to query version: %s", err) - return + return res, fmt.Errorf("failed to query version: %w", err) } if deleted { - res.Error = "backup was deleted" - return + return res, fmt.Errorf("backup was deleted") } if version != req.Version { - res.BadInput = true - res.Error = fmt.Sprintf("%s isn't the current version, %s is.", req.Version, version) - return + return res, jsonerror.WrongBackupVersionError(version) } res.Exists = true res.Version = version @@ -756,23 +733,25 @@ func (a *UserInternalAPI) uploadBackupKeys(ctx context.Context, req *api.Perform } count, etag, err := a.DB.UpsertBackupKeys(ctx, version, req.UserID, uploads) if err != nil { - res.Error = fmt.Sprintf("failed to upsert keys: %s", err) - return + return res, fmt.Errorf("failed to upsert keys: %w", err) } res.KeyCount = count res.KeyETag = etag + return res, nil } -func (a *UserInternalAPI) QueryKeyBackup(ctx context.Context, req *api.QueryKeyBackupRequest, res *api.QueryKeyBackupResponse) error { +func (a *UserInternalAPI) QueryKeyBackup(ctx context.Context, req *api.QueryKeyBackupRequest) (*api.QueryKeyBackupResponse, error) { + res := &api.QueryKeyBackupResponse{} version, algorithm, authData, etag, deleted, err := a.DB.GetKeyBackup(ctx, req.UserID, req.Version) res.Version = version if err != nil { - if err == sql.ErrNoRows { - res.Exists = false - return nil + if errors.Is(err, sql.ErrNoRows) { + return res, nil } - res.Error = fmt.Sprintf("failed to query key backup: %s", err) - return nil + if errors.Is(err, strconv.ErrSyntax) { + return res, nil + } + return res, fmt.Errorf("failed to query key backup: %s", err) } res.Algorithm = algorithm res.AuthData = authData @@ -782,18 +761,17 @@ func (a *UserInternalAPI) QueryKeyBackup(ctx context.Context, req *api.QueryKeyB if !req.ReturnKeys { res.Count, err = a.DB.CountBackupKeys(ctx, version, req.UserID) if err != nil { - res.Error = fmt.Sprintf("failed to count keys: %s", err) + return res, fmt.Errorf("failed to count keys: %w", err) } - return nil + return res, nil } result, err := a.DB.GetBackupKeys(ctx, version, req.UserID, req.KeysForRoomID, req.KeysForSessionID) if err != nil { - res.Error = fmt.Sprintf("failed to query keys: %s", err) - return nil + return res, fmt.Errorf("failed to query keys: %s", err) } res.Keys = result - return nil + return res, nil } func (a *UserInternalAPI) QueryNotifications(ctx context.Context, req *api.QueryNotificationsRequest, res *api.QueryNotificationsResponse) error { diff --git a/userapi/util/notify_test.go b/userapi/util/notify_test.go index d6cbad7db..e1c88d47f 100644 --- a/userapi/util/notify_test.go +++ b/userapi/util/notify_test.go @@ -100,7 +100,7 @@ func TestNotifyUserCountsAsync(t *testing.T) { // Insert a dummy event if err := db.InsertNotification(ctx, aliceLocalpart, serverName, dummyEvent.EventID(), 0, nil, &api.Notification{ - Event: synctypes.HeaderedToClientEvent(dummyEvent, synctypes.FormatAll), + Event: synctypes.ToClientEvent(dummyEvent, synctypes.FormatAll), }); err != nil { t.Error(err) }