Merge branch 'main' into s7evink/memberships

This commit is contained in:
Devon Hudson 2023-07-06 15:41:27 -06:00
commit 2bcb89ad4c
No known key found for this signature in database
GPG key ID: CD06B18E77F6A628
23 changed files with 395 additions and 152 deletions

View file

@ -57,8 +57,8 @@ jobs:
id: docker_build_monolith
uses: docker/build-push-action@v3
with:
cache-from: type=gha
cache-to: type=gha,mode=max
cache-from: type=registry,ref=ghcr.io/${{ env.GHCR_NAMESPACE }}/dendrite-monolith:buildcache
cache-to: type=registry,ref=ghcr.io/${{ env.GHCR_NAMESPACE }}/dendrite-monolith:buildcache,mode=max
context: .
build-args: FLAGS=-X github.com/matrix-org/dendrite/internal.branch=${{ env.BRANCH }} -X github.com/matrix-org/dendrite/internal.build=${{ env.BUILD }}
platforms: ${{ env.PLATFORMS }}

View file

@ -1,5 +1,27 @@
# Changelog
## Dendrite 0.13.1 (2023-07-06)
This releases fixes a long-standing "off-by-one" error which could result in state resets. Upgrading to this version is **highly** recommended.
When deduplicating state events, we were checking if the event in question was already in a state snapshot. If it was in a previous state snapshot, we would
then remove it from the list of events to store. If this happened, we were, unfortunately, skipping the next event to check. This resulted in
events getting stored in state snapshots where they may not be needed. When we now compared two of those state snapshots, one of them
contained the skipped event, while the other didn't. This difference possibly shouldn't exist, resulting in unexpected state resets and explains
reports of missing state events as well.
Rooms where a state reset occurred earlier should, hopefully, reconcile over time.
### Fixes:
- A long-standing "off-by-one" error has been fixed, which could result in state resets
- Roomserver Prometheus Metrics are available again
### Features
- Updated dependencies
- Internal NATS Server has been updated from v2.9.15 to v2.9.19
## Dendrite 0.13.0 (2023-06-30)
### Features

View file

@ -337,22 +337,55 @@ func sendInvite(
rsAPI roomserverAPI.ClientRoomserverAPI,
asAPI appserviceAPI.AppServiceInternalAPI, evTime time.Time,
) (util.JSONResponse, error) {
event, err := buildMembershipEvent(
ctx, userID, reason, profileAPI, device, spec.Invite,
roomID, false, cfg, evTime, rsAPI, asAPI,
)
validRoomID, err := spec.NewRoomID(roomID)
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.InvalidParam("RoomID is invalid"),
}, err
}
inviter, err := spec.NewUserID(device.UserID, true)
if err != nil {
return util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}, err
}
invitee, err := spec.NewUserID(userID, true)
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.InvalidParam("UserID is invalid"),
}, err
}
profile, err := loadProfile(ctx, userID, cfg, profileAPI, asAPI)
if err != nil {
return util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}, err
}
identity, err := cfg.Matrix.SigningIdentityFor(device.UserDomain())
if err != nil {
util.GetLogger(ctx).WithError(err).Error("buildMembershipEvent failed")
return util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}, err
}
err = rsAPI.PerformInvite(ctx, &api.PerformInviteRequest{
Event: event,
InviteInput: roomserverAPI.InviteInput{
RoomID: *validRoomID,
Inviter: *inviter,
Invitee: *invitee,
DisplayName: profile.DisplayName,
AvatarURL: profile.AvatarURL,
Reason: reason,
IsDirect: false,
KeyID: identity.KeyID,
PrivateKey: identity.PrivateKey,
EventTime: evTime,
},
InviteRoomState: nil, // ask the roomserver to draw up invite room state for us
RoomVersion: event.Version(),
SendAsServer: string(device.UserDomain()),
})

View file

@ -63,6 +63,8 @@ type RoomserverFederationAPI interface {
PerformLeave(ctx context.Context, request *PerformLeaveRequest, response *PerformLeaveResponse) error
// Handle sending an invite to a remote server.
SendInvite(ctx context.Context, event gomatrixserverlib.PDU, strippedState []gomatrixserverlib.InviteStrippedState) (gomatrixserverlib.PDU, error)
// Handle sending an invite to a remote server.
SendInviteV3(ctx context.Context, event gomatrixserverlib.ProtoEvent, invitee spec.UserID, version gomatrixserverlib.RoomVersion, strippedState []gomatrixserverlib.InviteStrippedState) (gomatrixserverlib.PDU, error)
// Handle an instruction to peek a room on a remote server.
PerformOutboundPeek(ctx context.Context, request *PerformOutboundPeekRequest, response *PerformOutboundPeekResponse) error
// Query the server names of the joined hosts in a room.

View file

@ -55,11 +55,14 @@ func NewFederationInternalAPI(
KeyDatabase: serverKeyDB,
}
pubKey := cfg.Matrix.PrivateKey.Public().(ed25519.PublicKey)
addDirectFetcher := func() {
keyRing.KeyFetchers = append(
keyRing.KeyFetchers,
&gomatrixserverlib.DirectKeyFetcher{
Client: federation,
IsLocalServerName: cfg.Matrix.IsLocalServerName,
LocalPublicKey: []byte(pubKey),
},
)
}

View file

@ -600,6 +600,58 @@ func (r *FederationInternalAPI) SendInvite(
return inviteEvent, nil
}
// SendInviteV3 implements api.FederationInternalAPI
func (r *FederationInternalAPI) SendInviteV3(
ctx context.Context,
event gomatrixserverlib.ProtoEvent,
invitee spec.UserID,
version gomatrixserverlib.RoomVersion,
strippedState []gomatrixserverlib.InviteStrippedState,
) (gomatrixserverlib.PDU, error) {
validRoomID, err := spec.NewRoomID(event.RoomID)
if err != nil {
return nil, err
}
verImpl, err := gomatrixserverlib.GetRoomVersion(version)
if err != nil {
return nil, err
}
inviter, err := r.rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(event.SenderID))
if err != nil {
return nil, err
}
// TODO (devon): This should be allowed via a relay. Currently only transactions
// can be sent to relays. Would need to extend relays to handle invites.
if !r.shouldAttemptDirectFederation(invitee.Domain()) {
return nil, fmt.Errorf("relay servers have no meaningful response for invite.")
}
logrus.WithFields(logrus.Fields{
"user_id": invitee.String(),
"room_id": event.RoomID,
"room_version": version,
"destination": invitee.Domain(),
}).Info("Sending invite")
inviteReq, err := fclient.NewInviteV3Request(event, version, strippedState)
if err != nil {
return nil, fmt.Errorf("gomatrixserverlib.NewInviteV3Request: %w", err)
}
inviteRes, err := r.federation.SendInviteV3(ctx, inviter.Domain(), invitee.Domain(), inviteReq, invitee)
if err != nil {
return nil, fmt.Errorf("r.federation.SendInviteV3: failed to send invite: %w", err)
}
inviteEvent, err := verImpl.NewEventFromUntrustedJSON(inviteRes.Event)
if err != nil {
return nil, fmt.Errorf("r.federation.SendInviteV3 failed to decode event response: %w", err)
}
return inviteEvent, nil
}
// PerformServersAlive implements api.FederationInternalAPI
func (r *FederationInternalAPI) PerformBroadcastEDU(
ctx context.Context,

View file

@ -16,6 +16,7 @@ package internal
import (
"context"
"crypto/ed25519"
"testing"
"github.com/matrix-org/dendrite/federationapi/api"
@ -53,10 +54,14 @@ func TestPerformWakeupServers(t *testing.T) {
assert.NoError(t, err)
assert.True(t, offline)
_, key, err := ed25519.GenerateKey(nil)
assert.NoError(t, err)
cfg := config.FederationAPI{
Matrix: &config.Global{
SigningIdentity: fclient.SigningIdentity{
ServerName: "relay",
KeyID: "ed25519:1",
PrivateKey: key,
},
},
}
@ -95,10 +100,14 @@ func TestQueryRelayServers(t *testing.T) {
err := testDB.P2PAddRelayServersForServer(context.Background(), server, relayServers)
assert.NoError(t, err)
_, key, err := ed25519.GenerateKey(nil)
assert.NoError(t, err)
cfg := config.FederationAPI{
Matrix: &config.Global{
SigningIdentity: fclient.SigningIdentity{
ServerName: "relay",
KeyID: "ed25519:1",
PrivateKey: key,
},
},
}
@ -132,10 +141,14 @@ func TestRemoveRelayServers(t *testing.T) {
err := testDB.P2PAddRelayServersForServer(context.Background(), server, relayServers)
assert.NoError(t, err)
_, key, err := ed25519.GenerateKey(nil)
assert.NoError(t, err)
cfg := config.FederationAPI{
Matrix: &config.Global{
SigningIdentity: fclient.SigningIdentity{
ServerName: "relay",
KeyID: "ed25519:1",
PrivateKey: key,
},
},
}
@ -168,10 +181,14 @@ func TestRemoveRelayServers(t *testing.T) {
func TestPerformDirectoryLookup(t *testing.T) {
testDB := test.NewInMemoryFederationDatabase()
_, key, err := ed25519.GenerateKey(nil)
assert.NoError(t, err)
cfg := config.FederationAPI{
Matrix: &config.Global{
SigningIdentity: fclient.SigningIdentity{
ServerName: "relay",
KeyID: "ed25519:1",
PrivateKey: key,
},
},
}
@ -192,7 +209,7 @@ func TestPerformDirectoryLookup(t *testing.T) {
ServerName: "server",
}
res := api.PerformDirectoryLookupResponse{}
err := fedAPI.PerformDirectoryLookup(context.Background(), &req, &res)
err = fedAPI.PerformDirectoryLookup(context.Background(), &req, &res)
assert.NoError(t, err)
}
@ -203,10 +220,14 @@ func TestPerformDirectoryLookupRelaying(t *testing.T) {
testDB.SetServerAssumedOffline(context.Background(), server)
testDB.P2PAddRelayServersForServer(context.Background(), server, []spec.ServerName{"relay"})
_, key, err := ed25519.GenerateKey(nil)
assert.NoError(t, err)
cfg := config.FederationAPI{
Matrix: &config.Global{
SigningIdentity: fclient.SigningIdentity{
ServerName: server,
ServerName: "relay",
KeyID: "ed25519:1",
PrivateKey: key,
},
},
}
@ -227,6 +248,6 @@ func TestPerformDirectoryLookupRelaying(t *testing.T) {
ServerName: server,
}
res := api.PerformDirectoryLookupResponse{}
err := fedAPI.PerformDirectoryLookup(context.Background(), &req, &res)
err = fedAPI.PerformDirectoryLookup(context.Background(), &req, &res)
assert.Error(t, err)
}

View file

@ -16,6 +16,7 @@ package routing
import (
"context"
"crypto/ed25519"
"encoding/json"
"fmt"
"net/http"
@ -29,6 +30,73 @@ import (
"github.com/matrix-org/util"
)
// InviteV3 implements /_matrix/federation/v2/invite/{roomID}/{userID}
func InviteV3(
httpReq *http.Request,
request *fclient.FederationRequest,
roomID spec.RoomID,
invitedUser spec.UserID,
cfg *config.FederationAPI,
rsAPI api.FederationRoomserverAPI,
keys gomatrixserverlib.JSONVerifier,
) util.JSONResponse {
inviteReq := fclient.InviteV3Request{}
err := json.Unmarshal(request.Content(), &inviteReq)
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.BadJSON(err.Error()),
}
}
if !cfg.Matrix.IsLocalServerName(invitedUser.Domain()) {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.InvalidParam("The invited user domain does not belong to this server"),
}
}
input := gomatrixserverlib.HandleInviteV3Input{
HandleInviteInput: gomatrixserverlib.HandleInviteInput{
RoomVersion: inviteReq.RoomVersion(),
RoomID: roomID,
InvitedUser: invitedUser,
KeyID: cfg.Matrix.KeyID,
PrivateKey: cfg.Matrix.PrivateKey,
Verifier: keys,
RoomQuerier: rsAPI,
MembershipQuerier: &api.MembershipQuerier{Roomserver: rsAPI},
StateQuerier: rsAPI.StateQuerier(),
InviteEvent: nil,
StrippedState: inviteReq.InviteRoomState(),
UserIDQuerier: func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return rsAPI.QueryUserIDForSender(httpReq.Context(), roomID, senderID)
},
},
InviteProtoEvent: inviteReq.Event(),
GetOrCreateSenderID: func(ctx context.Context, userID spec.UserID, roomID spec.RoomID, roomVersion string) (spec.SenderID, ed25519.PrivateKey, error) {
// assign a roomNID, otherwise we can't create a private key for the user
_, nidErr := rsAPI.AssignRoomNID(ctx, roomID, gomatrixserverlib.RoomVersion(roomVersion))
if nidErr != nil {
return "", nil, nidErr
}
key, keyErr := rsAPI.GetOrCreateUserRoomPrivateKey(ctx, userID, roomID)
if keyErr != nil {
return "", nil, keyErr
}
return spec.SenderIDFromPseudoIDKey(key), key, nil
},
}
event, jsonErr := handleInviteV3(httpReq.Context(), input, rsAPI)
if jsonErr != nil {
return *jsonErr
}
return util.JSONResponse{
Code: http.StatusOK,
JSON: fclient.RespInviteV2{Event: event.JSON()},
}
}
// InviteV2 implements /_matrix/federation/v2/invite/{roomID}/{eventID}
func InviteV2(
httpReq *http.Request,
@ -204,6 +272,15 @@ func InviteV1(
func handleInvite(ctx context.Context, input gomatrixserverlib.HandleInviteInput, rsAPI api.FederationRoomserverAPI) (gomatrixserverlib.PDU, *util.JSONResponse) {
inviteEvent, err := gomatrixserverlib.HandleInvite(ctx, input)
return handleInviteResult(ctx, inviteEvent, err, rsAPI)
}
func handleInviteV3(ctx context.Context, input gomatrixserverlib.HandleInviteV3Input, rsAPI api.FederationRoomserverAPI) (gomatrixserverlib.PDU, *util.JSONResponse) {
inviteEvent, err := gomatrixserverlib.HandleInviteV3(ctx, input)
return handleInviteResult(ctx, inviteEvent, err, rsAPI)
}
func handleInviteResult(ctx context.Context, inviteEvent gomatrixserverlib.PDU, err error, rsAPI api.FederationRoomserverAPI) (gomatrixserverlib.PDU, *util.JSONResponse) {
switch e := err.(type) {
case nil:
case spec.InternalServerError:
@ -245,4 +322,5 @@ func handleInvite(ctx context.Context, input gomatrixserverlib.HandleInviteInput
}
}
return inviteEvent, nil
}

View file

@ -187,9 +187,6 @@ func MakeJoin(
}
// SendJoin implements the /send_join API
// The make-join send-join dance makes much more sense as a single
// flow so the cyclomatic complexity is high:
// nolint:gocyclo
func SendJoin(
httpReq *http.Request,
request *fclient.FederationRequest,

View file

@ -78,6 +78,7 @@ func Setup(
v2keysmux := keyMux.PathPrefix("/v2").Subrouter()
v1fedmux := fedMux.PathPrefix("/v1").Subrouter()
v2fedmux := fedMux.PathPrefix("/v2").Subrouter()
v3fedmux := fedMux.PathPrefix("/v3").Subrouter()
wakeup := &FederationWakeups{
FsAPI: fsAPI,
@ -191,6 +192,37 @@ func Setup(
},
)).Methods(http.MethodPut, http.MethodOptions)
v3fedmux.Handle("/invite/{roomID}/{userID}", MakeFedAPI(
"federation_invite", cfg.Matrix.ServerName, cfg.Matrix.IsLocalServerName, keys, wakeup,
func(httpReq *http.Request, request *fclient.FederationRequest, vars map[string]string) util.JSONResponse {
if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) {
return util.JSONResponse{
Code: http.StatusForbidden,
JSON: spec.Forbidden("Forbidden by server ACLs"),
}
}
userID, err := spec.NewUserID(vars["userID"], true)
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.InvalidParam("Invalid UserID"),
}
}
roomID, err := spec.NewRoomID(vars["roomID"])
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.InvalidParam("Invalid RoomID"),
}
}
return InviteV3(
httpReq, request, *roomID, *userID,
cfg, rsAPI, keys,
)
},
)).Methods(http.MethodPut, http.MethodOptions)
v1fedmux.Handle("/3pid/onbind", httputil.MakeExternalAPI("3pid_onbind",
func(req *http.Request) util.JSONResponse {
return CreateInvitesFrom3PIDInvites(req, rsAPI, cfg, federation, userAPI)

12
go.mod
View file

@ -1,5 +1,7 @@
module github.com/matrix-org/dendrite
replace github.com/matrix-org/gomatrixserverlib => ../../../gomatrixserverlib/s7evink/memberships/
require (
github.com/Arceliar/ironwood v0.0.0-20221025225125-45b4281814c2
github.com/Arceliar/phony v0.0.0-20210209235338-dde1a8dca979
@ -22,7 +24,7 @@ require (
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-20230705085830-cd68bcc30aec
github.com/matrix-org/gomatrixserverlib v0.0.0-20230706213828-fa6d5ca0e184
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
@ -42,12 +44,12 @@ require (
github.com/uber/jaeger-lib v2.4.1+incompatible
github.com/yggdrasil-network/yggdrasil-go v0.4.6
go.uber.org/atomic v1.10.0
golang.org/x/crypto v0.10.0
golang.org/x/crypto v0.11.0
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db
golang.org/x/image v0.5.0
golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e
golang.org/x/sync v0.1.0
golang.org/x/term v0.9.0
golang.org/x/term v0.10.0
gopkg.in/h2non/bimg.v1 v1.1.9
gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.4.0
@ -127,8 +129,8 @@ require (
go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/text v0.10.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect

18
go.sum
View file

@ -323,8 +323,6 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 h1:s7fexw
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-20230705085830-cd68bcc30aec h1:5dR/r+xmOWpgpvE/K+PPNNXNDHFdYGCz10YdoW5T2po=
github.com/matrix-org/gomatrixserverlib v0.0.0-20230705085830-cd68bcc30aec/go.mod h1:H9V9N3Uqn1bBJqYJNGK1noqtgJTaCEhtTdcH/mp50uU=
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=
@ -511,8 +509,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -669,12 +667,12 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -683,8 +681,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View file

@ -17,7 +17,7 @@ var build string
const (
VersionMajor = 0
VersionMinor = 13
VersionPatch = 0
VersionPatch = 1
VersionTag = "" // example: "rc1"
)

View file

@ -50,9 +50,21 @@ type PerformLeaveResponse struct {
Message interface{} `json:"message,omitempty"`
}
type InviteInput struct {
RoomID spec.RoomID
Inviter spec.UserID
Invitee spec.UserID
DisplayName string
AvatarURL string
Reason string
IsDirect bool
KeyID gomatrixserverlib.KeyID
PrivateKey ed25519.PrivateKey
EventTime time.Time
}
type PerformInviteRequest struct {
RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
Event *types.HeaderedEvent `json:"event"`
InviteInput InviteInput
InviteRoomState []gomatrixserverlib.InviteStrippedState `json:"invite_room_state"`
SendAsServer string `json:"send_as_server"`
TransactionID *TransactionID `json:"transaction_id"`

View file

@ -126,6 +126,7 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
KeyRing: keyRing,
ACLs: r.ServerACLs,
Queryer: r.Queryer,
EnableMetrics: r.enableMetrics,
}
r.Inviter = &perform.Inviter{
DB: r.DB,
@ -317,7 +318,7 @@ func (r *RoomserverInternalAPI) SigningIdentityFor(ctx context.Context, roomID s
return fclient.SigningIdentity{
PrivateKey: privKey,
KeyID: "ed25519:1",
ServerName: "self",
ServerName: spec.ServerName(spec.SenderIDFromPseudoIDKey(privKey)),
}, nil
}
identity, err := r.Cfg.Global.SigningIdentityFor(senderID.Domain())

View file

@ -91,7 +91,7 @@ type Inputer struct {
Queryer *query.Queryer
UserAPI userapi.RoomserverUserAPI
enableMetrics bool
EnableMetrics bool
}
// If a room consumer is inactive for a while then we will allow NATS
@ -178,7 +178,7 @@ func (r *Inputer) startWorkerForRoom(roomID string) {
// will look to see if we have a worker for that room which has its
// own consumer. If we don't, we'll start one.
func (r *Inputer) Start() error {
if r.enableMetrics {
if r.EnableMetrics {
prometheus.MustRegister(roomserverInputBackpressure, processRoomEventDuration)
}
_, err := r.JetStream.Subscribe(

View file

@ -195,7 +195,7 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
// sign all events with the pseudo ID key
identity = &fclient.SigningIdentity{
ServerName: "self",
ServerName: spec.ServerName(spec.SenderIDFromPseudoIDKey(pseudoIDKey)),
KeyID: "ed25519:1",
PrivateKey: pseudoIDKey,
}
@ -489,7 +489,6 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
}
// Process the invites.
var inviteEvent *types.HeaderedEvent
for _, invitee := range createRequest.InvitedUsers {
inviteeUserID, userIDErr := spec.NewUserID(invitee, true)
if userIDErr != nil {
@ -499,54 +498,21 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
JSON: spec.InternalServerError{},
}
}
inviteeSenderID, queryErr := c.RSAPI.QuerySenderIDForUser(ctx, roomID, *inviteeUserID)
if queryErr != nil {
util.GetLogger(ctx).WithError(queryErr).Error("rsapi.QuerySenderIDForUser failed")
return "", &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}
}
inviteeString := string(inviteeSenderID)
proto := gomatrixserverlib.ProtoEvent{
SenderID: string(senderID),
RoomID: roomID.String(),
Type: "m.room.member",
StateKey: &inviteeString,
}
content := gomatrixserverlib.MemberContent{
Membership: spec.Invite,
err = c.RSAPI.PerformInvite(ctx, &api.PerformInviteRequest{
InviteInput: api.InviteInput{
RoomID: roomID,
Inviter: userID,
Invitee: *inviteeUserID,
DisplayName: createRequest.UserDisplayName,
AvatarURL: createRequest.UserAvatarURL,
Reason: "",
IsDirect: createRequest.IsDirect,
}
if err = proto.SetContent(content); err != nil {
return "", &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}
}
// Build the invite event.
inviteEvent, err = eventutil.QueryAndBuildEvent(ctx, &proto, identity, createRequest.EventTime, c.RSAPI, nil)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("buildMembershipEvent failed")
continue
}
inviteStrippedState := append(
globalStrippedState,
gomatrixserverlib.NewInviteStrippedState(inviteEvent.PDU),
)
// Send the invite event to the roomserver.
event := inviteEvent
err = c.RSAPI.PerformInvite(ctx, &api.PerformInviteRequest{
Event: event,
InviteRoomState: inviteStrippedState,
RoomVersion: event.Version(),
KeyID: createRequest.KeyID,
PrivateKey: createRequest.PrivateKey,
EventTime: createRequest.EventTime,
},
InviteRoomState: globalStrippedState,
SendAsServer: string(userID.Domain()),
})
switch e := err.(type) {

View file

@ -16,6 +16,7 @@ package perform
import (
"context"
"crypto/ed25519"
"fmt"
federationAPI "github.com/matrix-org/dendrite/federationapi/api"
@ -129,65 +130,102 @@ func (r *Inviter) PerformInvite(
ctx context.Context,
req *api.PerformInviteRequest,
) error {
event := req.Event
validRoomID, err := spec.NewRoomID(event.RoomID())
senderID, err := r.RSAPI.QuerySenderIDForUser(ctx, req.InviteInput.RoomID, req.InviteInput.Inviter)
if err != nil {
return err
}
info, err := r.DB.RoomInfo(ctx, req.InviteInput.RoomID.String())
if err != nil {
return err
}
sender, err := r.RSAPI.QueryUserIDForSender(ctx, *validRoomID, event.SenderID())
if err != nil {
return spec.InvalidParam("The sender user ID is invalid")
proto := gomatrixserverlib.ProtoEvent{
SenderID: string(senderID),
RoomID: req.InviteInput.RoomID.String(),
Type: "m.room.member",
}
if !r.Cfg.Matrix.IsLocalServerName(sender.Domain()) {
content := gomatrixserverlib.MemberContent{
Membership: spec.Invite,
DisplayName: req.InviteInput.DisplayName,
AvatarURL: req.InviteInput.AvatarURL,
Reason: req.InviteInput.Reason,
IsDirect: req.InviteInput.IsDirect,
}
if err = proto.SetContent(content); err != nil {
return err
}
if !r.Cfg.Matrix.IsLocalServerName(req.InviteInput.Inviter.Domain()) {
return api.ErrInvalidID{Err: fmt.Errorf("the invite must be from a local user")}
}
if event.StateKey() == nil || *event.StateKey() == "" {
return fmt.Errorf("invite must be a state event")
}
invitedUser, err := r.RSAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*event.StateKey()))
if err != nil || invitedUser == nil {
return spec.InvalidParam("Could not find the matching senderID for this user")
}
isTargetLocal := r.Cfg.Matrix.IsLocalServerName(invitedUser.Domain())
isTargetLocal := r.Cfg.Matrix.IsLocalServerName(req.InviteInput.Invitee.Domain())
// If we're inviting a local user, we can generate the needed pseudoID key here. (if needed)
if isTargetLocal {
var roomVersion gomatrixserverlib.RoomVersion
roomVersion, err = r.DB.GetRoomVersion(ctx, event.RoomID())
signingKey := req.InviteInput.PrivateKey
if info.RoomVersion == gomatrixserverlib.RoomVersionPseudoIDs {
signingKey, err = r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, req.InviteInput.Inviter, req.InviteInput.RoomID)
if err != nil {
return err
}
switch roomVersion {
case gomatrixserverlib.RoomVersionPseudoIDs:
_, err = r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, *invitedUser, *validRoomID)
if err != nil {
return err
}
}
}
invitedSenderID, err := r.RSAPI.QuerySenderIDForUser(ctx, *validRoomID, *invitedUser)
if err != nil {
return fmt.Errorf("failed looking up senderID for invited user")
}
input := gomatrixserverlib.PerformInviteInput{
RoomID: *validRoomID,
InviteEvent: event.PDU,
InvitedUser: *invitedUser,
InvitedSenderID: invitedSenderID,
RoomID: req.InviteInput.RoomID,
RoomVersion: info.RoomVersion,
Inviter: req.InviteInput.Inviter,
Invitee: req.InviteInput.Invitee,
IsTargetLocal: isTargetLocal,
EventTemplate: proto,
StrippedState: req.InviteRoomState,
KeyID: req.InviteInput.KeyID,
SigningKey: signingKey,
EventTime: req.InviteInput.EventTime,
MembershipQuerier: &api.MembershipQuerier{Roomserver: r.RSAPI},
StateQuerier: &QueryState{r.DB, r.RSAPI},
UserIDQuerier: func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return r.RSAPI.QueryUserIDForSender(ctx, roomID, senderID)
},
SenderIDQuerier: func(roomID spec.RoomID, userID spec.UserID) (spec.SenderID, error) {
return r.RSAPI.QuerySenderIDForUser(ctx, roomID, userID)
},
SenderIDCreator: func(ctx context.Context, userID spec.UserID, roomID spec.RoomID, roomVersion string) (spec.SenderID, ed25519.PrivateKey, error) {
key, keyErr := r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, userID, roomID)
if keyErr != nil {
return "", nil, keyErr
}
return spec.SenderIDFromPseudoIDKey(key), key, nil
},
EventQuerier: func(ctx context.Context, roomID spec.RoomID, eventsNeeded []gomatrixserverlib.StateKeyTuple) (gomatrixserverlib.LatestEvents, error) {
req := api.QueryLatestEventsAndStateRequest{RoomID: roomID.String(), StateToFetch: eventsNeeded}
res := api.QueryLatestEventsAndStateResponse{}
err = r.RSAPI.QueryLatestEventsAndState(ctx, &req, &res)
if err != nil {
return gomatrixserverlib.LatestEvents{}, nil
}
stateEvents := []gomatrixserverlib.PDU{}
for _, event := range res.StateEvents {
stateEvents = append(stateEvents, event.PDU)
}
return gomatrixserverlib.LatestEvents{
RoomExists: res.RoomExists,
StateEvents: stateEvents,
PrevEventIDs: res.LatestEvents,
Depth: res.Depth,
}, nil
},
StoreSenderIDFromPublicID: func(ctx context.Context, senderID spec.SenderID, userIDRaw string, roomID spec.RoomID) error {
storeUserID, userErr := spec.NewUserID(userIDRaw, true)
if userErr != nil {
return userErr
}
return r.RSAPI.StoreUserRoomPublicKey(ctx, senderID, *storeUserID, roomID)
},
}
inviteEvent, err := gomatrixserverlib.PerformInvite(ctx, input, r.FSAPI)
if err != nil {
switch e := err.(type) {
@ -199,20 +237,6 @@ func (r *Inviter) PerformInvite(
return err
}
// Use the returned event if there was one (due to federation), otherwise
// send the original invite event to the roomserver.
if inviteEvent == nil {
inviteEvent = event
}
// if we invited a local user, we can also create a user room key, if it doesn't exist yet.
if isTargetLocal && event.Version() == gomatrixserverlib.RoomVersionPseudoIDs {
_, err = r.RSAPI.GetOrCreateUserRoomPrivateKey(ctx, *invitedUser, *validRoomID)
if err != nil {
return fmt.Errorf("failed to get user room private key: %w", err)
}
}
// Send the invite event to the roomserver input stream. This will
// notify existing users in the room about the invite, update the
// membership table and ensure that the event is ready and available
@ -223,7 +247,7 @@ func (r *Inviter) PerformInvite(
{
Kind: api.KindNew,
Event: &types.HeaderedEvent{PDU: inviteEvent},
Origin: sender.Domain(),
Origin: req.InviteInput.Inviter.Domain(),
SendAsServer: req.SendAsServer,
},
},
@ -231,7 +255,7 @@ func (r *Inviter) PerformInvite(
inputRes := &api.InputRoomEventsResponse{}
r.Inputer.InputRoomEvents(context.Background(), inputReq, inputRes)
if err := inputRes.Err(); err != nil {
util.GetLogger(ctx).WithField("event_id", event.EventID()).Error("r.InputRoomEvents failed")
util.GetLogger(ctx).WithField("event_id", inviteEvent.EventID()).Error("r.InputRoomEvents failed")
return api.ErrNotAllowed{Err: err}
}

View file

@ -313,7 +313,7 @@ func (r *Joiner) performJoinRoomByID(
// sign the event with the pseudo ID key
identity = fclient.SigningIdentity{
ServerName: "self",
ServerName: spec.ServerName(spec.SenderIDFromPseudoIDKey(pseudoIDKey)),
KeyID: "ed25519:1",
PrivateKey: pseudoIDKey,
}

View file

@ -70,7 +70,7 @@ func (s *NATSInstance) Prepare(process *process.ProcessContext, cfg *config.JetS
process.ComponentFinished()
}()
}
if !s.ReadyForConnections(time.Second * 10) {
if !s.ReadyForConnections(time.Second * 60) {
logrus.Fatalln("NATS did not start in time")
}
// reuse existing connections

View file

@ -565,20 +565,18 @@ func (s *OutputRoomEventConsumer) updateStateEvent(event *rstypes.HeaderedEvent)
return event, err
}
if event.StateKey() != nil {
if *event.StateKey() != "" {
sKeyUser := ""
if stateKey != "" {
var sku *spec.UserID
sku, err = s.rsAPI.QueryUserIDForSender(s.ctx, *validRoomID, spec.SenderID(stateKey))
if err == nil && sku != nil {
sKey := sku.String()
event.StateKeyResolved = &sKey
stateKey = sKey
}
sKeyUser = sku.String()
event.StateKeyResolved = &sKeyUser
}
}
prevEvent, err := snapshot.GetStateEvent(
s.ctx, event.RoomID(), event.Type(), stateKey,
s.ctx, event.RoomID(), event.Type(), sKeyUser,
)
if err != nil {
return event, err

View file

@ -115,7 +115,7 @@ func (n *Notifier) OnNewEvent(
// If this is an invite, also add in the invitee to this list.
if ev.Type() == "m.room.member" && ev.StateKey() != nil {
targetUserID, err := n.rsAPI.QueryUserIDForSender(context.Background(), *validRoomID, spec.SenderID(*ev.StateKey()))
if err != nil {
if err != nil || targetUserID == nil {
log.WithError(err).WithField("event_id", ev.EventID()).Errorf(
"Notifier.OnNewEvent: Failed to find the userID for this event",
)

View file

@ -313,10 +313,12 @@ func (s *OutputRoomEventConsumer) processMessage(ctx context.Context, event *rst
sk := event.StateKey()
if sk != nil && *sk != "" {
skUserID, queryErr := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*event.StateKey()))
skUserID, queryErr := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*sk))
if queryErr == nil && skUserID != nil {
skString := skUserID.String()
sk = &skString
} else {
return fmt.Errorf("queryUserIDForSender: userID unknown for %s", *sk)
}
}
cevent := synctypes.ToClientEvent(event, synctypes.FormatAll, sender, sk)