Merge branch 'main' of github.com:matrix-org/dendrite into gh-pages

This commit is contained in:
Till Faelligen 2023-09-28 12:06:51 +02:00
commit b5312d1421
No known key found for this signature in database
GPG key ID: 3DF82D8AB9211D4E
92 changed files with 1515 additions and 840 deletions

View file

@ -280,6 +280,8 @@ jobs:
with: with:
go-version: "stable" go-version: "stable"
cache: true cache: true
- name: Docker version
run: docker version
- name: Build upgrade-tests - name: Build upgrade-tests
run: go build ./cmd/dendrite-upgrade-tests run: go build ./cmd/dendrite-upgrade-tests
- name: Test upgrade (PostgreSQL) - name: Test upgrade (PostgreSQL)
@ -300,6 +302,8 @@ jobs:
with: with:
go-version: "stable" go-version: "stable"
cache: true cache: true
- name: Docker version
run: docker version
- name: Build upgrade-tests - name: Build upgrade-tests
run: go build ./cmd/dendrite-upgrade-tests run: go build ./cmd/dendrite-upgrade-tests
- name: Test upgrade (PostgreSQL) - name: Test upgrade (PostgreSQL)

View file

@ -32,7 +32,7 @@ jobs:
version: v3.10.0 version: v3.10.0
- name: Run chart-releaser - name: Run chart-releaser
uses: helm/chart-releaser-action@v1.4.1 uses: helm/chart-releaser-action@ed43eb303604cbc0eeec8390544f7748dc6c790d # specific commit, since `mark_as_latest` is not yet in a release
env: env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
with: with:

View file

@ -128,7 +128,7 @@ jobs:
# See https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md specifically GOROOT_1_17_X64 # See https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md specifically GOROOT_1_17_X64
run: | run: |
sudo apt-get update && sudo apt-get install -y libolm3 libolm-dev sudo apt-get update && sudo apt-get install -y libolm3 libolm-dev
go get -v github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest go install github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest
- name: Run actions/checkout@v3 for dendrite - name: Run actions/checkout@v3 for dendrite
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:

View file

@ -1,5 +1,24 @@
# Changelog # Changelog
## Dendrite 0.13.3 (2023-09-28)
### Fixes:
- The `user_id` query parameter when authenticating is now used correctly (contributed by [tulir](https://github.com/tulir))
- Invitations are now correctly pushed to devices
- A bug which could result in the corruption of `m.direct` account data has been fixed
### Features
- [Sliding Sync proxy](https://github.com/matrix-org/sliding-sync) can be configured in the `/.well-known/matrix/client` response
- Room version 11 is now supported
- Clients can request the `federation` `event_format` when creating filters
- Many under the hood improvements for [MSC4014: Pseudonymous Identities](https://github.com/matrix-org/matrix-spec-proposals/blob/kegan/pseudo-ids/proposals/4014-pseudonymous-identities.md)
### Other
- Dendrite now requires Go 1.20 if building from source
## Dendrite 0.13.2 (2023-08-23) ## Dendrite 0.13.2 (2023-08-23)
### Fixes: ### Fixes:

View file

@ -36,7 +36,7 @@ If you have further questions, please take a look at [our FAQ](docs/FAQ.md) or j
See the [Planning your Installation](https://matrix-org.github.io/dendrite/installation/planning) page for See the [Planning your Installation](https://matrix-org.github.io/dendrite/installation/planning) page for
more information on requirements. more information on requirements.
To build Dendrite, you will need Go 1.18 or later. To build Dendrite, you will need Go 1.20 or later.
For a usable federating Dendrite deployment, you will also need: For a usable federating Dendrite deployment, you will also need:

View file

@ -128,7 +128,7 @@ func (s *OutputRoomEventConsumer) onMessage(
if len(output.NewRoomEvent.AddsStateEventIDs) > 0 { if len(output.NewRoomEvent.AddsStateEventIDs) > 0 {
newEventID := output.NewRoomEvent.Event.EventID() newEventID := output.NewRoomEvent.Event.EventID()
eventsReq := &api.QueryEventsByIDRequest{ eventsReq := &api.QueryEventsByIDRequest{
RoomID: output.NewRoomEvent.Event.RoomID(), RoomID: output.NewRoomEvent.Event.RoomID().String(),
EventIDs: make([]string, 0, len(output.NewRoomEvent.AddsStateEventIDs)), EventIDs: make([]string, 0, len(output.NewRoomEvent.AddsStateEventIDs)),
} }
eventsRes := &api.QueryEventsByIDResponse{} eventsRes := &api.QueryEventsByIDResponse{}
@ -236,11 +236,7 @@ func (s *appserviceState) backoffAndPause(err error) error {
// TODO: This should be cached, see https://github.com/matrix-org/dendrite/issues/1682 // TODO: This should be cached, see https://github.com/matrix-org/dendrite/issues/1682
func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Context, event *types.HeaderedEvent, appservice *config.ApplicationService) bool { func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Context, event *types.HeaderedEvent, appservice *config.ApplicationService) bool {
user := "" user := ""
validRoomID, err := spec.NewRoomID(event.RoomID()) userID, err := s.rsAPI.QueryUserIDForSender(ctx, event.RoomID(), event.SenderID())
if err != nil {
return false
}
userID, err := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, event.SenderID())
if err == nil { if err == nil {
user = userID.String() user = userID.String()
} }
@ -250,7 +246,7 @@ func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Cont
return false return false
case appservice.IsInterestedInUserID(user): case appservice.IsInterestedInUserID(user):
return true return true
case appservice.IsInterestedInRoomID(event.RoomID()): case appservice.IsInterestedInRoomID(event.RoomID().String()):
return true return true
} }
@ -261,7 +257,7 @@ func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Cont
} }
// Check all known room aliases of the room the event came from // Check all known room aliases of the room the event came from
queryReq := api.GetAliasesForRoomIDRequest{RoomID: event.RoomID()} queryReq := api.GetAliasesForRoomIDRequest{RoomID: event.RoomID().String()}
var queryRes api.GetAliasesForRoomIDResponse var queryRes api.GetAliasesForRoomIDResponse
if err := s.rsAPI.GetAliasesForRoomID(ctx, &queryReq, &queryRes); err == nil { if err := s.rsAPI.GetAliasesForRoomID(ctx, &queryReq, &queryRes); err == nil {
for _, alias := range queryRes.Aliases { for _, alias := range queryRes.Aliases {
@ -272,7 +268,7 @@ func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Cont
} else { } else {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"appservice": appservice.ID, "appservice": appservice.ID,
"room_id": event.RoomID(), "room_id": event.RoomID().String(),
}).WithError(err).Errorf("Unable to get aliases for room") }).WithError(err).Errorf("Unable to get aliases for room")
} }
@ -288,7 +284,7 @@ func (s *OutputRoomEventConsumer) appserviceJoinedAtEvent(ctx context.Context, e
// until we have a lighter way of checking the state before the event that // until we have a lighter way of checking the state before the event that
// doesn't involve state res, then this is probably OK. // doesn't involve state res, then this is probably OK.
membershipReq := &api.QueryMembershipsForRoomRequest{ membershipReq := &api.QueryMembershipsForRoomRequest{
RoomID: event.RoomID(), RoomID: event.RoomID().String(),
JoinedOnly: true, JoinedOnly: true,
} }
membershipRes := &api.QueryMembershipsForRoomResponse{} membershipRes := &api.QueryMembershipsForRoomResponse{}
@ -317,7 +313,7 @@ func (s *OutputRoomEventConsumer) appserviceJoinedAtEvent(ctx context.Context, e
} else { } else {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"appservice": appservice.ID, "appservice": appservice.ID,
"room_id": event.RoomID(), "room_id": event.RoomID().String(),
}).WithError(err).Errorf("Unable to get membership for room") }).WithError(err).Errorf("Unable to get membership for room")
} }
return false return false

View file

@ -944,4 +944,12 @@ rmv remote user can join room with version 10
rmv User can invite remote user to room with version 10 rmv User can invite remote user to room with version 10
rmv Remote user can backfill in a room with version 10 rmv Remote user can backfill in a room with version 10
rmv Can reject invites over federation for rooms with version 10 rmv Can reject invites over federation for rooms with version 10
rmv Can receive redactions from regular users over federation in room version 10 rmv Can receive redactions from regular users over federation in room version 10
rmv User can create and send/receive messages in a room with version 11
rmv local user can join room with version 11
rmv User can invite local user to room with version 11
rmv remote user can join room with version 11
rmv User can invite remote user to room with version 11
rmv Remote user can backfill in a room with version 11
rmv Can reject invites over federation for rooms with version 11
rmv Can receive redactions from regular users over federation in room version 11

View file

@ -34,7 +34,8 @@ import (
) )
type redactionContent struct { type redactionContent struct {
Reason string `json:"reason"` Reason string `json:"reason"`
Redacts string `json:"redacts"`
} }
type redactionResponse struct { type redactionResponse struct {
@ -98,7 +99,7 @@ func SendRedaction(
JSON: spec.NotFound("unknown event ID"), // TODO: is it ok to leak existence? JSON: spec.NotFound("unknown event ID"), // TODO: is it ok to leak existence?
} }
} }
if ev.RoomID() != roomID { if ev.RoomID().String() != roomID {
return util.JSONResponse{ return util.JSONResponse{
Code: 400, Code: 400,
JSON: spec.NotFound("cannot redact event in another room"), JSON: spec.NotFound("cannot redact event in another room"),
@ -151,6 +152,11 @@ func SendRedaction(
Type: spec.MRoomRedaction, Type: spec.MRoomRedaction,
Redacts: eventID, Redacts: eventID,
} }
// Room version 11 expects the "redacts" field on the
// content field, so add it here as well
r.Redacts = eventID
err = proto.SetContent(r) err = proto.SetContent(r)
if err != nil { if err != nil {
util.GetLogger(req.Context()).WithError(err).Error("proto.SetContent failed") util.GetLogger(req.Context()).WithError(err).Error("proto.SetContent failed")

View file

@ -263,7 +263,11 @@ func SendEvent(
} }
func updatePowerLevels(req *http.Request, r map[string]interface{}, roomID string, rsAPI api.ClientRoomserverAPI) error { func updatePowerLevels(req *http.Request, r map[string]interface{}, roomID string, rsAPI api.ClientRoomserverAPI) error {
userMap := r["users"].(map[string]interface{}) users, ok := r["users"]
if !ok {
return nil
}
userMap := users.(map[string]interface{})
validRoomID, err := spec.NewRoomID(roomID) validRoomID, err := spec.NewRoomID(roomID)
if err != nil { if err != nil {
return err return err
@ -277,7 +281,8 @@ func updatePowerLevels(req *http.Request, r map[string]interface{}, roomID strin
if err != nil { if err != nil {
return err return err
} else if senderID == nil { } else if senderID == nil {
return fmt.Errorf("sender ID not found for %s in %s", uID, *validRoomID) util.GetLogger(req.Context()).Warnf("sender ID not found for %s in %s", uID, *validRoomID)
continue
} }
userMap[string(*senderID)] = level userMap[string(*senderID)] = level
delete(userMap, user) delete(userMap, user)
@ -437,7 +442,7 @@ func generateSendEvent(
JSON: spec.BadJSON("Cannot unmarshal the event content."), JSON: spec.BadJSON("Cannot unmarshal the event content."),
} }
} }
if content["replacement_room"] == e.RoomID() { if content["replacement_room"] == e.RoomID().String() {
return nil, &util.JSONResponse{ return nil, &util.JSONResponse{
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
JSON: spec.InvalidParam("Cannot send tombstone event that points to the same room."), JSON: spec.InvalidParam("Cannot send tombstone event that points to the same room."),

View file

@ -172,28 +172,16 @@ func OnIncomingStateRequest(ctx context.Context, device *userapi.Device, rsAPI a
} }
} }
for _, ev := range stateAfterRes.StateEvents { for _, ev := range stateAfterRes.StateEvents {
sender := spec.UserID{} clientEvent, err := synctypes.ToClientEvent(ev, synctypes.FormatAll, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
evRoomID, err := spec.NewRoomID(ev.RoomID()) return rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
})
if err != nil { if err != nil {
util.GetLogger(ctx).WithError(err).Error("Event roomID is invalid") util.GetLogger(ctx).WithError(err).Error("Failed converting to ClientEvent")
continue continue
} }
userID, err := rsAPI.QueryUserIDForSender(ctx, *evRoomID, ev.SenderID())
if err == nil && userID != nil {
sender = *userID
}
sk := ev.StateKey()
if sk != nil && *sk != "" {
skUserID, err := rsAPI.QueryUserIDForSender(ctx, *evRoomID, spec.SenderID(*ev.StateKey()))
if err == nil && skUserID != nil {
skString := skUserID.String()
sk = &skString
}
}
stateEvents = append( stateEvents = append(
stateEvents, stateEvents,
synctypes.ToClientEvent(ev, synctypes.FormatAll, sender, sk), *clientEvent,
) )
} }
} }

View file

@ -1,6 +1,6 @@
# Yggdrasil Demo # Yggdrasil Demo
This is the Dendrite Yggdrasil demo! It's easy to get started - all you need is Go 1.18 or later. This is the Dendrite Yggdrasil demo! It's easy to get started - all you need is Go 1.20 or later.
To run the homeserver, start at the root of the Dendrite repository and run: To run the homeserver, start at the root of the Dendrite repository and run:

View file

@ -7,7 +7,6 @@ import (
"flag" "flag"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"log" "log"
"net/http" "net/http"
"os" "os"
@ -55,7 +54,7 @@ var latest, _ = semver.NewVersion("v6.6.6") // Dummy version, used as "HEAD"
// due to the error: // due to the error:
// When using COPY with more than one source file, the destination must be a directory and end with a / // When using COPY with more than one source file, the destination must be a directory and end with a /
// We need to run a postgres anyway, so use the dockerfile associated with Complement instead. // We need to run a postgres anyway, so use the dockerfile associated with Complement instead.
const DockerfilePostgreSQL = `FROM golang:1.18-buster as build const DockerfilePostgreSQL = `FROM golang:1.20-bookworm as build
RUN apt-get update && apt-get install -y postgresql RUN apt-get update && apt-get install -y postgresql
WORKDIR /build WORKDIR /build
ARG BINARY ARG BINARY
@ -74,16 +73,16 @@ RUN ./generate-keys --private-key matrix_key.pem --tls-cert server.crt --tls-key
# Replace the connection string with a single postgres DB, using user/db = 'postgres' and no password # Replace the connection string with a single postgres DB, using user/db = 'postgres' and no password
RUN sed -i "s%connection_string:.*$%connection_string: postgresql://postgres@localhost/postgres?sslmode=disable%g" dendrite.yaml RUN sed -i "s%connection_string:.*$%connection_string: postgresql://postgres@localhost/postgres?sslmode=disable%g" dendrite.yaml
# No password when connecting over localhost # No password when connecting over localhost
RUN sed -i "s%127.0.0.1/32 md5%127.0.0.1/32 trust%g" /etc/postgresql/11/main/pg_hba.conf RUN sed -i "s%127.0.0.1/32 scram-sha-256%127.0.0.1/32 trust%g" /etc/postgresql/15/main/pg_hba.conf
# Bump up max conns for moar concurrency # Bump up max conns for moar concurrency
RUN sed -i 's/max_connections = 100/max_connections = 2000/g' /etc/postgresql/11/main/postgresql.conf RUN sed -i 's/max_connections = 100/max_connections = 2000/g' /etc/postgresql/15/main/postgresql.conf
RUN sed -i 's/max_open_conns:.*$/max_open_conns: 100/g' dendrite.yaml RUN sed -i 's/max_open_conns:.*$/max_open_conns: 100/g' dendrite.yaml
# This entry script starts postgres, waits for it to be up then starts dendrite # This entry script starts postgres, waits for it to be up then starts dendrite
RUN echo '\ RUN echo '\
#!/bin/bash -eu \n\ #!/bin/bash -eu \n\
pg_lsclusters \n\ pg_lsclusters \n\
pg_ctlcluster 11 main start \n\ pg_ctlcluster 15 main start \n\
\n\ \n\
until pg_isready \n\ until pg_isready \n\
do \n\ do \n\
@ -101,7 +100,7 @@ ENV BINARY=dendrite
EXPOSE 8008 8448 EXPOSE 8008 8448
CMD /build/run_dendrite.sh` CMD /build/run_dendrite.sh`
const DockerfileSQLite = `FROM golang:1.18-buster as build const DockerfileSQLite = `FROM golang:1.20-bookworm as build
RUN apt-get update && apt-get install -y postgresql RUN apt-get update && apt-get install -y postgresql
WORKDIR /build WORKDIR /build
ARG BINARY ARG BINARY
@ -119,7 +118,7 @@ RUN ./generate-keys --private-key matrix_key.pem --tls-cert server.crt --tls-key
# Make sure the SQLite databases are in a persistent location, we're already mapping # Make sure the SQLite databases are in a persistent location, we're already mapping
# the postgresql folder so let's just use that for simplicity # the postgresql folder so let's just use that for simplicity
RUN sed -i "s%connection_string:.file:%connection_string: file:\/var\/lib\/postgresql\/11\/main\/%g" dendrite.yaml RUN sed -i "s%connection_string:.file:%connection_string: file:\/var\/lib\/postgresql\/15\/main\/%g" dendrite.yaml
# This entry script starts postgres, waits for it to be up then starts dendrite # This entry script starts postgres, waits for it to be up then starts dendrite
RUN echo '\ RUN echo '\
@ -402,7 +401,7 @@ func runImage(dockerClient *client.Client, volumeName string, branchNameToImageI
{ {
Type: mount.TypeVolume, Type: mount.TypeVolume,
Source: volumeName, Source: volumeName,
Target: "/var/lib/postgresql/11/main", Target: "/var/lib/postgresql/15/main",
}, },
}, },
}, nil, nil, "dendrite_upgrade_test_"+branchName) }, nil, nil, "dendrite_upgrade_test_"+branchName)
@ -515,7 +514,7 @@ func testCreateAccount(dockerClient *client.Client, version *semver.Version, con
} }
defer response.Close() defer response.Close()
data, err := ioutil.ReadAll(response.Reader) data, err := io.ReadAll(response.Reader)
if err != nil { if err != nil {
return err return err
} }
@ -557,8 +556,8 @@ func cleanup(dockerClient *client.Client) {
}) })
for _, c := range containers { for _, c := range containers {
log.Printf("Removing container: %v %v\n", c.ID, c.Names) log.Printf("Removing container: %v %v\n", c.ID, c.Names)
s := time.Second timeout := 1
_ = dockerClient.ContainerStop(context.Background(), c.ID, &s) _ = dockerClient.ContainerStop(context.Background(), c.ID, container.StopOptions{Timeout: &timeout})
_ = dockerClient.ContainerRemove(context.Background(), c.ID, types.ContainerRemoveOptions{ _ = dockerClient.ContainerRemove(context.Background(), c.ID, types.ContainerRemoveOptions{
Force: true, Force: true,
}) })
@ -592,7 +591,7 @@ func main() {
branchToImageID := buildDendriteImages(httpClient, dockerClient, *flagTempDir, *flagBuildConcurrency, versions) branchToImageID := buildDendriteImages(httpClient, dockerClient, *flagTempDir, *flagBuildConcurrency, versions)
// make a shared postgres volume // make a shared postgres volume
volume, err := dockerClient.VolumeCreate(context.Background(), volume.VolumeCreateBody{ volume, err := dockerClient.VolumeCreate(context.Background(), volume.CreateOptions{
Name: "dendrite_upgrade_test", Name: "dendrite_upgrade_test",
Labels: map[string]string{ Labels: map[string]string{
dendriteUpgradeTestLabel: "yes", dendriteUpgradeTestLabel: "yes",

View file

@ -14,7 +14,7 @@ GEM
execjs execjs
coffee-script-source (1.11.1) coffee-script-source (1.11.1)
colorator (1.1.0) colorator (1.1.0)
commonmarker (0.23.9) commonmarker (0.23.10)
concurrent-ruby (1.2.0) concurrent-ruby (1.2.0)
dnsruby (1.61.9) dnsruby (1.61.9)
simpleidn (~> 0.1) simpleidn (~> 0.1)

View file

@ -95,7 +95,7 @@ Consider enabling the DNS cache by modifying the `global` section of your config
## Time synchronisation ## Time synchronisation
Matrix relies heavily on TLS which requires the system time to be correct. If the clock Matrix relies heavily on TLS which requires the system time to be correct. If the clock
drifts then you may find that federation no works reliably (or at all) and clients may drifts then you may find that federation will not work reliably (or at all) and clients may
struggle to connect to your Dendrite server. struggle to connect to your Dendrite server.
Ensure that the time is synchronised on your system by enabling NTP sync. Ensure that the time is synchronised on your system by enabling NTP sync.

View file

@ -59,7 +59,7 @@ In order to install Dendrite, you will need to satisfy the following dependencie
### Go ### Go
At this time, Dendrite supports being built with Go 1.18 or later. We do not support building At this time, Dendrite supports being built with Go 1.20 or later. We do not support building
Dendrite with older versions of Go than this. If you are installing Go using a package manager, Dendrite with older versions of Go than this. If you are installing Go using a package manager,
you should check (by running `go version`) that you are using a suitable version before you start. you should check (by running `go version`) that you are using a suitable version before you start.

View file

@ -176,7 +176,7 @@ func (s *OutputRoomEventConsumer) processMessage(ore api.OutputNewRoomEvent, rew
// Finally, work out if there are any more events missing. // Finally, work out if there are any more events missing.
if len(missingEventIDs) > 0 { if len(missingEventIDs) > 0 {
eventsReq := &api.QueryEventsByIDRequest{ eventsReq := &api.QueryEventsByIDRequest{
RoomID: ore.Event.RoomID(), RoomID: ore.Event.RoomID().String(),
EventIDs: missingEventIDs, EventIDs: missingEventIDs,
} }
eventsRes := &api.QueryEventsByIDResponse{} eventsRes := &api.QueryEventsByIDResponse{}
@ -205,7 +205,7 @@ func (s *OutputRoomEventConsumer) processMessage(ore api.OutputNewRoomEvent, rew
// talking to the roomserver // talking to the roomserver
oldJoinedHosts, err := s.db.UpdateRoom( oldJoinedHosts, err := s.db.UpdateRoom(
s.ctx, s.ctx,
ore.Event.RoomID(), ore.Event.RoomID().String(),
addsJoinedHosts, addsJoinedHosts,
ore.RemovesStateEventIDs, ore.RemovesStateEventIDs,
rewritesState, // if we're re-writing state, nuke all joined hosts before adding rewritesState, // if we're re-writing state, nuke all joined hosts before adding
@ -218,7 +218,7 @@ func (s *OutputRoomEventConsumer) processMessage(ore api.OutputNewRoomEvent, rew
if s.cfg.Matrix.Presence.EnableOutbound && len(addsJoinedHosts) > 0 && ore.Event.Type() == spec.MRoomMember && ore.Event.StateKey() != nil { if s.cfg.Matrix.Presence.EnableOutbound && len(addsJoinedHosts) > 0 && ore.Event.Type() == spec.MRoomMember && ore.Event.StateKey() != nil {
membership, _ := ore.Event.Membership() membership, _ := ore.Event.Membership()
if membership == spec.Join { if membership == spec.Join {
s.sendPresence(ore.Event.RoomID(), addsJoinedHosts) s.sendPresence(ore.Event.RoomID().String(), addsJoinedHosts)
} }
} }
@ -376,7 +376,7 @@ func (s *OutputRoomEventConsumer) joinedHostsAtEvent(
} }
// handle peeking hosts // handle peeking hosts
inboundPeeks, err := s.db.GetInboundPeeks(s.ctx, ore.Event.PDU.RoomID()) inboundPeeks, err := s.db.GetInboundPeeks(s.ctx, ore.Event.PDU.RoomID().String())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -409,12 +409,8 @@ func JoinedHostsFromEvents(ctx context.Context, evs []gomatrixserverlib.PDU, rsA
if membership != spec.Join { if membership != spec.Join {
continue continue
} }
validRoomID, err := spec.NewRoomID(ev.RoomID())
if err != nil {
return nil, err
}
var domain spec.ServerName var domain spec.ServerName
userID, err := rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*ev.StateKey())) userID, err := rsAPI.QueryUserIDForSender(ctx, ev.RoomID(), spec.SenderID(*ev.StateKey()))
if err != nil { if err != nil {
if errors.As(err, new(base64.CorruptInputError)) { if errors.As(err, new(base64.CorruptInputError)) {
// Fallback to using the "old" way of getting the user domain, avoids // Fallback to using the "old" way of getting the user domain, avoids
@ -510,7 +506,7 @@ func (s *OutputRoomEventConsumer) lookupStateEvents(
// At this point the missing events are neither the event itself nor are // At this point the missing events are neither the event itself nor are
// they present in our local database. Our only option is to fetch them // they present in our local database. Our only option is to fetch them
// from the roomserver using the query API. // from the roomserver using the query API.
eventReq := api.QueryEventsByIDRequest{EventIDs: missing, RoomID: event.RoomID()} eventReq := api.QueryEventsByIDRequest{EventIDs: missing, RoomID: event.RoomID().String()}
var eventResp api.QueryEventsByIDResponse var eventResp api.QueryEventsByIDResponse
if err := s.rsAPI.QueryEventsByID(s.ctx, &eventReq, &eventResp); err != nil { if err := s.rsAPI.QueryEventsByID(s.ctx, &eventReq, &eventResp); err != nil {
return nil, err return nil, err

View file

@ -146,7 +146,7 @@ func (f *fedClient) SendJoin(ctx context.Context, origin, s spec.ServerName, eve
f.fedClientMutex.Lock() f.fedClientMutex.Lock()
defer f.fedClientMutex.Unlock() defer f.fedClientMutex.Unlock()
for _, r := range f.allowJoins { for _, r := range f.allowJoins {
if r.ID == event.RoomID() { if r.ID == event.RoomID().String() {
r.InsertEvent(f.t, &types.HeaderedEvent{PDU: event}) r.InsertEvent(f.t, &types.HeaderedEvent{PDU: event})
f.t.Logf("Join event: %v", event.EventID()) f.t.Logf("Join event: %v", event.EventID())
res.StateEvents = types.NewEventJSONsFromHeaderedEvents(r.CurrentState()) res.StateEvents = types.NewEventJSONsFromHeaderedEvents(r.CurrentState())

View file

@ -548,11 +548,7 @@ func (r *FederationInternalAPI) SendInvite(
event gomatrixserverlib.PDU, event gomatrixserverlib.PDU,
strippedState []gomatrixserverlib.InviteStrippedState, strippedState []gomatrixserverlib.InviteStrippedState,
) (gomatrixserverlib.PDU, error) { ) (gomatrixserverlib.PDU, error) {
validRoomID, err := spec.NewRoomID(event.RoomID()) inviter, err := r.rsAPI.QueryUserIDForSender(ctx, event.RoomID(), event.SenderID())
if err != nil {
return nil, err
}
inviter, err := r.rsAPI.QueryUserIDForSender(ctx, *validRoomID, event.SenderID())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -575,7 +571,7 @@ func (r *FederationInternalAPI) SendInvite(
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"event_id": event.EventID(), "event_id": event.EventID(),
"user_id": *event.StateKey(), "user_id": *event.StateKey(),
"room_id": event.RoomID(), "room_id": event.RoomID().String(),
"room_version": event.Version(), "room_version": event.Version(),
"destination": destination, "destination": destination,
}).Info("Sending invite") }).Info("Sending invite")

View file

@ -218,7 +218,7 @@ func (oqs *OutgoingQueues) SendEvent(
if api.IsServerBannedFromRoom( if api.IsServerBannedFromRoom(
oqs.process.Context(), oqs.process.Context(),
oqs.rsAPI, oqs.rsAPI,
ev.RoomID(), ev.RoomID().String(),
destination, destination,
) { ) {
delete(destmap, destination) delete(destmap, destination)

View file

@ -104,7 +104,7 @@ func (f *stubFederationClient) P2PSendTransactionToRelay(ctx context.Context, u
func mustCreatePDU(t *testing.T) *types.HeaderedEvent { func mustCreatePDU(t *testing.T) *types.HeaderedEvent {
t.Helper() t.Helper()
content := `{"type":"m.room.message"}` content := `{"type":"m.room.message", "room_id":"!room:a"}`
ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionV10).NewEventFromTrustedJSON([]byte(content), false) ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionV10).NewEventFromTrustedJSON([]byte(content), false)
if err != nil { if err != nil {
t.Fatalf("failed to create event: %v", err) t.Fatalf("failed to create event: %v", err)

View file

@ -109,7 +109,7 @@ func Backfill(
var ev *types.HeaderedEvent var ev *types.HeaderedEvent
for _, ev = range res.Events { for _, ev = range res.Events {
if ev.RoomID() == roomID { if ev.RoomID().String() == roomID {
evs = append(evs, ev.PDU) evs = append(evs, ev.PDU)
} }
} }

View file

@ -42,10 +42,10 @@ func GetEventAuth(
return *resErr return *resErr
} }
if event.RoomID() != roomID { if event.RoomID().String() != roomID {
return util.JSONResponse{Code: http.StatusNotFound, JSON: spec.NotFound("event does not belong to this room")} return util.JSONResponse{Code: http.StatusNotFound, JSON: spec.NotFound("event does not belong to this room")}
} }
resErr = allowedToSeeEvent(ctx, request.Origin(), rsAPI, eventID, event.RoomID()) resErr = allowedToSeeEvent(ctx, request.Origin(), rsAPI, eventID, event.RoomID().String())
if resErr != nil { if resErr != nil {
return *resErr return *resErr
} }

View file

@ -42,7 +42,7 @@ func GetEvent(
return *err return *err
} }
err = allowedToSeeEvent(ctx, request.Origin(), rsAPI, eventID, event.RoomID()) err = allowedToSeeEvent(ctx, request.Origin(), rsAPI, eventID, event.RoomID().String())
if err != nil { if err != nil {
return *err return *err
} }

View file

@ -211,7 +211,7 @@ func SendLeave(
} }
// Check that the room ID is correct. // Check that the room ID is correct.
if event.RoomID() != roomID { if event.RoomID().String() != roomID {
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
JSON: spec.BadJSON("The room ID in the request path must match the room ID in the leave event JSON"), JSON: spec.BadJSON("The room ID in the request path must match the room ID in the leave event JSON"),
@ -242,14 +242,7 @@ func SendLeave(
// Check that the sender belongs to the server that is sending us // Check that the sender belongs to the server that is sending us
// the request. By this point we've already asserted that the sender // the request. By this point we've already asserted that the sender
// and the state key are equal so we don't need to check both. // and the state key are equal so we don't need to check both.
validRoomID, err := spec.NewRoomID(event.RoomID()) sender, err := rsAPI.QueryUserIDForSender(httpReq.Context(), event.RoomID(), event.SenderID())
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.BadJSON("Room ID is invalid."),
}
}
sender, err := rsAPI.QueryUserIDForSender(httpReq.Context(), *validRoomID, event.SenderID())
if err != nil { if err != nil {
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusForbidden, Code: http.StatusForbidden,

View file

@ -87,7 +87,7 @@ func filterEvents(
) []*types.HeaderedEvent { ) []*types.HeaderedEvent {
ref := events[:0] ref := events[:0]
for _, ev := range events { for _, ev := range events {
if ev.RoomID() == roomID { if ev.RoomID().String() == roomID {
ref = append(ref, ev) ref = append(ref, ev)
} }
} }

View file

@ -113,10 +113,10 @@ func getState(
return nil, nil, resErr return nil, nil, resErr
} }
if event.RoomID() != roomID { if event.RoomID().String() != roomID {
return nil, nil, &util.JSONResponse{Code: http.StatusNotFound, JSON: spec.NotFound("event does not belong to this room")} return nil, nil, &util.JSONResponse{Code: http.StatusNotFound, JSON: spec.NotFound("event does not belong to this room")}
} }
resErr = allowedToSeeEvent(ctx, request.Origin(), rsAPI, eventID, event.RoomID()) resErr = allowedToSeeEvent(ctx, request.Origin(), rsAPI, eventID, event.RoomID().String())
if resErr != nil { if resErr != nil {
return nil, nil, resErr return nil, nil, resErr
} }

16
go.mod
View file

@ -9,7 +9,7 @@ require (
github.com/blevesearch/bleve/v2 v2.3.8 github.com/blevesearch/bleve/v2 v2.3.8
github.com/codeclysm/extract v2.2.0+incompatible github.com/codeclysm/extract v2.2.0+incompatible
github.com/dgraph-io/ristretto v0.1.1 github.com/dgraph-io/ristretto v0.1.1
github.com/docker/docker v20.10.24+incompatible github.com/docker/docker v24.0.5+incompatible
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/getsentry/sentry-go v0.14.0 github.com/getsentry/sentry-go v0.14.0
github.com/gologme/log v1.3.0 github.com/gologme/log v1.3.0
@ -22,7 +22,7 @@ require (
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e 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/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530
github.com/matrix-org/gomatrixserverlib v0.0.0-20230823153616-484e7693bb8d github.com/matrix-org/gomatrixserverlib v0.0.0-20230926165653-79fcff283fc4
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7 github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 github.com/matrix-org/util v0.0.0-20221111132719-399730281e66
github.com/mattn/go-sqlite3 v1.14.17 github.com/mattn/go-sqlite3 v1.14.17
@ -36,18 +36,18 @@ require (
github.com/prometheus/client_golang v1.16.0 github.com/prometheus/client_golang v1.16.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.2 github.com/stretchr/testify v1.8.2
github.com/tidwall/gjson v1.16.0 github.com/tidwall/gjson v1.17.0
github.com/tidwall/sjson v1.2.5 github.com/tidwall/sjson v1.2.5
github.com/uber/jaeger-client-go v2.30.0+incompatible github.com/uber/jaeger-client-go v2.30.0+incompatible
github.com/uber/jaeger-lib v2.4.1+incompatible github.com/uber/jaeger-lib v2.4.1+incompatible
github.com/yggdrasil-network/yggdrasil-go v0.4.6 github.com/yggdrasil-network/yggdrasil-go v0.4.6
go.uber.org/atomic v1.10.0 go.uber.org/atomic v1.10.0
golang.org/x/crypto v0.12.0 golang.org/x/crypto v0.13.0
golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819
golang.org/x/image v0.5.0 golang.org/x/image v0.5.0
golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e
golang.org/x/sync v0.3.0 golang.org/x/sync v0.3.0
golang.org/x/term v0.11.0 golang.org/x/term v0.12.0
gopkg.in/h2non/bimg.v1 v1.1.9 gopkg.in/h2non/bimg.v1 v1.1.9
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.4.0 gotest.tools/v3 v3.4.0
@ -124,8 +124,8 @@ require (
go.etcd.io/bbolt v1.3.6 // indirect go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/mod v0.12.0 // indirect golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.14.0 // indirect golang.org/x/net v0.14.0 // indirect
golang.org/x/sys v0.11.0 // indirect golang.org/x/sys v0.12.0 // indirect
golang.org/x/text v0.12.0 // indirect golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.12.0 // indirect golang.org/x/tools v0.12.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect google.golang.org/protobuf v1.30.0 // indirect
@ -143,4 +143,4 @@ require (
modernc.org/token v1.0.1 // indirect modernc.org/token v1.0.1 // indirect
) )
go 1.18 go 1.20

28
go.sum
View file

@ -89,8 +89,8 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczC
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.24+incompatible h1:Ugvxm7a8+Gz6vqQYQQ2W7GYq5EUPaAiuPgIfVyI3dYE= github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY=
github.com/docker/docker v20.10.24+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
@ -208,8 +208,8 @@ 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/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 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
github.com/matrix-org/gomatrixserverlib v0.0.0-20230823153616-484e7693bb8d h1:yFoT2nyjD4TFrgYMJGgrotFbTLjaYKfZbRmnsj7lvZE= github.com/matrix-org/gomatrixserverlib v0.0.0-20230926165653-79fcff283fc4 h1:UuXfC7b29RBDfMdLmggeF3opu3XuGi8bNT9SKZtZc3I=
github.com/matrix-org/gomatrixserverlib v0.0.0-20230823153616-484e7693bb8d/go.mod h1:H9V9N3Uqn1bBJqYJNGK1noqtgJTaCEhtTdcH/mp50uU= github.com/matrix-org/gomatrixserverlib v0.0.0-20230926165653-79fcff283fc4/go.mod h1:H9V9N3Uqn1bBJqYJNGK1noqtgJTaCEhtTdcH/mp50uU=
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7 h1:6t8kJr8i1/1I5nNttw6nn1ryQJgzVlBmSGgPiiaTdw4= github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7 h1:6t8kJr8i1/1I5nNttw6nn1ryQJgzVlBmSGgPiiaTdw4=
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7/go.mod h1:ReWMS/LoVnOiRAdq9sNUC2NZnd1mZkMNB52QhpTRWjg= github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7/go.mod h1:ReWMS/LoVnOiRAdq9sNUC2NZnd1mZkMNB52QhpTRWjg=
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y= github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=
@ -318,8 +318,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
@ -354,8 +354,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/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.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 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-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -418,19 +418,19 @@ 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-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-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.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.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-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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/text v0.3.0/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.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View file

@ -1,7 +1,7 @@
apiVersion: v2 apiVersion: v2
name: dendrite name: dendrite
version: "0.13.2" version: "0.13.4"
appVersion: "0.13.2" appVersion: "0.13.3"
description: Dendrite Matrix Homeserver description: Dendrite Matrix Homeserver
type: application type: application
keywords: keywords:

View file

@ -1,7 +1,7 @@
# dendrite # dendrite
![Version: 0.13.2](https://img.shields.io/badge/Version-0.13.2-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.13.2](https://img.shields.io/badge/AppVersion-0.13.2-informational?style=flat-square) ![Version: 0.13.4](https://img.shields.io/badge/Version-0.13.4-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.13.3](https://img.shields.io/badge/AppVersion-0.13.3-informational?style=flat-square)
Dendrite Matrix Homeserver Dendrite Matrix Homeserver
Status: **NOT PRODUCTION READY** Status: **NOT PRODUCTION READY**
@ -63,9 +63,6 @@ Create a folder `appservices` and place your configurations in there. The confi
| strategy.type | string | `"RollingUpdate"` | Strategy to use for rolling updates (e.g. Recreate, RollingUpdate) If you are using ReadWriteOnce volumes, you should probably use Recreate | | strategy.type | string | `"RollingUpdate"` | Strategy to use for rolling updates (e.g. Recreate, RollingUpdate) If you are using ReadWriteOnce volumes, you should probably use Recreate |
| strategy.rollingUpdate.maxUnavailable | string | `"25%"` | Maximum number of pods that can be unavailable during the update process | | strategy.rollingUpdate.maxUnavailable | string | `"25%"` | Maximum number of pods that can be unavailable during the update process |
| strategy.rollingUpdate.maxSurge | string | `"25%"` | Maximum number of pods that can be scheduled above the desired number of pods | | strategy.rollingUpdate.maxSurge | string | `"25%"` | Maximum number of pods that can be scheduled above the desired number of pods |
| strategy.type | string | `"RollingUpdate"` | Strategy to use for rolling updates (e.g. Recreate, RollingUpdate) If you are using ReadWriteOnce volumes, you should probably use Recreate |
| strategy.rollingUpdate.maxUnavailable | string | `"25%"` | Maximum number of pods that can be unavailable during the update process |
| strategy.rollingUpdate.maxSurge | string | `"25%"` | Maximum number of pods that can be scheduled above the desired number of pods |
| dendrite_config.version | int | `2` | | | dendrite_config.version | int | `2` | |
| dendrite_config.global.server_name | string | `""` | **REQUIRED** Servername for this Dendrite deployment. | | dendrite_config.global.server_name | string | `""` | **REQUIRED** Servername for this Dendrite deployment. |
| dendrite_config.global.private_key | string | `"/etc/dendrite/secrets/signing.key"` | The private key to use. (**NOTE**: This is overriden in Helm) | | dendrite_config.global.private_key | string | `"/etc/dendrite/secrets/signing.key"` | The private key to use. (**NOTE**: This is overriden in Helm) |

View file

@ -26,13 +26,6 @@ spec:
annotations: annotations:
confighash: secret-{{ .Values.dendrite_config | toYaml | sha256sum | trunc 32 }} confighash: secret-{{ .Values.dendrite_config | toYaml | sha256sum | trunc 32 }}
spec: spec:
strategy:
type: {{ $.Values.strategy.type }}
{{- if eq $.Values.strategy.type "RollingUpdate" }}
rollingUpdate:
maxSurge: {{ $.Values.strategy.rollingUpdate.maxSurge }}
maxUnavailable: {{ $.Values.strategy.rollingUpdate.maxUnavailable }}
{{- end }}
volumes: volumes:
- name: {{ include "dendrite.fullname" . }}-conf-vol - name: {{ include "dendrite.fullname" . }}-conf-vol
secret: secret:
@ -116,4 +109,4 @@ spec:
failureThreshold: 10 failureThreshold: 10
httpGet: httpGet:
path: /_dendrite/monitor/up path: /_dendrite/monitor/up
port: http port: http

View file

@ -1,8 +1,8 @@
{{- if .Values.ingress.enabled -}} {{- if .Values.ingress.enabled -}}
{{- $fullName := include "dendrite.fullname" . -}} {{- $fullName := include "dendrite.fullname" . -}}
{{- $serverNameHost := .Values.dendrite_config.global.server_name -}} {{- $serverNameHost := .Values.dendrite_config.global.server_name -}}
{{- $wellKnownServerHost := default $serverNameHost (regexFind "^[^:]+" .Values.dendrite_config.global.well_known_server_name) -}} {{- $wellKnownServerHost := default $serverNameHost (regexFind "^(\\[.+\\])?[^:]*" .Values.dendrite_config.global.well_known_server_name) -}}
{{- $wellKnownClientHost := default $serverNameHost (regexFind "^[^:]+" .Values.dendrite_config.global.well_known_client_name) -}} {{- $wellKnownClientHost := default $serverNameHost (regexFind "//(\\[.+\\])?[^:/]*" .Values.dendrite_config.global.well_known_client_name | trimAll "/") -}}
{{- $allHosts := list $serverNameHost $wellKnownServerHost $wellKnownClientHost | uniq -}} {{- $allHosts := list $serverNameHost $wellKnownServerHost $wellKnownClientHost | uniq -}}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1

View file

@ -65,16 +65,6 @@ extraVolumeMounts: []
# - mountPath: /etc/dendrite/extra-config # - mountPath: /etc/dendrite/extra-config
# name: extra-config # name: extra-config
strategy:
# -- Strategy to use for rolling updates (e.g. Recreate, RollingUpdate)
# If you are using ReadWriteOnce volumes, you should probably use Recreate
type: RollingUpdate
rollingUpdate:
# -- Maximum number of pods that can be unavailable during the update process
maxUnavailable: 25%
# -- Maximum number of pods that can be scheduled above the desired number of pods
maxSurge: 25%
strategy: strategy:
# -- Strategy to use for rolling updates (e.g. Recreate, RollingUpdate) # -- Strategy to use for rolling updates (e.g. Recreate, RollingUpdate)
# If you are using ReadWriteOnce volumes, you should probably use Recreate # If you are using ReadWriteOnce volumes, you should probably use Recreate

View file

@ -176,15 +176,13 @@ func RedactEvent(ctx context.Context, redactionEvent, redactedEvent gomatrixserv
return fmt.Errorf("RedactEvent: redactionEvent isn't a redaction event, is '%s'", redactionEvent.Type()) return fmt.Errorf("RedactEvent: redactionEvent isn't a redaction event, is '%s'", redactionEvent.Type())
} }
redactedEvent.Redact() redactedEvent.Redact()
validRoomID, err := spec.NewRoomID(redactionEvent.RoomID()) clientEvent, err := synctypes.ToClientEvent(redactionEvent, synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return querier.QueryUserIDForSender(ctx, roomID, senderID)
})
if err != nil { if err != nil {
return err return err
} }
senderID, err := querier.QueryUserIDForSender(ctx, *validRoomID, redactionEvent.SenderID()) redactedBecause := clientEvent
if err != nil {
return err
}
redactedBecause := synctypes.ToClientEvent(redactionEvent, synctypes.FormatSync, *senderID, redactionEvent.StateKey())
if err := redactedEvent.SetUnsignedField("redacted_because", redactedBecause); err != nil { if err := redactedEvent.SetUnsignedField("redacted_because", redactedBecause); err != nil {
return err return err
} }

View file

@ -111,15 +111,11 @@ func ruleMatches(rule *Rule, kind Kind, event gomatrixserverlib.PDU, ec Evaluati
return patternMatches("content.body", *rule.Pattern, event) return patternMatches("content.body", *rule.Pattern, event)
case RoomKind: case RoomKind:
return rule.RuleID == event.RoomID(), nil return rule.RuleID == event.RoomID().String(), nil
case SenderKind: case SenderKind:
userID := "" userID := ""
validRoomID, err := spec.NewRoomID(event.RoomID()) sender, err := userIDForSender(event.RoomID(), event.SenderID())
if err != nil {
return false, err
}
sender, err := userIDForSender(*validRoomID, event.SenderID())
if err == nil { if err == nil {
userID = sender.String() userID = sender.String()
} }

View file

@ -13,7 +13,7 @@ func UserIDForSender(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID,
} }
func TestRuleSetEvaluatorMatchEvent(t *testing.T) { func TestRuleSetEvaluatorMatchEvent(t *testing.T) {
ev := mustEventFromJSON(t, `{}`) ev := mustEventFromJSON(t, `{"room_id":"!room:a"}`)
defaultEnabled := &Rule{ defaultEnabled := &Rule{
RuleID: ".default.enabled", RuleID: ".default.enabled",
Default: true, Default: true,
@ -44,8 +44,8 @@ func TestRuleSetEvaluatorMatchEvent(t *testing.T) {
{"overrideRoom", RuleSet{Override: []*Rule{userEnabled}, Room: []*Rule{userEnabled2}}, userEnabled, ev}, {"overrideRoom", RuleSet{Override: []*Rule{userEnabled}, Room: []*Rule{userEnabled2}}, userEnabled, ev},
{"overrideSender", RuleSet{Override: []*Rule{userEnabled}, Sender: []*Rule{userEnabled2}}, userEnabled, ev}, {"overrideSender", RuleSet{Override: []*Rule{userEnabled}, Sender: []*Rule{userEnabled2}}, userEnabled, ev},
{"overrideUnderride", RuleSet{Override: []*Rule{userEnabled}, Underride: []*Rule{userEnabled2}}, userEnabled, ev}, {"overrideUnderride", RuleSet{Override: []*Rule{userEnabled}, Underride: []*Rule{userEnabled2}}, userEnabled, ev},
{"reactions don't notify", *defaultRuleset, &mRuleReactionDefinition, mustEventFromJSON(t, `{"type":"m.reaction"}`)}, {"reactions don't notify", *defaultRuleset, &mRuleReactionDefinition, mustEventFromJSON(t, `{"room_id":"!room:a","type":"m.reaction"}`)},
{"receipts don't notify", *defaultRuleset, nil, mustEventFromJSON(t, `{"type":"m.receipt"}`)}, {"receipts don't notify", *defaultRuleset, nil, mustEventFromJSON(t, `{"room_id":"!room:a","type":"m.receipt"}`)},
} }
for _, tst := range tsts { for _, tst := range tsts {
t.Run(tst.Name, func(t *testing.T) { t.Run(tst.Name, func(t *testing.T) {
@ -70,28 +70,27 @@ func TestRuleMatches(t *testing.T) {
EventJSON string EventJSON string
Want bool Want bool
}{ }{
{"emptyOverride", OverrideKind, emptyRule, `{}`, true}, {"emptyOverride", OverrideKind, emptyRule, `{"room_id":"!room:example.com"}`, true},
{"emptyContent", ContentKind, emptyRule, `{}`, false}, {"emptyContent", ContentKind, emptyRule, `{"room_id":"!room:example.com"}`, false},
{"emptyRoom", RoomKind, emptyRule, `{}`, true},
{"emptySender", SenderKind, emptyRule, `{"room_id":"!room:example.com"}`, true}, {"emptySender", SenderKind, emptyRule, `{"room_id":"!room:example.com"}`, true},
{"emptyUnderride", UnderrideKind, emptyRule, `{}`, true}, {"emptyUnderride", UnderrideKind, emptyRule, `{"room_id":"!room:example.com"}`, true},
{"disabled", OverrideKind, Rule{}, `{}`, false}, {"disabled", OverrideKind, Rule{}, `{"room_id":"!room:example.com"}`, false},
{"overrideConditionMatch", OverrideKind, Rule{Enabled: true}, `{}`, true}, {"overrideConditionMatch", OverrideKind, Rule{Enabled: true}, `{"room_id":"!room:example.com"}`, true},
{"overrideConditionNoMatch", OverrideKind, Rule{Enabled: true, Conditions: []*Condition{{}}}, `{}`, false}, {"overrideConditionNoMatch", OverrideKind, Rule{Enabled: true, Conditions: []*Condition{{}}}, `{"room_id":"!room:example.com"}`, false},
{"underrideConditionMatch", UnderrideKind, Rule{Enabled: true}, `{}`, true}, {"underrideConditionMatch", UnderrideKind, Rule{Enabled: true}, `{"room_id":"!room:example.com"}`, true},
{"underrideConditionNoMatch", UnderrideKind, Rule{Enabled: true, Conditions: []*Condition{{}}}, `{}`, false}, {"underrideConditionNoMatch", UnderrideKind, Rule{Enabled: true, Conditions: []*Condition{{}}}, `{"room_id":"!room:example.com"}`, false},
{"contentMatch", ContentKind, Rule{Enabled: true, Pattern: pointer("b")}, `{"content":{"body":"abc"}}`, true}, {"contentMatch", ContentKind, Rule{Enabled: true, Pattern: pointer("b")}, `{"room_id":"!room:example.com","content":{"body":"abc"}}`, true},
{"contentNoMatch", ContentKind, Rule{Enabled: true, Pattern: pointer("d")}, `{"content":{"body":"abc"}}`, false}, {"contentNoMatch", ContentKind, Rule{Enabled: true, Pattern: pointer("d")}, `{"room_id":"!room:example.com","content":{"body":"abc"}}`, false},
{"roomMatch", RoomKind, Rule{Enabled: true, RuleID: "!room:example.com"}, `{"room_id":"!room:example.com"}`, true}, {"roomMatch", RoomKind, Rule{Enabled: true, RuleID: "!room:example.com"}, `{"room_id":"!room:example.com"}`, true},
{"roomNoMatch", RoomKind, Rule{Enabled: true, RuleID: "!room:example.com"}, `{"room_id":"!otherroom:example.com"}`, false}, {"roomNoMatch", RoomKind, Rule{Enabled: true, RuleID: "!room:example.com"}, `{"room_id":"!otherroom:example.com"}`, false},
{"senderMatch", SenderKind, Rule{Enabled: true, RuleID: "@user:example.com"}, `{"sender":"@user:example.com","room_id":"!room:example.com"}`, true}, {"senderMatch", SenderKind, Rule{Enabled: true, RuleID: "@user:example.com"}, `{"room_id":"!room:example.com","sender":"@user:example.com","room_id":"!room:example.com"}`, true},
{"senderNoMatch", SenderKind, Rule{Enabled: true, RuleID: "@user:example.com"}, `{"sender":"@otheruser:example.com","room_id":"!room:example.com"}`, false}, {"senderNoMatch", SenderKind, Rule{Enabled: true, RuleID: "@user:example.com"}, `{"room_id":"!room:example.com","sender":"@otheruser:example.com","room_id":"!room:example.com"}`, false},
} }
for _, tst := range tsts { for _, tst := range tsts {
t.Run(tst.Name, func(t *testing.T) { t.Run(tst.Name, func(t *testing.T) {
@ -114,32 +113,32 @@ func TestConditionMatches(t *testing.T) {
WantMatch bool WantMatch bool
WantErr bool WantErr bool
}{ }{
{Name: "empty", Cond: Condition{}, EventJSON: `{}`, WantMatch: false, WantErr: false}, {Name: "empty", Cond: Condition{}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: false, WantErr: false},
{Name: "empty", Cond: Condition{Kind: "unknownstring"}, EventJSON: `{}`, WantMatch: false, WantErr: false}, {Name: "empty", Cond: Condition{Kind: "unknownstring"}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: false, WantErr: false},
// Neither of these should match because `content` is not a full string match, // Neither of these should match because `content` is not a full string match,
// and `content.body` is not a string value. // and `content.body` is not a string value.
{Name: "eventMatch", Cond: Condition{Kind: EventMatchCondition, Key: "content", Pattern: pointer("")}, EventJSON: `{"content":{}}`, WantMatch: false, WantErr: false}, {Name: "eventMatch", Cond: Condition{Kind: EventMatchCondition, Key: "content", Pattern: pointer("")}, EventJSON: `{"room_id":"!room:example.com","content":{}}`, WantMatch: false, WantErr: false},
{Name: "eventBodyMatch", Cond: Condition{Kind: EventMatchCondition, Key: "content.body", Is: "3", Pattern: pointer("")}, EventJSON: `{"content":{"body": "3"}}`, WantMatch: false, WantErr: false}, {Name: "eventBodyMatch", Cond: Condition{Kind: EventMatchCondition, Key: "content.body", Is: "3", Pattern: pointer("")}, EventJSON: `{"room_id":"!room:example.com","content":{"body": "3"}}`, WantMatch: false, WantErr: false},
{Name: "eventBodyMatch matches", Cond: Condition{Kind: EventMatchCondition, Key: "content.body", Pattern: pointer("world")}, EventJSON: `{"content":{"body": "hello world!"}}`, WantMatch: true, WantErr: false}, {Name: "eventBodyMatch matches", Cond: Condition{Kind: EventMatchCondition, Key: "content.body", Pattern: pointer("world")}, EventJSON: `{"room_id":"!room:example.com","content":{"body": "hello world!"}}`, WantMatch: true, WantErr: false},
{Name: "EventMatch missing pattern", Cond: Condition{Kind: EventMatchCondition, Key: "content.body"}, EventJSON: `{"content":{"body": "hello world!"}}`, WantMatch: false, WantErr: true}, {Name: "EventMatch missing pattern", Cond: Condition{Kind: EventMatchCondition, Key: "content.body"}, EventJSON: `{"room_id":"!room:example.com","content":{"body": "hello world!"}}`, WantMatch: false, WantErr: true},
{Name: "displayNameNoMatch", Cond: Condition{Kind: ContainsDisplayNameCondition}, EventJSON: `{"content":{"body":"something without displayname"}}`, WantMatch: false, WantErr: false}, {Name: "displayNameNoMatch", Cond: Condition{Kind: ContainsDisplayNameCondition}, EventJSON: `{"room_id":"!room:example.com","content":{"body":"something without displayname"}}`, WantMatch: false, WantErr: false},
{Name: "displayNameMatch", Cond: Condition{Kind: ContainsDisplayNameCondition}, EventJSON: `{"content":{"body":"hello Dear User, how are you?"}}`, WantMatch: true, WantErr: false}, {Name: "displayNameMatch", Cond: Condition{Kind: ContainsDisplayNameCondition}, EventJSON: `{"room_id":"!room:example.com","content":{"body":"hello Dear User, how are you?"}}`, WantMatch: true, WantErr: false},
{Name: "roomMemberCountLessNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<2"}, EventJSON: `{}`, WantMatch: false, WantErr: false}, {Name: "roomMemberCountLessNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<2"}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: false, WantErr: false},
{Name: "roomMemberCountLessMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<3"}, EventJSON: `{}`, WantMatch: true, WantErr: false}, {Name: "roomMemberCountLessMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<3"}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: true, WantErr: false},
{Name: "roomMemberCountLessEqualNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<=1"}, EventJSON: `{}`, WantMatch: false, WantErr: false}, {Name: "roomMemberCountLessEqualNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<=1"}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: false, WantErr: false},
{Name: "roomMemberCountLessEqualMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<=2"}, EventJSON: `{}`, WantMatch: true, WantErr: false}, {Name: "roomMemberCountLessEqualMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "<=2"}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: true, WantErr: false},
{Name: "roomMemberCountEqualNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "==1"}, EventJSON: `{}`, WantMatch: false, WantErr: false}, {Name: "roomMemberCountEqualNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "==1"}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: false, WantErr: false},
{Name: "roomMemberCountEqualMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "==2"}, EventJSON: `{}`, WantMatch: true, WantErr: false}, {Name: "roomMemberCountEqualMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: "==2"}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: true, WantErr: false},
{Name: "roomMemberCountGreaterEqualNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">=3"}, EventJSON: `{}`, WantMatch: false, WantErr: false}, {Name: "roomMemberCountGreaterEqualNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">=3"}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: false, WantErr: false},
{Name: "roomMemberCountGreaterEqualMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">=2"}, EventJSON: `{}`, WantMatch: true, WantErr: false}, {Name: "roomMemberCountGreaterEqualMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">=2"}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: true, WantErr: false},
{Name: "roomMemberCountGreaterNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">2"}, EventJSON: `{}`, WantMatch: false, WantErr: false}, {Name: "roomMemberCountGreaterNoMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">2"}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: false, WantErr: false},
{Name: "roomMemberCountGreaterMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">1"}, EventJSON: `{}`, WantMatch: true, WantErr: false}, {Name: "roomMemberCountGreaterMatch", Cond: Condition{Kind: RoomMemberCountCondition, Is: ">1"}, EventJSON: `{"room_id":"!room:example.com"}`, WantMatch: true, WantErr: false},
{Name: "senderNotificationPermissionMatch", Cond: Condition{Kind: SenderNotificationPermissionCondition, Key: "powerlevel"}, EventJSON: `{"sender":"@poweruser:example.com"}`, WantMatch: true, WantErr: false}, {Name: "senderNotificationPermissionMatch", Cond: Condition{Kind: SenderNotificationPermissionCondition, Key: "powerlevel"}, EventJSON: `{"room_id":"!room:example.com","sender":"@poweruser:example.com"}`, WantMatch: true, WantErr: false},
{Name: "senderNotificationPermissionNoMatch", Cond: Condition{Kind: SenderNotificationPermissionCondition, Key: "powerlevel"}, EventJSON: `{"sender":"@nobody:example.com"}`, WantMatch: false, WantErr: false}, {Name: "senderNotificationPermissionNoMatch", Cond: Condition{Kind: SenderNotificationPermissionCondition, Key: "powerlevel"}, EventJSON: `{"room_id":"!room:example.com","sender":"@nobody:example.com"}`, WantMatch: false, WantErr: false},
} }
for _, tst := range tsts { for _, tst := range tsts {
t.Run(tst.Name, func(t *testing.T) { t.Run(tst.Name, func(t *testing.T) {
@ -170,15 +169,15 @@ func TestPatternMatches(t *testing.T) {
EventJSON string EventJSON string
Want bool Want bool
}{ }{
{"empty", "", "", `{}`, false}, {"empty", "", "", `{"room_id":"!room:a"}`, false},
{"patternEmpty", "content", "", `{"content":{}}`, false}, {"patternEmpty", "content", "", `{"room_id":"!room:a","content":{}}`, false},
{"literal", "content.creator", "acreator", `{"content":{"creator":"acreator"}}`, true}, {"literal", "content.creator", "acreator", `{"room_id":"!room:a","content":{"creator":"acreator"}}`, true},
{"substring", "content.creator", "reat", `{"content":{"creator":"acreator"}}`, true}, {"substring", "content.creator", "reat", `{"room_id":"!room:a","content":{"creator":"acreator"}}`, true},
{"singlePattern", "content.creator", "acr?ator", `{"content":{"creator":"acreator"}}`, true}, {"singlePattern", "content.creator", "acr?ator", `{"room_id":"!room:a","content":{"creator":"acreator"}}`, true},
{"multiPattern", "content.creator", "a*ea*r", `{"content":{"creator":"acreator"}}`, true}, {"multiPattern", "content.creator", "a*ea*r", `{"room_id":"!room:a","content":{"creator":"acreator"}}`, true},
{"patternNoSubstring", "content.creator", "r*t", `{"content":{"creator":"acreator"}}`, false}, {"patternNoSubstring", "content.creator", "r*t", `{"room_id":"!room:a","content":{"creator":"acreator"}}`, false},
} }
for _, tst := range tsts { for _, tst := range tsts {
t.Run(tst.Name, func(t *testing.T) { t.Run(tst.Name, func(t *testing.T) {

View file

@ -161,7 +161,7 @@ func (t *TxnReq) ProcessTransaction(ctx context.Context) (*fclient.RespSend, *ut
if event.Type() == spec.MRoomCreate && event.StateKeyEquals("") { if event.Type() == spec.MRoomCreate && event.StateKeyEquals("") {
continue continue
} }
if api.IsServerBannedFromRoom(ctx, t.rsAPI, event.RoomID(), t.Origin) { if api.IsServerBannedFromRoom(ctx, t.rsAPI, event.RoomID().String(), t.Origin) {
results[event.EventID()] = fclient.PDUResult{ results[event.EventID()] = fclient.PDUResult{
Error: "Forbidden by server ACLs", Error: "Forbidden by server ACLs",
} }

View file

@ -18,7 +18,7 @@ var build string
const ( const (
VersionMajor = 0 VersionMajor = 0
VersionMinor = 13 VersionMinor = 13
VersionPatch = 2 VersionPatch = 3
VersionTag = "" // example: "rc1" VersionTag = "" // example: "rc1"
gitRevLen = 7 // 7 matches the displayed characters on github.com gitRevLen = 7 // 7 matches the displayed characters on github.com

View file

@ -119,7 +119,7 @@ func (s *ServerACLs) OnServerACLUpdate(state gomatrixserverlib.PDU) {
}).Debugf("Updating server ACLs for %q", state.RoomID()) }).Debugf("Updating server ACLs for %q", state.RoomID())
s.aclsMutex.Lock() s.aclsMutex.Lock()
defer s.aclsMutex.Unlock() defer s.aclsMutex.Unlock()
s.acls[state.RoomID()] = acls s.acls[state.RoomID().String()] = acls
} }
func (s *ServerACLs) IsServerBannedFromRoom(serverName spec.ServerName, roomID string) bool { func (s *ServerACLs) IsServerBannedFromRoom(serverName spec.ServerName, roomID string) bool {

View file

@ -75,7 +75,7 @@ func SendEventWithState(
} }
logrus.WithContext(ctx).WithFields(logrus.Fields{ logrus.WithContext(ctx).WithFields(logrus.Fields{
"room_id": event.RoomID(), "room_id": event.RoomID().String(),
"event_id": event.EventID(), "event_id": event.EventID(),
"outliers": len(ires), "outliers": len(ires),
"state_ids": len(stateEventIDs), "state_ids": len(stateEventIDs),

View file

@ -85,11 +85,7 @@ func IsAnyUserOnServerWithMembership(ctx context.Context, querier api.QuerySende
continue continue
} }
validRoomID, err := spec.NewRoomID(ev.RoomID()) userID, err := querier.QueryUserIDForSender(ctx, ev.RoomID(), spec.SenderID(*stateKey))
if err != nil {
continue
}
userID, err := querier.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*stateKey))
if err != nil { if err != nil {
continue continue
} }

View file

@ -189,7 +189,7 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias(ctx context.Context, senderID sp
proto := &gomatrixserverlib.ProtoEvent{ proto := &gomatrixserverlib.ProtoEvent{
SenderID: string(canonicalSenderID), SenderID: string(canonicalSenderID),
RoomID: ev.RoomID(), RoomID: ev.RoomID().String(),
Type: ev.Type(), Type: ev.Type(),
StateKey: ev.StateKey(), StateKey: ev.StateKey(),
Content: res, Content: res,

View file

@ -239,7 +239,7 @@ func (r *RoomserverInternalAPI) HandleInvite(
if err != nil { if err != nil {
return err return err
} }
return r.OutputProducer.ProduceRoomEvents(inviteEvent.RoomID(), outputEvents) return r.OutputProducer.ProduceRoomEvents(inviteEvent.RoomID().String(), outputEvents)
} }
func (r *RoomserverInternalAPI) PerformCreateRoom( func (r *RoomserverInternalAPI) PerformCreateRoom(

View file

@ -218,9 +218,9 @@ func loadAuthEvents(
roomID := "" roomID := ""
for _, ev := range result.events { for _, ev := range result.events {
if roomID == "" { if roomID == "" {
roomID = ev.RoomID() roomID = ev.RoomID().String()
} }
if ev.RoomID() != roomID { if ev.RoomID().String() != roomID {
result.valid = false result.valid = false
break break
} }

View file

@ -54,7 +54,7 @@ func UpdateToInviteMembership(
Type: api.OutputTypeRetireInviteEvent, Type: api.OutputTypeRetireInviteEvent,
RetireInviteEvent: &api.OutputRetireInviteEvent{ RetireInviteEvent: &api.OutputRetireInviteEvent{
EventID: eventID, EventID: eventID,
RoomID: add.RoomID(), RoomID: add.RoomID().String(),
Membership: spec.Join, Membership: spec.Join,
RetiredByEventID: add.EventID(), RetiredByEventID: add.EventID(),
TargetSenderID: spec.SenderID(*add.StateKey()), TargetSenderID: spec.SenderID(*add.StateKey()),
@ -396,7 +396,7 @@ BFSLoop:
// It's nasty that we have to extract the room ID from an event, but many federation requests // It's nasty that we have to extract the room ID from an event, but many federation requests
// only talk in event IDs, no room IDs at all (!!!) // only talk in event IDs, no room IDs at all (!!!)
ev := events[0] ev := events[0]
isServerInRoom, err = IsServerCurrentlyInRoom(ctx, db, querier, serverName, ev.RoomID()) isServerInRoom, err = IsServerCurrentlyInRoom(ctx, db, querier, serverName, ev.RoomID().String())
if err != nil { if err != nil {
util.GetLogger(ctx).WithError(err).Error("Failed to check if server is currently in room, assuming not.") util.GetLogger(ctx).WithError(err).Error("Failed to check if server is currently in room, assuming not.")
} }
@ -419,7 +419,7 @@ BFSLoop:
// hasn't been seen before. // hasn't been seen before.
if !visited[pre] { if !visited[pre] {
visited[pre] = true visited[pre] = true
allowed, err = CheckServerAllowedToSeeEvent(ctx, db, info, ev.RoomID(), pre, serverName, isServerInRoom, querier) allowed, err = CheckServerAllowedToSeeEvent(ctx, db, info, ev.RoomID().String(), pre, serverName, isServerInRoom, querier)
if err != nil { if err != nil {
util.GetLogger(ctx).WithField("server", serverName).WithField("event_id", pre).WithError(err).Error( util.GetLogger(ctx).WithField("server", serverName).WithField("event_id", pre).WithError(err).Error(
"Error checking if allowed to see event", "Error checking if allowed to see event",

View file

@ -358,7 +358,7 @@ func (r *Inputer) queueInputRoomEvents(
// For each event, marshal the input room event and then // For each event, marshal the input room event and then
// send it into the input queue. // send it into the input queue.
for _, e := range request.InputRoomEvents { for _, e := range request.InputRoomEvents {
roomID := e.Event.RoomID() roomID := e.Event.RoomID().String()
subj := r.Cfg.Matrix.JetStream.Prefixed(jetstream.InputRoomEventSubj(roomID)) subj := r.Cfg.Matrix.JetStream.Prefixed(jetstream.InputRoomEventSubj(roomID))
msg := &nats.Msg{ msg := &nats.Msg{
Subject: subj, Subject: subj,

View file

@ -87,7 +87,7 @@ func (r *Inputer) processRoomEvent(
} }
trace, ctx := internal.StartRegion(ctx, "processRoomEvent") trace, ctx := internal.StartRegion(ctx, "processRoomEvent")
trace.SetTag("room_id", input.Event.RoomID()) trace.SetTag("room_id", input.Event.RoomID().String())
trace.SetTag("event_id", input.Event.EventID()) trace.SetTag("event_id", input.Event.EventID())
defer trace.EndRegion() defer trace.EndRegion()
@ -96,7 +96,7 @@ func (r *Inputer) processRoomEvent(
defer func() { defer func() {
timetaken := time.Since(started) timetaken := time.Since(started)
processRoomEventDuration.With(prometheus.Labels{ processRoomEventDuration.With(prometheus.Labels{
"room_id": input.Event.RoomID(), "room_id": input.Event.RoomID().String(),
}).Observe(float64(timetaken.Milliseconds())) }).Observe(float64(timetaken.Milliseconds()))
}() }()
@ -105,7 +105,7 @@ func (r *Inputer) processRoomEvent(
event := headered.PDU event := headered.PDU
logger := util.GetLogger(ctx).WithFields(logrus.Fields{ logger := util.GetLogger(ctx).WithFields(logrus.Fields{
"event_id": event.EventID(), "event_id": event.EventID(),
"room_id": event.RoomID(), "room_id": event.RoomID().String(),
"kind": input.Kind, "kind": input.Kind,
"origin": input.Origin, "origin": input.Origin,
"type": event.Type(), "type": event.Type(),
@ -120,19 +120,15 @@ func (r *Inputer) processRoomEvent(
// Don't waste time processing the event if the room doesn't exist. // Don't waste time processing the event if the room doesn't exist.
// A room entry locally will only be created in response to a create // A room entry locally will only be created in response to a create
// event. // event.
roomInfo, rerr := r.DB.RoomInfo(ctx, event.RoomID()) roomInfo, rerr := r.DB.RoomInfo(ctx, event.RoomID().String())
if rerr != nil { if rerr != nil {
return fmt.Errorf("r.DB.RoomInfo: %w", rerr) return fmt.Errorf("r.DB.RoomInfo: %w", rerr)
} }
isCreateEvent := event.Type() == spec.MRoomCreate && event.StateKeyEquals("") isCreateEvent := event.Type() == spec.MRoomCreate && event.StateKeyEquals("")
if roomInfo == nil && !isCreateEvent { if roomInfo == nil && !isCreateEvent {
return fmt.Errorf("room %s does not exist for event %s", event.RoomID(), event.EventID()) return fmt.Errorf("room %s does not exist for event %s", event.RoomID().String(), event.EventID())
} }
validRoomID, err := spec.NewRoomID(event.RoomID()) sender, err := r.Queryer.QueryUserIDForSender(ctx, event.RoomID(), event.SenderID())
if err != nil {
return err
}
sender, err := r.Queryer.QueryUserIDForSender(ctx, *validRoomID, event.SenderID())
if err != nil { if err != nil {
return fmt.Errorf("failed getting userID for sender %q. %w", event.SenderID(), err) return fmt.Errorf("failed getting userID for sender %q. %w", event.SenderID(), err)
} }
@ -179,7 +175,7 @@ func (r *Inputer) processRoomEvent(
// If we have missing events (auth or prev), we build a list of servers to ask // If we have missing events (auth or prev), we build a list of servers to ask
if missingAuth || missingPrev { if missingAuth || missingPrev {
serverReq := &fedapi.QueryJoinedHostServerNamesInRoomRequest{ serverReq := &fedapi.QueryJoinedHostServerNamesInRoomRequest{
RoomID: event.RoomID(), RoomID: event.RoomID().String(),
ExcludeSelf: true, ExcludeSelf: true,
ExcludeBlacklisted: true, ExcludeBlacklisted: true,
} }
@ -395,12 +391,12 @@ func (r *Inputer) processRoomEvent(
// Request the room info again — it's possible that the room has been // Request the room info again — it's possible that the room has been
// created by now if it didn't exist already. // created by now if it didn't exist already.
roomInfo, err = r.DB.RoomInfo(ctx, event.RoomID()) roomInfo, err = r.DB.RoomInfo(ctx, event.RoomID().String())
if err != nil { if err != nil {
return fmt.Errorf("updater.RoomInfo: %w", err) return fmt.Errorf("updater.RoomInfo: %w", err)
} }
if roomInfo == nil { if roomInfo == nil {
return fmt.Errorf("updater.RoomInfo missing for room %s", event.RoomID()) return fmt.Errorf("updater.RoomInfo missing for room %s", event.RoomID().String())
} }
if input.HasState || (!missingPrev && stateAtEvent.BeforeStateSnapshotNID == 0) { if input.HasState || (!missingPrev && stateAtEvent.BeforeStateSnapshotNID == 0) {
@ -459,7 +455,7 @@ func (r *Inputer) processRoomEvent(
if userErr != nil { if userErr != nil {
return userErr return userErr
} }
err = r.RSAPI.StoreUserRoomPublicKey(ctx, mapping.MXIDMapping.UserRoomKey, *storeUserID, *validRoomID) err = r.RSAPI.StoreUserRoomPublicKey(ctx, mapping.MXIDMapping.UserRoomKey, *storeUserID, event.RoomID())
if err != nil { if err != nil {
return fmt.Errorf("failed storing user room public key: %w", err) return fmt.Errorf("failed storing user room public key: %w", err)
} }
@ -481,7 +477,7 @@ func (r *Inputer) processRoomEvent(
return fmt.Errorf("r.updateLatestEvents: %w", err) return fmt.Errorf("r.updateLatestEvents: %w", err)
} }
case api.KindOld: case api.KindOld:
err = r.OutputProducer.ProduceRoomEvents(event.RoomID(), []api.OutputEvent{ err = r.OutputProducer.ProduceRoomEvents(event.RoomID().String(), []api.OutputEvent{
{ {
Type: api.OutputTypeOldRoomEvent, Type: api.OutputTypeOldRoomEvent,
OldRoomEvent: &api.OutputOldRoomEvent{ OldRoomEvent: &api.OutputOldRoomEvent{
@ -507,7 +503,7 @@ func (r *Inputer) processRoomEvent(
// so notify downstream components to redact this event - they should have it if they've // so notify downstream components to redact this event - they should have it if they've
// been tracking our output log. // been tracking our output log.
if redactedEventID != "" { if redactedEventID != "" {
err = r.OutputProducer.ProduceRoomEvents(event.RoomID(), []api.OutputEvent{ err = r.OutputProducer.ProduceRoomEvents(event.RoomID().String(), []api.OutputEvent{
{ {
Type: api.OutputTypeRedactedEvent, Type: api.OutputTypeRedactedEvent,
RedactedEvent: &api.OutputRedactedEvent{ RedactedEvent: &api.OutputRedactedEvent{
@ -536,7 +532,7 @@ func (r *Inputer) processRoomEvent(
// handleRemoteRoomUpgrade updates published rooms and room aliases // handleRemoteRoomUpgrade updates published rooms and room aliases
func (r *Inputer) handleRemoteRoomUpgrade(ctx context.Context, event gomatrixserverlib.PDU) error { func (r *Inputer) handleRemoteRoomUpgrade(ctx context.Context, event gomatrixserverlib.PDU) error {
oldRoomID := event.RoomID() oldRoomID := event.RoomID().String()
newRoomID := gjson.GetBytes(event.Content(), "replacement_room").Str newRoomID := gjson.GetBytes(event.Content(), "replacement_room").Str
return r.DB.UpgradeRoom(ctx, oldRoomID, newRoomID, string(event.SenderID())) return r.DB.UpgradeRoom(ctx, oldRoomID, newRoomID, string(event.SenderID()))
} }
@ -596,7 +592,7 @@ func (r *Inputer) processStateBefore(
StateKey: "", StateKey: "",
}) })
stateBeforeReq := &api.QueryStateAfterEventsRequest{ stateBeforeReq := &api.QueryStateAfterEventsRequest{
RoomID: event.RoomID(), RoomID: event.RoomID().String(),
PrevEventIDs: event.PrevEventIDs(), PrevEventIDs: event.PrevEventIDs(),
StateToFetch: tuplesNeeded, StateToFetch: tuplesNeeded,
} }
@ -606,7 +602,7 @@ func (r *Inputer) processStateBefore(
} }
switch { switch {
case !stateBeforeRes.RoomExists: case !stateBeforeRes.RoomExists:
rejectionErr = fmt.Errorf("room %q does not exist", event.RoomID()) rejectionErr = fmt.Errorf("room %q does not exist", event.RoomID().String())
return return
case !stateBeforeRes.PrevEventsExist: case !stateBeforeRes.PrevEventsExist:
rejectionErr = fmt.Errorf("prev events of %q are not known", event.EventID()) rejectionErr = fmt.Errorf("prev events of %q are not known", event.EventID())
@ -707,7 +703,7 @@ func (r *Inputer) fetchAuthEvents(
// Request the entire auth chain for the event in question. This should // Request the entire auth chain for the event in question. This should
// contain all of the auth events — including ones that we already know — // contain all of the auth events — including ones that we already know —
// so we'll need to filter through those in the next section. // so we'll need to filter through those in the next section.
res, err = r.FSAPI.GetEventAuth(ctx, virtualHost, serverName, event.Version(), event.RoomID(), event.EventID()) res, err = r.FSAPI.GetEventAuth(ctx, virtualHost, serverName, event.Version(), event.RoomID().String(), event.EventID())
if err != nil { if err != nil {
logger.WithError(err).Warnf("Failed to get event auth from federation for %q: %s", event.EventID(), err) logger.WithError(err).Warnf("Failed to get event auth from federation for %q: %s", event.EventID(), err)
continue continue
@ -866,25 +862,20 @@ func (r *Inputer) kickGuests(ctx context.Context, event gomatrixserverlib.PDU, r
inputEvents := make([]api.InputRoomEvent, 0, len(memberEvents)) inputEvents := make([]api.InputRoomEvent, 0, len(memberEvents))
latestReq := &api.QueryLatestEventsAndStateRequest{ latestReq := &api.QueryLatestEventsAndStateRequest{
RoomID: event.RoomID(), RoomID: event.RoomID().String(),
} }
latestRes := &api.QueryLatestEventsAndStateResponse{} latestRes := &api.QueryLatestEventsAndStateResponse{}
if err = r.Queryer.QueryLatestEventsAndState(ctx, latestReq, latestRes); err != nil { if err = r.Queryer.QueryLatestEventsAndState(ctx, latestReq, latestRes); err != nil {
return err return err
} }
validRoomID, err := spec.NewRoomID(event.RoomID())
if err != nil {
return err
}
prevEvents := latestRes.LatestEvents prevEvents := latestRes.LatestEvents
for _, memberEvent := range memberEvents { for _, memberEvent := range memberEvents {
if memberEvent.StateKey() == nil { if memberEvent.StateKey() == nil {
continue continue
} }
memberUserID, err := r.Queryer.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*memberEvent.StateKey())) memberUserID, err := r.Queryer.QueryUserIDForSender(ctx, event.RoomID(), spec.SenderID(*memberEvent.StateKey()))
if err != nil { if err != nil {
continue continue
} }
@ -912,7 +903,7 @@ func (r *Inputer) kickGuests(ctx context.Context, event gomatrixserverlib.PDU, r
stateKey := *memberEvent.StateKey() stateKey := *memberEvent.StateKey()
fledglingEvent := &gomatrixserverlib.ProtoEvent{ fledglingEvent := &gomatrixserverlib.ProtoEvent{
RoomID: event.RoomID(), RoomID: event.RoomID().String(),
Type: spec.MRoomMember, Type: spec.MRoomMember,
StateKey: &stateKey, StateKey: &stateKey,
SenderID: stateKey, SenderID: stateKey,
@ -928,12 +919,7 @@ func (r *Inputer) kickGuests(ctx context.Context, event gomatrixserverlib.PDU, r
return err return err
} }
validRoomID, err := spec.NewRoomID(event.RoomID()) signingIdentity, err := r.SigningIdentity(ctx, event.RoomID(), *memberUserID)
if err != nil {
return err
}
signingIdentity, err := r.SigningIdentity(ctx, *validRoomID, *memberUserID)
if err != nil { if err != nil {
return err return err
} }

View file

@ -197,7 +197,7 @@ func (u *latestEventsUpdater) doUpdateLatestEvents() error {
// send the event asynchronously but we would need to ensure that 1) the events are written to the log in // send the event asynchronously but we would need to ensure that 1) the events are written to the log in
// the correct order, 2) that pending writes are resent across restarts. In order to avoid writing all the // the correct order, 2) that pending writes are resent across restarts. In order to avoid writing all the
// necessary bookkeeping we'll keep the event sending synchronous for now. // necessary bookkeeping we'll keep the event sending synchronous for now.
if err = u.api.OutputProducer.ProduceRoomEvents(u.event.RoomID(), updates); err != nil { if err = u.api.OutputProducer.ProduceRoomEvents(u.event.RoomID().String(), updates); err != nil {
return fmt.Errorf("u.api.WriteOutputEvents: %w", err) return fmt.Errorf("u.api.WriteOutputEvents: %w", err)
} }
@ -290,7 +290,7 @@ func (u *latestEventsUpdater) latestState() error {
if removed := len(u.removed) - len(u.added); !u.rewritesState && removed > 0 { if removed := len(u.removed) - len(u.added); !u.rewritesState && removed > 0 {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"event_id": u.event.EventID(), "event_id": u.event.EventID(),
"room_id": u.event.RoomID(), "room_id": u.event.RoomID().String(),
"old_state_nid": u.oldStateNID, "old_state_nid": u.oldStateNID,
"new_state_nid": u.newStateNID, "new_state_nid": u.newStateNID,
"old_latest": u.oldLatest.EventIDs(), "old_latest": u.oldLatest.EventIDs(),

View file

@ -139,11 +139,7 @@ func (r *Inputer) updateMembership(
func (r *Inputer) isLocalTarget(ctx context.Context, event *types.Event) bool { func (r *Inputer) isLocalTarget(ctx context.Context, event *types.Event) bool {
isTargetLocalUser := false isTargetLocalUser := false
if statekey := event.StateKey(); statekey != nil { if statekey := event.StateKey(); statekey != nil {
validRoomID, err := spec.NewRoomID(event.RoomID()) userID, err := r.Queryer.QueryUserIDForSender(ctx, event.RoomID(), spec.SenderID(*statekey))
if err != nil {
return isTargetLocalUser
}
userID, err := r.Queryer.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*statekey))
if err != nil || userID == nil { if err != nil || userID == nil {
return isTargetLocalUser return isTargetLocalUser
} }
@ -168,7 +164,7 @@ func updateToJoinMembership(
Type: api.OutputTypeRetireInviteEvent, Type: api.OutputTypeRetireInviteEvent,
RetireInviteEvent: &api.OutputRetireInviteEvent{ RetireInviteEvent: &api.OutputRetireInviteEvent{
EventID: eventID, EventID: eventID,
RoomID: add.RoomID(), RoomID: add.RoomID().String(),
Membership: spec.Join, Membership: spec.Join,
RetiredByEventID: add.EventID(), RetiredByEventID: add.EventID(),
TargetSenderID: spec.SenderID(*add.StateKey()), TargetSenderID: spec.SenderID(*add.StateKey()),
@ -195,7 +191,7 @@ func updateToLeaveMembership(
Type: api.OutputTypeRetireInviteEvent, Type: api.OutputTypeRetireInviteEvent,
RetireInviteEvent: &api.OutputRetireInviteEvent{ RetireInviteEvent: &api.OutputRetireInviteEvent{
EventID: eventID, EventID: eventID,
RoomID: add.RoomID(), RoomID: add.RoomID().String(),
Membership: newMembership, Membership: newMembership,
RetiredByEventID: add.EventID(), RetiredByEventID: add.EventID(),
TargetSenderID: spec.SenderID(*add.StateKey()), TargetSenderID: spec.SenderID(*add.StateKey()),

View file

@ -84,7 +84,7 @@ func (t *missingStateReq) processEventWithMissingState(
// need to fallback to /state. // need to fallback to /state.
t.log = util.GetLogger(ctx).WithFields(map[string]interface{}{ t.log = util.GetLogger(ctx).WithFields(map[string]interface{}{
"txn_event": e.EventID(), "txn_event": e.EventID(),
"room_id": e.RoomID(), "room_id": e.RoomID().String(),
"txn_prev_events": e.PrevEventIDs(), "txn_prev_events": e.PrevEventIDs(),
}) })
@ -264,7 +264,7 @@ func (t *missingStateReq) lookupResolvedStateBeforeEvent(ctx context.Context, e
// Look up what the state is after the backward extremity. This will either // Look up what the state is after the backward extremity. This will either
// come from the roomserver, if we know all the required events, or it will // come from the roomserver, if we know all the required events, or it will
// come from a remote server via /state_ids if not. // come from a remote server via /state_ids if not.
prevState, trustworthy, err := t.lookupStateAfterEvent(ctx, roomVersion, e.RoomID(), prevEventID) prevState, trustworthy, err := t.lookupStateAfterEvent(ctx, roomVersion, e.RoomID().String(), prevEventID)
switch err2 := err.(type) { switch err2 := err.(type) {
case gomatrixserverlib.EventValidationError: case gomatrixserverlib.EventValidationError:
if !err2.Persistable { if !err2.Persistable {
@ -316,9 +316,9 @@ func (t *missingStateReq) lookupResolvedStateBeforeEvent(ctx context.Context, e
} }
// There's more than one previous state - run them all through state res // There's more than one previous state - run them all through state res
var err error var err error
t.roomsMu.Lock(e.RoomID()) t.roomsMu.Lock(e.RoomID().String())
resolvedState, err = t.resolveStatesAndCheck(ctx, roomVersion, respStates, e) resolvedState, err = t.resolveStatesAndCheck(ctx, roomVersion, respStates, e)
t.roomsMu.Unlock(e.RoomID()) t.roomsMu.Unlock(e.RoomID().String())
switch err2 := err.(type) { switch err2 := err.(type) {
case gomatrixserverlib.EventValidationError: case gomatrixserverlib.EventValidationError:
if !err2.Persistable { if !err2.Persistable {
@ -510,7 +510,7 @@ retryAllowedState:
}); err != nil { }); err != nil {
switch missing := err.(type) { switch missing := err.(type) {
case gomatrixserverlib.MissingAuthEventError: case gomatrixserverlib.MissingAuthEventError:
h, err2 := t.lookupEvent(ctx, roomVersion, backwardsExtremity.RoomID(), missing.AuthEventID, true) h, err2 := t.lookupEvent(ctx, roomVersion, backwardsExtremity.RoomID().String(), missing.AuthEventID, true)
switch e := err2.(type) { switch e := err2.(type) {
case gomatrixserverlib.EventValidationError: case gomatrixserverlib.EventValidationError:
if !e.Persistable { if !e.Persistable {
@ -546,7 +546,7 @@ func (t *missingStateReq) getMissingEvents(ctx context.Context, e gomatrixserver
trace, ctx := internal.StartRegion(ctx, "getMissingEvents") trace, ctx := internal.StartRegion(ctx, "getMissingEvents")
defer trace.EndRegion() defer trace.EndRegion()
logger := t.log.WithField("event_id", e.EventID()).WithField("room_id", e.RoomID()) logger := t.log.WithField("event_id", e.EventID()).WithField("room_id", e.RoomID().String())
latest, _, _, err := t.db.LatestEventIDs(ctx, t.roomInfo.RoomNID) latest, _, _, err := t.db.LatestEventIDs(ctx, t.roomInfo.RoomNID)
if err != nil { if err != nil {
return nil, false, false, fmt.Errorf("t.DB.LatestEventIDs: %w", err) return nil, false, false, fmt.Errorf("t.DB.LatestEventIDs: %w", err)
@ -560,7 +560,7 @@ func (t *missingStateReq) getMissingEvents(ctx context.Context, e gomatrixserver
var missingResp *fclient.RespMissingEvents var missingResp *fclient.RespMissingEvents
for _, server := range t.servers { for _, server := range t.servers {
var m fclient.RespMissingEvents var m fclient.RespMissingEvents
if m, err = t.federation.LookupMissingEvents(ctx, t.virtualHost, server, e.RoomID(), fclient.MissingEvents{ if m, err = t.federation.LookupMissingEvents(ctx, t.virtualHost, server, e.RoomID().String(), fclient.MissingEvents{
Limit: 20, Limit: 20,
// The latest event IDs that the sender already has. These are skipped when retrieving the previous events of latest_events. // The latest event IDs that the sender already has. These are skipped when retrieving the previous events of latest_events.
EarliestEvents: latestEvents, EarliestEvents: latestEvents,

View file

@ -301,7 +301,7 @@ func (b *backfillRequester) StateIDsBeforeEvent(ctx context.Context, targetEvent
return ids, nil return ids, nil
} }
if len(targetEvent.PrevEventIDs()) == 0 && targetEvent.Type() == "m.room.create" && targetEvent.StateKeyEquals("") { if len(targetEvent.PrevEventIDs()) == 0 && targetEvent.Type() == "m.room.create" && targetEvent.StateKeyEquals("") {
util.GetLogger(ctx).WithField("room_id", targetEvent.RoomID()).Info("Backfilled to the beginning of the room") util.GetLogger(ctx).WithField("room_id", targetEvent.RoomID().String()).Info("Backfilled to the beginning of the room")
b.eventIDToBeforeStateIDs[targetEvent.EventID()] = []string{} b.eventIDToBeforeStateIDs[targetEvent.EventID()] = []string{}
return nil, nil return nil, nil
} }
@ -494,11 +494,7 @@ FindSuccessor:
// Store the server names in a temporary map to avoid duplicates. // Store the server names in a temporary map to avoid duplicates.
serverSet := make(map[spec.ServerName]bool) serverSet := make(map[spec.ServerName]bool)
for _, event := range memberEvents { for _, event := range memberEvents {
validRoomID, err := spec.NewRoomID(event.RoomID()) if sender, err := b.querier.QueryUserIDForSender(ctx, event.RoomID(), event.SenderID()); err == nil {
if err != nil {
continue
}
if sender, err := b.querier.QueryUserIDForSender(ctx, *validRoomID, event.SenderID()); err == nil {
serverSet[sender.Domain()] = true serverSet[sender.Domain()] = true
} }
} }

View file

@ -90,7 +90,16 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
} else { } else {
senderID = spec.SenderID(userID.String()) senderID = spec.SenderID(userID.String())
} }
createContent["creator"] = senderID
// TODO: Maybe, at some point, GMSL should return the events to create, so we can define the version
// entirely there.
switch createRequest.RoomVersion {
case gomatrixserverlib.RoomVersionV11:
// RoomVersionV11 removed the creator field from the create content: https://github.com/matrix-org/matrix-spec-proposals/pull/2175
default:
createContent["creator"] = senderID
}
createContent["room_version"] = createRequest.RoomVersion createContent["room_version"] = createRequest.RoomVersion
powerLevelContent := eventutil.InitialPowerLevelsContent(string(senderID)) powerLevelContent := eventutil.InitialPowerLevelsContent(string(senderID))
joinRuleContent := gomatrixserverlib.JoinRuleContent{ joinRuleContent := gomatrixserverlib.JoinRuleContent{

View file

@ -100,16 +100,12 @@ func (r *Inviter) ProcessInviteMembership(
var outputUpdates []api.OutputEvent var outputUpdates []api.OutputEvent
var updater *shared.MembershipUpdater var updater *shared.MembershipUpdater
validRoomID, err := spec.NewRoomID(inviteEvent.RoomID()) userID, err := r.RSAPI.QueryUserIDForSender(ctx, inviteEvent.RoomID(), spec.SenderID(*inviteEvent.StateKey()))
if err != nil {
return nil, err
}
userID, err := r.RSAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*inviteEvent.StateKey()))
if err != nil { if err != nil {
return nil, api.ErrInvalidID{Err: fmt.Errorf("the user ID %s is invalid", *inviteEvent.StateKey())} return nil, api.ErrInvalidID{Err: fmt.Errorf("the user ID %s is invalid", *inviteEvent.StateKey())}
} }
isTargetLocal := r.Cfg.Matrix.IsLocalServerName(userID.Domain()) isTargetLocal := r.Cfg.Matrix.IsLocalServerName(userID.Domain())
if updater, err = r.DB.MembershipUpdater(ctx, inviteEvent.RoomID(), *inviteEvent.StateKey(), isTargetLocal, inviteEvent.Version()); err != nil { if updater, err = r.DB.MembershipUpdater(ctx, inviteEvent.RoomID().String(), *inviteEvent.StateKey(), isTargetLocal, inviteEvent.Version()); err != nil {
return nil, fmt.Errorf("r.DB.MembershipUpdater: %w", err) return nil, fmt.Errorf("r.DB.MembershipUpdater: %w", err)
} }
outputUpdates, err = helpers.UpdateToInviteMembership(updater, &types.Event{ outputUpdates, err = helpers.UpdateToInviteMembership(updater, &types.Event{

View file

@ -93,11 +93,21 @@ func (r *Leaver) performLeaveRoomByID(
isInvitePending, senderUser, eventID, _, err := helpers.IsInvitePending(ctx, r.DB, req.RoomID, *leaver) isInvitePending, senderUser, eventID, _, err := helpers.IsInvitePending(ctx, r.DB, req.RoomID, *leaver)
if err == nil && isInvitePending { if err == nil && isInvitePending {
sender, serr := r.RSAPI.QueryUserIDForSender(ctx, *roomID, senderUser) sender, serr := r.RSAPI.QueryUserIDForSender(ctx, *roomID, senderUser)
if serr != nil || sender == nil { if serr != nil {
return nil, fmt.Errorf("sender %q has no matching userID", senderUser) return nil, fmt.Errorf("failed looking up userID for sender %q: %w", senderUser, serr)
} }
if !r.Cfg.Matrix.IsLocalServerName(sender.Domain()) {
return r.performFederatedRejectInvite(ctx, req, res, *sender, eventID, *leaver) var domain spec.ServerName
if sender == nil {
// TODO: Currently a federated invite has no way of knowing the mxid_mapping of the inviter.
// Should we add the inviter's m.room.member event (with mxid_mapping) to invite_room_state to allow
// the invited user to leave via the inviter's server?
domain = roomID.Domain()
} else {
domain = sender.Domain()
}
if !r.Cfg.Matrix.IsLocalServerName(domain) {
return r.performFederatedRejectInvite(ctx, req, res, domain, eventID, *leaver)
} }
// check that this is not a "server notice room" // check that this is not a "server notice room"
accData := &userapi.QueryAccountDataResponse{} accData := &userapi.QueryAccountDataResponse{}
@ -219,14 +229,14 @@ func (r *Leaver) performFederatedRejectInvite(
ctx context.Context, ctx context.Context,
req *api.PerformLeaveRequest, req *api.PerformLeaveRequest,
res *api.PerformLeaveResponse, // nolint:unparam res *api.PerformLeaveResponse, // nolint:unparam
inviteSender spec.UserID, eventID string, inviteDomain spec.ServerName, eventID string,
leaver spec.SenderID, leaver spec.SenderID,
) ([]api.OutputEvent, error) { ) ([]api.OutputEvent, error) {
// Ask the federation sender to perform a federated leave for us. // Ask the federation sender to perform a federated leave for us.
leaveReq := fsAPI.PerformLeaveRequest{ leaveReq := fsAPI.PerformLeaveRequest{
RoomID: req.RoomID, RoomID: req.RoomID,
UserID: req.Leaver.String(), UserID: req.Leaver.String(),
ServerNames: []spec.ServerName{inviteSender.Domain()}, ServerNames: []spec.ServerName{inviteDomain},
} }
leaveRes := fsAPI.PerformLeaveResponse{} leaveRes := fsAPI.PerformLeaveResponse{}
if err := r.FSAPI.PerformLeave(ctx, &leaveReq, &leaveRes); err != nil { if err := r.FSAPI.PerformLeave(ctx, &leaveReq, &leaveRes); err != nil {

View file

@ -368,7 +368,16 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
// in the create event (such as for the room types MSC). // in the create event (such as for the room types MSC).
newCreateContent := map[string]interface{}{} newCreateContent := map[string]interface{}{}
_ = json.Unmarshal(oldCreateEvent.Content(), &newCreateContent) _ = json.Unmarshal(oldCreateEvent.Content(), &newCreateContent)
newCreateContent["creator"] = string(senderID)
switch newVersion {
case gomatrixserverlib.RoomVersionV11:
// RoomVersionV11 removed the creator field from the create content: https://github.com/matrix-org/matrix-spec-proposals/pull/2175
// So if we are upgrading from pre v11, we need to remove the field.
delete(newCreateContent, "creator")
default:
newCreateContent["creator"] = senderID
}
newCreateContent["room_version"] = newVersion newCreateContent["room_version"] = newVersion
newCreateContent["predecessor"] = gomatrixserverlib.PreviousRoom{ newCreateContent["predecessor"] = gomatrixserverlib.PreviousRoom{
EventID: tombstoneEvent.EventID(), EventID: tombstoneEvent.EventID(),

View file

@ -513,14 +513,14 @@ func restrictedJoinRuleAllowedRooms(ctx context.Context, joinRuleEv *types.Heade
} }
var jrContent gomatrixserverlib.JoinRuleContent var jrContent gomatrixserverlib.JoinRuleContent
if err := json.Unmarshal(joinRuleEv.Content(), &jrContent); err != nil { if err := json.Unmarshal(joinRuleEv.Content(), &jrContent); err != nil {
util.GetLogger(ctx).Warnf("failed to check join_rule on room %s: %s", joinRuleEv.RoomID(), err) util.GetLogger(ctx).Warnf("failed to check join_rule on room %s: %s", joinRuleEv.RoomID().String(), err)
return nil return nil
} }
for _, allow := range jrContent.Allow { for _, allow := range jrContent.Allow {
if allow.Type == spec.MRoomMembership { if allow.Type == spec.MRoomMembership {
allowedRoomID, err := spec.NewRoomID(allow.RoomID) allowedRoomID, err := spec.NewRoomID(allow.RoomID)
if err != nil { if err != nil {
util.GetLogger(ctx).Warnf("invalid room ID '%s' found in join_rule on room %s: %s", allow.RoomID, joinRuleEv.RoomID(), err) util.GetLogger(ctx).Warnf("invalid room ID '%s' found in join_rule on room %s: %s", allow.RoomID, joinRuleEv.RoomID().String(), err)
} else { } else {
allows = append(allows, *allowedRoomID) allows = append(allows, *allowedRoomID)
} }

View file

@ -49,6 +49,7 @@ func (db *getEventDB) addFakeEvent(eventID string, authIDs []string) error {
} }
builder := map[string]interface{}{ builder := map[string]interface{}{
"event_id": eventID, "event_id": eventID,
"room_id": "!room:a",
"auth_events": authEvents, "auth_events": authEvents,
} }

View file

@ -696,8 +696,8 @@ func (d *Database) GetOrCreateRoomInfo(ctx context.Context, event gomatrixserver
return nil, fmt.Errorf("extractRoomVersionFromCreateEvent: %w", err) return nil, fmt.Errorf("extractRoomVersionFromCreateEvent: %w", err)
} }
roomNID, nidOK := d.Cache.GetRoomServerRoomNID(event.RoomID()) roomNID, nidOK := d.Cache.GetRoomServerRoomNID(event.RoomID().String())
cachedRoomVersion, versionOK := d.Cache.GetRoomVersion(event.RoomID()) cachedRoomVersion, versionOK := d.Cache.GetRoomVersion(event.RoomID().String())
// if we found both, the roomNID and version in our cache, no need to query the database // if we found both, the roomNID and version in our cache, no need to query the database
if nidOK && versionOK { if nidOK && versionOK {
return &types.RoomInfo{ return &types.RoomInfo{
@ -707,14 +707,14 @@ func (d *Database) GetOrCreateRoomInfo(ctx context.Context, event gomatrixserver
} }
err = d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error { err = d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error {
roomNID, err = d.assignRoomNID(ctx, txn, event.RoomID(), roomVersion) roomNID, err = d.assignRoomNID(ctx, txn, event.RoomID().String(), roomVersion)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
}) })
if roomVersion != "" { if roomVersion != "" {
d.Cache.StoreRoomVersion(event.RoomID(), roomVersion) d.Cache.StoreRoomVersion(event.RoomID().String(), roomVersion)
} }
return &types.RoomInfo{ return &types.RoomInfo{
RoomVersion: roomVersion, RoomVersion: roomVersion,
@ -1026,24 +1026,19 @@ func (d *EventDatabase) MaybeRedactEvent(
case validated || redactedEvent == nil || redactionEvent == nil: case validated || redactedEvent == nil || redactionEvent == nil:
// we've seen this redaction before or there is nothing to redact // we've seen this redaction before or there is nothing to redact
return nil return nil
case redactedEvent.RoomID() != redactionEvent.RoomID(): case redactedEvent.RoomID().String() != redactionEvent.RoomID().String():
// redactions across rooms aren't allowed // redactions across rooms aren't allowed
ignoreRedaction = true ignoreRedaction = true
return nil return nil
} }
var validRoomID *spec.RoomID
validRoomID, err = spec.NewRoomID(redactedEvent.RoomID())
if err != nil {
return err
}
sender1Domain := "" sender1Domain := ""
sender1, err1 := querier.QueryUserIDForSender(ctx, *validRoomID, redactedEvent.SenderID()) sender1, err1 := querier.QueryUserIDForSender(ctx, redactedEvent.RoomID(), redactedEvent.SenderID())
if err1 == nil { if err1 == nil {
sender1Domain = string(sender1.Domain()) sender1Domain = string(sender1.Domain())
} }
sender2Domain := "" sender2Domain := ""
sender2, err2 := querier.QueryUserIDForSender(ctx, *validRoomID, redactionEvent.SenderID()) sender2, err2 := querier.QueryUserIDForSender(ctx, redactedEvent.RoomID(), redactionEvent.SenderID())
if err2 == nil { if err2 == nil {
sender2Domain = string(sender2.Domain()) sender2Domain = string(sender2.Domain())
} }
@ -1522,7 +1517,7 @@ func (d *Database) GetBulkStateContent(ctx context.Context, roomIDs []string, tu
} }
result[i] = tables.StrippedEvent{ result[i] = tables.StrippedEvent{
EventType: ev.Type(), EventType: ev.Type(),
RoomID: ev.RoomID(), RoomID: ev.RoomID().String(),
StateKey: *ev.StateKey(), StateKey: *ev.StateKey(),
ContentValue: tables.ExtractContentValue(&types.HeaderedEvent{PDU: ev}), ContentValue: tables.ExtractContentValue(&types.HeaderedEvent{PDU: ev}),
} }

View file

@ -271,7 +271,7 @@ func (rc *reqCtx) process() (*MSC2836EventRelationshipsResponse, *util.JSONRespo
event = rc.fetchUnknownEvent(rc.req.EventID, rc.req.RoomID) event = rc.fetchUnknownEvent(rc.req.EventID, rc.req.RoomID)
} }
if rc.req.RoomID == "" && event != nil { if rc.req.RoomID == "" && event != nil {
rc.req.RoomID = event.RoomID() rc.req.RoomID = event.RoomID().String()
} }
if event == nil || !rc.authorisedToSeeEvent(event) { if event == nil || !rc.authorisedToSeeEvent(event) {
return nil, &util.JSONResponse{ return nil, &util.JSONResponse{
@ -526,7 +526,7 @@ func (rc *reqCtx) authorisedToSeeEvent(event *types.HeaderedEvent) bool {
// make sure the server is in this room // make sure the server is in this room
var res fs.QueryJoinedHostServerNamesInRoomResponse var res fs.QueryJoinedHostServerNamesInRoomResponse
err := rc.fsAPI.QueryJoinedHostServerNamesInRoom(rc.ctx, &fs.QueryJoinedHostServerNamesInRoomRequest{ err := rc.fsAPI.QueryJoinedHostServerNamesInRoom(rc.ctx, &fs.QueryJoinedHostServerNamesInRoomRequest{
RoomID: event.RoomID(), RoomID: event.RoomID().String(),
}, &res) }, &res)
if err != nil { if err != nil {
util.GetLogger(rc.ctx).WithError(err).Error("authorisedToSeeEvent: failed to QueryJoinedHostServerNamesInRoom") util.GetLogger(rc.ctx).WithError(err).Error("authorisedToSeeEvent: failed to QueryJoinedHostServerNamesInRoom")
@ -545,7 +545,7 @@ func (rc *reqCtx) authorisedToSeeEvent(event *types.HeaderedEvent) bool {
// TODO: This does not honour m.room.create content // TODO: This does not honour m.room.create content
var queryMembershipRes roomserver.QueryMembershipForUserResponse var queryMembershipRes roomserver.QueryMembershipForUserResponse
err := rc.rsAPI.QueryMembershipForUser(rc.ctx, &roomserver.QueryMembershipForUserRequest{ err := rc.rsAPI.QueryMembershipForUser(rc.ctx, &roomserver.QueryMembershipForUserRequest{
RoomID: event.RoomID(), RoomID: event.RoomID().String(),
UserID: rc.userID, UserID: rc.userID,
}, &queryMembershipRes) }, &queryMembershipRes)
if err != nil { if err != nil {
@ -612,7 +612,7 @@ func (rc *reqCtx) lookForEvent(eventID string) *types.HeaderedEvent {
// inject all the events into the roomserver then return the event in question // inject all the events into the roomserver then return the event in question
rc.injectResponseToRoomserver(queryRes) rc.injectResponseToRoomserver(queryRes)
for _, ev := range queryRes.ParsedEvents { for _, ev := range queryRes.ParsedEvents {
if ev.EventID() == eventID && rc.req.RoomID == ev.RoomID() { if ev.EventID() == eventID && rc.req.RoomID == ev.RoomID().String() {
return &types.HeaderedEvent{PDU: ev} return &types.HeaderedEvent{PDU: ev}
} }
} }
@ -629,7 +629,7 @@ func (rc *reqCtx) lookForEvent(eventID string) *types.HeaderedEvent {
} }
} }
} }
if rc.req.RoomID == event.RoomID() { if rc.req.RoomID == event.RoomID().String() {
return event return event
} }
return nil return nil

View file

@ -239,7 +239,7 @@ func (p *DB) StoreRelation(ctx context.Context, ev *types.HeaderedEvent) error {
return err return err
} }
util.GetLogger(ctx).Infof("StoreRelation child=%s parent=%s rel_type=%s", child, parent, relType) util.GetLogger(ctx).Infof("StoreRelation child=%s parent=%s rel_type=%s", child, parent, relType)
_, err = txn.Stmt(p.insertNodeStmt).ExecContext(ctx, ev.EventID(), ev.OriginServerTS(), ev.RoomID(), count, base64.RawStdEncoding.EncodeToString(hash), 0) _, err = txn.Stmt(p.insertNodeStmt).ExecContext(ctx, ev.EventID(), ev.OriginServerTS(), ev.RoomID().String(), count, base64.RawStdEncoding.EncodeToString(hash), 0)
return err return err
}) })
} }

View file

@ -113,7 +113,7 @@ func (s *OutputClientDataConsumer) Start() error {
id = streamPos id = streamPos
e := fulltext.IndexElement{ e := fulltext.IndexElement{
EventID: ev.EventID(), EventID: ev.EventID(),
RoomID: ev.RoomID(), RoomID: ev.RoomID().String(),
StreamPosition: streamPos, StreamPosition: streamPos,
} }
e.SetContentType(ev.Type()) e.SetContentType(ev.Type())

View file

@ -33,6 +33,7 @@ import (
"github.com/matrix-org/dendrite/syncapi/notifier" "github.com/matrix-org/dendrite/syncapi/notifier"
"github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/storage"
"github.com/matrix-org/dendrite/syncapi/streams" "github.com/matrix-org/dendrite/syncapi/streams"
"github.com/matrix-org/dendrite/syncapi/synctypes"
"github.com/matrix-org/dendrite/syncapi/types" "github.com/matrix-org/dendrite/syncapi/types"
"github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/gomatrixserverlib/spec"
"github.com/nats-io/nats.go" "github.com/nats-io/nats.go"
@ -165,9 +166,9 @@ func (s *OutputRoomEventConsumer) onRedactEvent(
return err return err
} }
if err = s.db.RedactRelations(ctx, msg.RedactedBecause.RoomID(), msg.RedactedEventID); err != nil { if err = s.db.RedactRelations(ctx, msg.RedactedBecause.RoomID().String(), msg.RedactedEventID); err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"room_id": msg.RedactedBecause.RoomID(), "room_id": msg.RedactedBecause.RoomID().String(),
"event_id": msg.RedactedBecause.EventID(), "event_id": msg.RedactedBecause.EventID(),
"redacted_event_id": msg.RedactedEventID, "redacted_event_id": msg.RedactedEventID,
}).WithError(err).Warn("Failed to redact relations") }).WithError(err).Warn("Failed to redact relations")
@ -221,7 +222,7 @@ func (s *OutputRoomEventConsumer) onNewRoomEvent(
// Finally, work out if there are any more events missing. // Finally, work out if there are any more events missing.
if len(missingEventIDs) > 0 { if len(missingEventIDs) > 0 {
eventsReq := &api.QueryEventsByIDRequest{ eventsReq := &api.QueryEventsByIDRequest{
RoomID: ev.RoomID(), RoomID: ev.RoomID().String(),
EventIDs: missingEventIDs, EventIDs: missingEventIDs,
} }
eventsRes := &api.QueryEventsByIDResponse{} eventsRes := &api.QueryEventsByIDResponse{}
@ -256,17 +257,12 @@ func (s *OutputRoomEventConsumer) onNewRoomEvent(
} }
if msg.RewritesState { if msg.RewritesState {
if err = s.db.PurgeRoomState(ctx, ev.RoomID()); err != nil { if err = s.db.PurgeRoomState(ctx, ev.RoomID().String()); err != nil {
return fmt.Errorf("s.db.PurgeRoom: %w", err) return fmt.Errorf("s.db.PurgeRoom: %w", err)
} }
} }
validRoomID, err := spec.NewRoomID(ev.RoomID()) userID, err := s.rsAPI.QueryUserIDForSender(ctx, ev.RoomID(), ev.SenderID())
if err != nil {
return err
}
userID, err := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, ev.SenderID())
if err != nil { if err != nil {
return err return err
} }
@ -306,7 +302,7 @@ func (s *OutputRoomEventConsumer) onNewRoomEvent(
} }
s.pduStream.Advance(pduPos) s.pduStream.Advance(pduPos)
s.notifier.OnNewEvent(ev, ev.RoomID(), nil, types.StreamingToken{PDUPosition: pduPos}) s.notifier.OnNewEvent(ev, ev.RoomID().String(), nil, types.StreamingToken{PDUPosition: pduPos})
return nil return nil
} }
@ -323,12 +319,7 @@ func (s *OutputRoomEventConsumer) onOldRoomEvent(
// old events in the sync API, this should at least prevent us // old events in the sync API, this should at least prevent us
// from confusing clients into thinking they've joined/left rooms. // from confusing clients into thinking they've joined/left rooms.
validRoomID, err := spec.NewRoomID(ev.RoomID()) userID, err := s.rsAPI.QueryUserIDForSender(ctx, ev.RoomID(), ev.SenderID())
if err != nil {
return err
}
userID, err := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, ev.SenderID())
if err != nil { if err != nil {
return err return err
} }
@ -354,7 +345,7 @@ func (s *OutputRoomEventConsumer) onOldRoomEvent(
if err = s.db.UpdateRelations(ctx, ev); err != nil { if err = s.db.UpdateRelations(ctx, ev); err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"room_id": ev.RoomID(), "room_id": ev.RoomID().String(),
"event_id": ev.EventID(), "event_id": ev.EventID(),
"type": ev.Type(), "type": ev.Type(),
}).WithError(err).Warn("Failed to update relations") }).WithError(err).Warn("Failed to update relations")
@ -367,7 +358,7 @@ func (s *OutputRoomEventConsumer) onOldRoomEvent(
} }
s.pduStream.Advance(pduPos) s.pduStream.Advance(pduPos)
s.notifier.OnNewEvent(ev, ev.RoomID(), nil, types.StreamingToken{PDUPosition: pduPos}) s.notifier.OnNewEvent(ev, ev.RoomID().String(), nil, types.StreamingToken{PDUPosition: pduPos})
return nil return nil
} }
@ -387,11 +378,7 @@ func (s *OutputRoomEventConsumer) notifyJoinedPeeks(ctx context.Context, ev *rst
return sp, fmt.Errorf("unexpected nil state_key") return sp, fmt.Errorf("unexpected nil state_key")
} }
validRoomID, err := spec.NewRoomID(ev.RoomID()) userID, err := s.rsAPI.QueryUserIDForSender(ctx, ev.RoomID(), spec.SenderID(*ev.StateKey()))
if err != nil {
return sp, err
}
userID, err := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*ev.StateKey()))
if err != nil || userID == nil { if err != nil || userID == nil {
return sp, fmt.Errorf("failed getting userID for sender: %w", err) return sp, fmt.Errorf("failed getting userID for sender: %w", err)
} }
@ -400,7 +387,7 @@ func (s *OutputRoomEventConsumer) notifyJoinedPeeks(ctx context.Context, ev *rst
} }
// cancel any peeks for it // cancel any peeks for it
peekSP, peekErr := s.db.DeletePeeks(ctx, ev.RoomID(), *ev.StateKey()) peekSP, peekErr := s.db.DeletePeeks(ctx, ev.RoomID().String(), *ev.StateKey())
if peekErr != nil { if peekErr != nil {
return sp, fmt.Errorf("s.db.DeletePeeks: %w", peekErr) return sp, fmt.Errorf("s.db.DeletePeeks: %w", peekErr)
} }
@ -418,11 +405,7 @@ func (s *OutputRoomEventConsumer) onNewInviteEvent(
return return
} }
validRoomID, err := spec.NewRoomID(msg.Event.RoomID()) userID, err := s.rsAPI.QueryUserIDForSender(ctx, msg.Event.RoomID(), spec.SenderID(*msg.Event.StateKey()))
if err != nil {
return
}
userID, err := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*msg.Event.StateKey()))
if err != nil || userID == nil { if err != nil || userID == nil {
return return
} }
@ -559,15 +542,10 @@ func (s *OutputRoomEventConsumer) updateStateEvent(event *rstypes.HeaderedEvent)
var succeeded bool var succeeded bool
defer sqlutil.EndTransactionWithCheck(snapshot, &succeeded, &err) defer sqlutil.EndTransactionWithCheck(snapshot, &succeeded, &err)
validRoomID, err := spec.NewRoomID(event.RoomID())
if err != nil {
return event, err
}
sKeyUser := "" sKeyUser := ""
if stateKey != "" { if stateKey != "" {
var sku *spec.UserID var sku *spec.UserID
sku, err = s.rsAPI.QueryUserIDForSender(s.ctx, *validRoomID, spec.SenderID(stateKey)) sku, err = s.rsAPI.QueryUserIDForSender(s.ctx, event.RoomID(), spec.SenderID(stateKey))
if err == nil && sku != nil { if err == nil && sku != nil {
sKeyUser = sku.String() sKeyUser = sku.String()
event.StateKeyResolved = &sKeyUser event.StateKeyResolved = &sKeyUser
@ -575,13 +553,13 @@ func (s *OutputRoomEventConsumer) updateStateEvent(event *rstypes.HeaderedEvent)
} }
prevEvent, err := snapshot.GetStateEvent( prevEvent, err := snapshot.GetStateEvent(
s.ctx, event.RoomID(), event.Type(), sKeyUser, s.ctx, event.RoomID().String(), event.Type(), sKeyUser,
) )
if err != nil { if err != nil {
return event, err return event, err
} }
userID, err := s.rsAPI.QueryUserIDForSender(s.ctx, *validRoomID, event.SenderID()) userID, err := s.rsAPI.QueryUserIDForSender(s.ctx, event.RoomID(), event.SenderID())
if err != nil { if err != nil {
return event, err return event, err
} }
@ -592,16 +570,10 @@ func (s *OutputRoomEventConsumer) updateStateEvent(event *rstypes.HeaderedEvent)
return event, nil return event, nil
} }
prevEventSender := string(prevEvent.SenderID()) prev := synctypes.PrevEventRef{
prevUser, err := s.rsAPI.QueryUserIDForSender(s.ctx, *validRoomID, prevEvent.SenderID())
if err == nil && prevUser != nil {
prevEventSender = prevUser.String()
}
prev := types.PrevEventRef{
PrevContent: prevEvent.Content(), PrevContent: prevEvent.Content(),
ReplacesState: prevEvent.EventID(), ReplacesState: prevEvent.EventID(),
PrevSenderID: prevEventSender, PrevSenderID: string(prevEvent.SenderID()),
} }
event.PDU, err = event.SetUnsigned(prev) event.PDU, err = event.SetUnsigned(prev)
@ -615,7 +587,7 @@ func (s *OutputRoomEventConsumer) writeFTS(ev *rstypes.HeaderedEvent, pduPositio
} }
e := fulltext.IndexElement{ e := fulltext.IndexElement{
EventID: ev.EventID(), EventID: ev.EventID(),
RoomID: ev.RoomID(), RoomID: ev.RoomID().String(),
StreamPosition: int64(pduPosition), StreamPosition: int64(pduPosition),
} }
e.SetContentType(ev.Type()) e.SetContentType(ev.Type())

View file

@ -118,26 +118,23 @@ func ApplyHistoryVisibilityFilter(
start := time.Now() start := time.Now()
// try to get the current membership of the user // try to get the current membership of the user
membershipCurrent, _, err := syncDB.SelectMembershipForUser(ctx, events[0].RoomID(), userID.String(), math.MaxInt64) membershipCurrent, _, err := syncDB.SelectMembershipForUser(ctx, events[0].RoomID().String(), userID.String(), math.MaxInt64)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Get the mapping from eventID -> eventVisibility // Get the mapping from eventID -> eventVisibility
eventsFiltered := make([]*types.HeaderedEvent, 0, len(events)) eventsFiltered := make([]*types.HeaderedEvent, 0, len(events))
firstEvRoomID, err := spec.NewRoomID(events[0].RoomID()) firstEvRoomID := events[0].RoomID()
senderID, err := rsAPI.QuerySenderIDForUser(ctx, firstEvRoomID, userID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
senderID, err := rsAPI.QuerySenderIDForUser(ctx, *firstEvRoomID, userID) visibilities := visibilityForEvents(ctx, rsAPI, events, senderID, firstEvRoomID)
if err != nil {
return nil, err
}
visibilities := visibilityForEvents(ctx, rsAPI, events, senderID, *firstEvRoomID)
for _, ev := range events { for _, ev := range events {
// Validate same room assumption // Validate same room assumption
if ev.RoomID() != firstEvRoomID.String() { if ev.RoomID().String() != firstEvRoomID.String() {
return nil, fmt.Errorf("events from different rooms supplied to ApplyHistoryVisibilityFilter") return nil, fmt.Errorf("events from different rooms supplied to ApplyHistoryVisibilityFilter")
} }

View file

@ -101,20 +101,13 @@ func (n *Notifier) OnNewEvent(
n._removeEmptyUserStreams() n._removeEmptyUserStreams()
if ev != nil { if ev != nil {
validRoomID, err := spec.NewRoomID(ev.RoomID())
if err != nil {
log.WithError(err).WithField("event_id", ev.EventID()).Errorf(
"Notifier.OnNewEvent: RoomID is invalid",
)
return
}
// Map this event's room_id to a list of joined users, and wake them up. // Map this event's room_id to a list of joined users, and wake them up.
usersToNotify := n._joinedUsers(ev.RoomID()) usersToNotify := n._joinedUsers(ev.RoomID().String())
// Map this event's room_id to a list of peeking devices, and wake them up. // Map this event's room_id to a list of peeking devices, and wake them up.
peekingDevicesToNotify := n._peekingDevices(ev.RoomID()) peekingDevicesToNotify := n._peekingDevices(ev.RoomID().String())
// If this is an invite, also add in the invitee to this list. // If this is an invite, also add in the invitee to this list.
if ev.Type() == "m.room.member" && ev.StateKey() != nil { if ev.Type() == "m.room.member" && ev.StateKey() != nil {
targetUserID, err := n.rsAPI.QueryUserIDForSender(context.Background(), *validRoomID, spec.SenderID(*ev.StateKey())) targetUserID, err := n.rsAPI.QueryUserIDForSender(context.Background(), ev.RoomID(), spec.SenderID(*ev.StateKey()))
if err != nil || targetUserID == nil { if err != nil || targetUserID == nil {
log.WithError(err).WithField("event_id", ev.EventID()).Errorf( log.WithError(err).WithField("event_id", ev.EventID()).Errorf(
"Notifier.OnNewEvent: Failed to find the userID for this event", "Notifier.OnNewEvent: Failed to find the userID for this event",
@ -134,11 +127,11 @@ func (n *Notifier) OnNewEvent(
// Manually append the new user's ID so they get notified // Manually append the new user's ID so they get notified
// along all members in the room // along all members in the room
usersToNotify = append(usersToNotify, targetUserID.String()) usersToNotify = append(usersToNotify, targetUserID.String())
n._addJoinedUser(ev.RoomID(), targetUserID.String()) n._addJoinedUser(ev.RoomID().String(), targetUserID.String())
case spec.Leave: case spec.Leave:
fallthrough fallthrough
case spec.Ban: case spec.Ban:
n._removeJoinedUser(ev.RoomID(), targetUserID.String()) n._removeJoinedUser(ev.RoomID().String(), targetUserID.String())
} }
} }
} }

View file

@ -118,32 +118,19 @@ func GetEvent(
} }
} }
senderUserID, err := rsAPI.QueryUserIDForSender(req.Context(), *roomID, events[0].SenderID()) clientEvent, err := synctypes.ToClientEvent(events[0], synctypes.FormatAll, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
if err != nil || senderUserID == nil { return rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
util.GetLogger(req.Context()).WithError(err).WithField("senderID", events[0].SenderID()).WithField("roomID", *roomID).Error("QueryUserIDForSender errored or returned nil-user ID when user should be part of a room") })
if err != nil {
util.GetLogger(req.Context()).WithError(err).WithField("senderID", events[0].SenderID()).WithField("roomID", *roomID).Error("Failed converting to ClientEvent")
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
JSON: spec.Unknown("internal server error"), JSON: spec.Unknown("internal server error"),
} }
} }
sk := events[0].StateKey()
if sk != nil && *sk != "" {
evRoomID, err := spec.NewRoomID(events[0].RoomID())
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.BadJSON("roomID is invalid"),
}
}
skUserID, err := rsAPI.QueryUserIDForSender(ctx, *evRoomID, spec.SenderID(*events[0].StateKey()))
if err == nil && skUserID != nil {
skString := skUserID.String()
sk = &skString
}
}
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusOK, Code: http.StatusOK,
JSON: synctypes.ToClientEvent(events[0], synctypes.FormatAll, *senderUserID, sk), JSON: *clientEvent,
} }
} }

View file

@ -152,15 +152,7 @@ func GetMemberships(
} }
} }
validRoomID, err := spec.NewRoomID(ev.RoomID()) userID, err := rsAPI.QueryUserIDForSender(req.Context(), ev.RoomID(), ev.SenderID())
if err != nil {
util.GetLogger(req.Context()).WithError(err).Error("roomID is invalid")
return util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}
}
userID, err := rsAPI.QueryUserIDForSender(req.Context(), *validRoomID, ev.SenderID())
if err != nil || userID == nil { if err != nil || userID == nil {
util.GetLogger(req.Context()).WithError(err).Error("rsAPI.QueryUserIDForSender failed") util.GetLogger(req.Context()).WithError(err).Error("rsAPI.QueryUserIDForSender failed")
return util.JSONResponse{ return util.JSONResponse{

View file

@ -130,23 +130,16 @@ func Relations(
// type if it was specified. // type if it was specified.
res.Chunk = make([]synctypes.ClientEvent, 0, len(filteredEvents)) res.Chunk = make([]synctypes.ClientEvent, 0, len(filteredEvents))
for _, event := range filteredEvents { for _, event := range filteredEvents {
sender := spec.UserID{} clientEvent, err := synctypes.ToClientEvent(event.PDU, synctypes.FormatAll, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
userID, err := rsAPI.QueryUserIDForSender(req.Context(), *roomID, event.SenderID()) return rsAPI.QueryUserIDForSender(req.Context(), roomID, senderID)
if err == nil && userID != nil { })
sender = *userID if err != nil {
} util.GetLogger(req.Context()).WithError(err).WithField("senderID", events[0].SenderID()).WithField("roomID", *roomID).Error("Failed converting to ClientEvent")
continue
sk := event.StateKey()
if sk != nil && *sk != "" {
skUserID, err := rsAPI.QueryUserIDForSender(req.Context(), *roomID, spec.SenderID(*event.StateKey()))
if err == nil && skUserID != nil {
skString := skUserID.String()
sk = &skString
}
} }
res.Chunk = append( res.Chunk = append(
res.Chunk, res.Chunk,
synctypes.ToClientEvent(event.PDU, synctypes.FormatAll, sender, sk), *clientEvent,
) )
} }

View file

@ -205,12 +205,7 @@ func Search(req *http.Request, device *api.Device, syncDB storage.Database, fts
profileInfos := make(map[string]ProfileInfoResponse) profileInfos := make(map[string]ProfileInfoResponse)
for _, ev := range append(eventsBefore, eventsAfter...) { for _, ev := range append(eventsBefore, eventsAfter...) {
validRoomID, roomErr := spec.NewRoomID(ev.RoomID()) userID, queryErr := rsAPI.QueryUserIDForSender(req.Context(), ev.RoomID(), ev.SenderID())
if err != nil {
logrus.WithError(roomErr).WithField("room_id", ev.RoomID()).Warn("failed to query userprofile")
continue
}
userID, queryErr := rsAPI.QueryUserIDForSender(req.Context(), *validRoomID, ev.SenderID())
if queryErr != nil { if queryErr != nil {
logrus.WithError(queryErr).WithField("sender_id", ev.SenderID()).Warn("failed to query userprofile") logrus.WithError(queryErr).WithField("sender_id", ev.SenderID()).Warn("failed to query userprofile")
continue continue
@ -218,7 +213,7 @@ func Search(req *http.Request, device *api.Device, syncDB storage.Database, fts
profile, ok := knownUsersProfiles[userID.String()] profile, ok := knownUsersProfiles[userID.String()]
if !ok { if !ok {
stateEvent, stateErr := snapshot.GetStateEvent(ctx, ev.RoomID(), spec.MRoomMember, string(ev.SenderID())) stateEvent, stateErr := snapshot.GetStateEvent(ctx, ev.RoomID().String(), spec.MRoomMember, string(ev.SenderID()))
if stateErr != nil { if stateErr != nil {
logrus.WithError(stateErr).WithField("sender_id", event.SenderID()).Warn("failed to query userprofile") logrus.WithError(stateErr).WithField("sender_id", event.SenderID()).Warn("failed to query userprofile")
continue continue
@ -235,25 +230,14 @@ func Search(req *http.Request, device *api.Device, syncDB storage.Database, fts
profileInfos[userID.String()] = profile profileInfos[userID.String()] = profile
} }
sender := spec.UserID{} clientEvent, err := synctypes.ToClientEvent(event, synctypes.FormatAll, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
validRoomID, roomErr := spec.NewRoomID(event.RoomID()) return rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
})
if err != nil { if err != nil {
logrus.WithError(roomErr).WithField("room_id", event.RoomID()).Warn("failed to query userprofile") util.GetLogger(req.Context()).WithError(err).WithField("senderID", event.SenderID()).Error("Failed converting to ClientEvent")
continue continue
} }
userID, err := rsAPI.QueryUserIDForSender(req.Context(), *validRoomID, event.SenderID())
if err == nil && userID != nil {
sender = *userID
}
sk := event.StateKey()
if sk != nil && *sk != "" {
skUserID, err := rsAPI.QueryUserIDForSender(req.Context(), *validRoomID, spec.SenderID(*event.StateKey()))
if err == nil && skUserID != nil {
skString := skUserID.String()
sk = &skString
}
}
results = append(results, Result{ results = append(results, Result{
Context: SearchContextResponse{ Context: SearchContextResponse{
Start: startToken.String(), Start: startToken.String(),
@ -267,14 +251,14 @@ func Search(req *http.Request, device *api.Device, syncDB storage.Database, fts
ProfileInfo: profileInfos, ProfileInfo: profileInfos,
}, },
Rank: eventScore[event.EventID()].Score, Rank: eventScore[event.EventID()].Score,
Result: synctypes.ToClientEvent(event, synctypes.FormatAll, sender, sk), Result: *clientEvent,
}) })
roomGroup := groups[event.RoomID()] roomGroup := groups[event.RoomID().String()]
roomGroup.Results = append(roomGroup.Results, event.EventID()) roomGroup.Results = append(roomGroup.Results, event.EventID())
groups[event.RoomID()] = roomGroup groups[event.RoomID().String()] = roomGroup
if _, ok := stateForRooms[event.RoomID()]; searchReq.SearchCategories.RoomEvents.IncludeState && !ok { if _, ok := stateForRooms[event.RoomID().String()]; searchReq.SearchCategories.RoomEvents.IncludeState && !ok {
stateFilter := synctypes.DefaultStateFilter() stateFilter := synctypes.DefaultStateFilter()
state, err := snapshot.CurrentState(ctx, event.RoomID(), &stateFilter, nil) state, err := snapshot.CurrentState(ctx, event.RoomID().String(), &stateFilter, nil)
if err != nil { if err != nil {
logrus.WithError(err).Error("unable to get current state") logrus.WithError(err).Error("unable to get current state")
return util.JSONResponse{ return util.JSONResponse{
@ -282,7 +266,7 @@ func Search(req *http.Request, device *api.Device, syncDB storage.Database, fts
JSON: spec.InternalServerError{}, JSON: spec.InternalServerError{},
} }
} }
stateForRooms[event.RoomID()] = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(state), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) { stateForRooms[event.RoomID().String()] = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(state), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return rsAPI.QueryUserIDForSender(req.Context(), roomID, senderID) return rsAPI.QueryUserIDForSender(req.Context(), roomID, senderID)
}) })
} }
@ -328,19 +312,19 @@ func contextEvents(
roomFilter *synctypes.RoomEventFilter, roomFilter *synctypes.RoomEventFilter,
searchReq SearchRequest, searchReq SearchRequest,
) ([]*types.HeaderedEvent, []*types.HeaderedEvent, error) { ) ([]*types.HeaderedEvent, []*types.HeaderedEvent, error) {
id, _, err := snapshot.SelectContextEvent(ctx, event.RoomID(), event.EventID()) id, _, err := snapshot.SelectContextEvent(ctx, event.RoomID().String(), event.EventID())
if err != nil { if err != nil {
logrus.WithError(err).Error("failed to query context event") logrus.WithError(err).Error("failed to query context event")
return nil, nil, err return nil, nil, err
} }
roomFilter.Limit = searchReq.SearchCategories.RoomEvents.EventContext.BeforeLimit roomFilter.Limit = searchReq.SearchCategories.RoomEvents.EventContext.BeforeLimit
eventsBefore, err := snapshot.SelectContextBeforeEvent(ctx, id, event.RoomID(), roomFilter) eventsBefore, err := snapshot.SelectContextBeforeEvent(ctx, id, event.RoomID().String(), roomFilter)
if err != nil { if err != nil {
logrus.WithError(err).Error("failed to query before context event") logrus.WithError(err).Error("failed to query before context event")
return nil, nil, err return nil, nil, err
} }
roomFilter.Limit = searchReq.SearchCategories.RoomEvents.EventContext.AfterLimit roomFilter.Limit = searchReq.SearchCategories.RoomEvents.EventContext.AfterLimit
_, eventsAfter, err := snapshot.SelectContextAfterEvent(ctx, id, event.RoomID(), roomFilter) _, eventsAfter, err := snapshot.SelectContextAfterEvent(ctx, id, event.RoomID().String(), roomFilter)
if err != nil { if err != nil {
logrus.WithError(err).Error("failed to query after context event") logrus.WithError(err).Error("failed to query after context event")
return nil, nil, err return nil, nil, err

View file

@ -238,7 +238,7 @@ func TestSearch(t *testing.T) {
} }
elements = append(elements, fulltext.IndexElement{ elements = append(elements, fulltext.IndexElement{
EventID: x.EventID(), EventID: x.EventID(),
RoomID: x.RoomID(), RoomID: x.RoomID().String(),
Content: string(x.Content()), Content: string(x.Content()),
ContentType: x.Type(), ContentType: x.Type(),
StreamPosition: int64(sp), StreamPosition: int64(sp),

View file

@ -340,7 +340,7 @@ func (s *currentRoomStateStatements) UpsertRoomState(
stmt := sqlutil.TxStmt(txn, s.upsertRoomStateStmt) stmt := sqlutil.TxStmt(txn, s.upsertRoomStateStmt)
_, err = stmt.ExecContext( _, err = stmt.ExecContext(
ctx, ctx,
event.RoomID(), event.RoomID().String(),
event.EventID(), event.EventID(),
event.Type(), event.Type(),
event.UserID.String(), event.UserID.String(),

View file

@ -99,7 +99,7 @@ func (s *inviteEventsStatements) InsertInviteEvent(
err = sqlutil.TxStmt(txn, s.insertInviteEventStmt).QueryRowContext( err = sqlutil.TxStmt(txn, s.insertInviteEventStmt).QueryRowContext(
ctx, ctx,
inviteEvent.RoomID(), inviteEvent.RoomID().String(),
inviteEvent.EventID(), inviteEvent.EventID(),
inviteEvent.UserID.String(), inviteEvent.UserID.String(),
headeredJSON, headeredJSON,

View file

@ -108,7 +108,7 @@ func (s *membershipsStatements) UpsertMembership(
} }
_, err = sqlutil.TxStmt(txn, s.upsertMembershipStmt).ExecContext( _, err = sqlutil.TxStmt(txn, s.upsertMembershipStmt).ExecContext(
ctx, ctx,
event.RoomID(), event.RoomID().String(),
event.StateKeyResolved, event.StateKeyResolved,
membership, membership,
event.EventID(), event.EventID(),

View file

@ -334,7 +334,7 @@ func (s *outputRoomEventsStatements) SelectStateInRange(
if err := json.Unmarshal(eventBytes, &ev); err != nil { if err := json.Unmarshal(eventBytes, &ev); err != nil {
return nil, nil, err return nil, nil, err
} }
needSet := stateNeeded[ev.RoomID()] needSet := stateNeeded[ev.RoomID().String()]
if needSet == nil { // make set if required if needSet == nil { // make set if required
needSet = make(map[string]bool) needSet = make(map[string]bool)
} }
@ -344,7 +344,7 @@ func (s *outputRoomEventsStatements) SelectStateInRange(
for _, id := range addIDs { for _, id := range addIDs {
needSet[id] = true needSet[id] = true
} }
stateNeeded[ev.RoomID()] = needSet stateNeeded[ev.RoomID().String()] = needSet
ev.Visibility = historyVisibility ev.Visibility = historyVisibility
eventIDToEvent[eventID] = types.StreamEvent{ eventIDToEvent[eventID] = types.StreamEvent{
@ -403,7 +403,7 @@ func (s *outputRoomEventsStatements) InsertEvent(
stmt := sqlutil.TxStmt(txn, s.insertEventStmt) stmt := sqlutil.TxStmt(txn, s.insertEventStmt)
err = stmt.QueryRowContext( err = stmt.QueryRowContext(
ctx, ctx,
event.RoomID(), event.RoomID().String(),
event.EventID(), event.EventID(),
headeredJSON, headeredJSON,
event.Type(), event.Type(),

View file

@ -107,7 +107,7 @@ func (s *outputRoomEventsTopologyStatements) InsertEventInTopology(
ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, pos types.StreamPosition, ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, pos types.StreamPosition,
) (topoPos types.StreamPosition, err error) { ) (topoPos types.StreamPosition, err error) {
err = sqlutil.TxStmt(txn, s.insertEventInTopologyStmt).QueryRowContext( err = sqlutil.TxStmt(txn, s.insertEventInTopologyStmt).QueryRowContext(
ctx, event.EventID(), event.Depth(), event.RoomID(), pos, ctx, event.EventID(), event.Depth(), event.RoomID().String(), pos,
).Scan(&topoPos) ).Scan(&topoPos)
return return
} }

View file

@ -114,14 +114,7 @@ func (d *Database) StreamEventsToEvents(ctx context.Context, device *userapi.Dev
}).WithError(err).Warnf("Failed to add transaction ID to event") }).WithError(err).Warnf("Failed to add transaction ID to event")
continue continue
} }
roomID, err := spec.NewRoomID(in[i].RoomID()) deviceSenderID, err := rsAPI.QuerySenderIDForUser(ctx, in[i].RoomID(), *userID)
if err != nil {
logrus.WithFields(logrus.Fields{
"event_id": out[i].EventID(),
}).WithError(err).Warnf("Room ID is invalid")
continue
}
deviceSenderID, err := rsAPI.QuerySenderIDForUser(ctx, *roomID, *userID)
if err != nil || deviceSenderID == nil { if err != nil || deviceSenderID == nil {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"event_id": out[i].EventID(), "event_id": out[i].EventID(),
@ -236,7 +229,7 @@ func (d *Database) UpsertAccountData(
// to account for the fact that the given event is no longer a backwards extremity, but may be marked as such. // 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. // 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 *rstypes.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 { if err := d.BackwardExtremities.DeleteBackwardExtremity(ctx, txn, ev.RoomID().String(), ev.EventID()); err != nil {
return err return err
} }
@ -257,7 +250,7 @@ func (d *Database) handleBackwardExtremities(ctx context.Context, txn *sql.Tx, e
// If the event is missing, consider it a backward extremity. // If the event is missing, consider it a backward extremity.
if !found { if !found {
if err = d.BackwardExtremities.InsertsBackwardExtremity(ctx, txn, ev.RoomID(), ev.EventID(), eID); err != nil { if err = d.BackwardExtremities.InsertsBackwardExtremity(ctx, txn, ev.RoomID().String(), ev.EventID(), eID); err != nil {
return err return err
} }
} }
@ -426,7 +419,7 @@ func (d *Database) fetchStateEvents(
} }
// we know we got them all otherwise an error would've been returned, so just loop the events // we know we got them all otherwise an error would've been returned, so just loop the events
for _, ev := range evs { for _, ev := range evs {
roomID := ev.RoomID() roomID := ev.RoomID().String()
stateBetween[roomID] = append(stateBetween[roomID], ev) stateBetween[roomID] = append(stateBetween[roomID], ev)
} }
} }
@ -522,11 +515,7 @@ func getMembershipFromEvent(ctx context.Context, ev gomatrixserverlib.PDU, userI
if err != nil { if err != nil {
return "", "" return "", ""
} }
roomID, err := spec.NewRoomID(ev.RoomID()) senderID, err := rsAPI.QuerySenderIDForUser(ctx, ev.RoomID(), *fullUser)
if err != nil {
return "", ""
}
senderID, err := rsAPI.QuerySenderIDForUser(ctx, *roomID, *fullUser)
if err != nil || senderID == nil { if err != nil || senderID == nil {
return "", "" return "", ""
} }
@ -626,7 +615,7 @@ func (d *Database) UpdateRelations(ctx context.Context, event *rstypes.HeaderedE
default: default:
return d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error { return d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error {
return d.Relations.InsertRelation( return d.Relations.InsertRelation(
ctx, txn, event.RoomID(), content.Relations.EventID, ctx, txn, event.RoomID().String(), content.Relations.EventID,
event.EventID(), event.Type(), content.Relations.RelationType, event.EventID(), event.Type(), content.Relations.RelationType,
) )
}) })

View file

@ -339,7 +339,7 @@ func (s *currentRoomStateStatements) UpsertRoomState(
stmt := sqlutil.TxStmt(txn, s.upsertRoomStateStmt) stmt := sqlutil.TxStmt(txn, s.upsertRoomStateStmt)
_, err = stmt.ExecContext( _, err = stmt.ExecContext(
ctx, ctx,
event.RoomID(), event.RoomID().String(),
event.EventID(), event.EventID(),
event.Type(), event.Type(),
event.UserID.String(), event.UserID.String(),

View file

@ -106,7 +106,7 @@ func (s *inviteEventsStatements) InsertInviteEvent(
_, err = stmt.ExecContext( _, err = stmt.ExecContext(
ctx, ctx,
streamPos, streamPos,
inviteEvent.RoomID(), inviteEvent.RoomID().String(),
inviteEvent.EventID(), inviteEvent.EventID(),
inviteEvent.UserID.String(), inviteEvent.UserID.String(),
headeredJSON, headeredJSON,

View file

@ -111,7 +111,7 @@ func (s *membershipsStatements) UpsertMembership(
} }
_, err = sqlutil.TxStmt(txn, s.upsertMembershipStmt).ExecContext( _, err = sqlutil.TxStmt(txn, s.upsertMembershipStmt).ExecContext(
ctx, ctx,
event.RoomID(), event.RoomID().String(),
event.StateKeyResolved, event.StateKeyResolved,
membership, membership,
event.EventID(), event.EventID(),

View file

@ -254,7 +254,7 @@ func (s *outputRoomEventsStatements) SelectStateInRange(
if err := json.Unmarshal(eventBytes, &ev); err != nil { if err := json.Unmarshal(eventBytes, &ev); err != nil {
return nil, nil, err return nil, nil, err
} }
needSet := stateNeeded[ev.RoomID()] needSet := stateNeeded[ev.RoomID().String()]
if needSet == nil { // make set if required if needSet == nil { // make set if required
needSet = make(map[string]bool) needSet = make(map[string]bool)
} }
@ -264,7 +264,7 @@ func (s *outputRoomEventsStatements) SelectStateInRange(
for _, id := range addIDs { for _, id := range addIDs {
needSet[id] = true needSet[id] = true
} }
stateNeeded[ev.RoomID()] = needSet stateNeeded[ev.RoomID().String()] = needSet
ev.Visibility = historyVisibility ev.Visibility = historyVisibility
eventIDToEvent[eventID] = types.StreamEvent{ eventIDToEvent[eventID] = types.StreamEvent{
@ -344,7 +344,7 @@ func (s *outputRoomEventsStatements) InsertEvent(
_, err = insertStmt.ExecContext( _, err = insertStmt.ExecContext(
ctx, ctx,
streamPos, streamPos,
event.RoomID(), event.RoomID().String(),
event.EventID(), event.EventID(),
headeredJSON, headeredJSON,
event.Type(), event.Type(),

View file

@ -106,7 +106,7 @@ func (s *outputRoomEventsTopologyStatements) InsertEventInTopology(
ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, pos types.StreamPosition, ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, pos types.StreamPosition,
) (types.StreamPosition, error) { ) (types.StreamPosition, error) {
_, err := sqlutil.TxStmt(txn, s.insertEventInTopologyStmt).ExecContext( _, err := sqlutil.TxStmt(txn, s.insertEventInTopologyStmt).ExecContext(
ctx, event.EventID(), event.Depth(), event.RoomID(), pos, ctx, event.EventID(), event.Depth(), event.RoomID().String(), pos,
) )
return types.StreamPosition(event.Depth()), err return types.StreamPosition(event.Depth()), err
} }

View file

@ -63,31 +63,27 @@ func (p *InviteStreamProvider) IncrementalSync(
return from return from
} }
eventFormat := synctypes.FormatSync
if req.Filter.EventFormat == synctypes.EventFormatFederation {
eventFormat = synctypes.FormatSyncFederation
}
for roomID, inviteEvent := range invites { for roomID, inviteEvent := range invites {
user := spec.UserID{} user := spec.UserID{}
validRoomID, err := spec.NewRoomID(inviteEvent.RoomID()) sender, err := p.rsAPI.QueryUserIDForSender(ctx, inviteEvent.RoomID(), inviteEvent.SenderID())
if err != nil {
continue
}
sender, err := p.rsAPI.QueryUserIDForSender(ctx, *validRoomID, inviteEvent.SenderID())
if err == nil && sender != nil { if err == nil && sender != nil {
user = *sender user = *sender
} }
sk := inviteEvent.StateKey()
if sk != nil && *sk != "" {
skUserID, err := p.rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*inviteEvent.StateKey()))
if err == nil && skUserID != nil {
skString := skUserID.String()
sk = &skString
}
}
// skip ignored user events // skip ignored user events
if _, ok := req.IgnoredUsers.List[user.String()]; ok { if _, ok := req.IgnoredUsers.List[user.String()]; ok {
continue continue
} }
ir := types.NewInviteResponse(inviteEvent, user, sk) ir, err := types.NewInviteResponse(ctx, p.rsAPI, inviteEvent, eventFormat)
if err != nil {
req.Log.WithError(err).Error("failed creating invite response")
continue
}
req.Response.Rooms.Invite[roomID] = ir req.Response.Rooms.Invite[roomID] = ir
} }

View file

@ -3,7 +3,6 @@ package streams
import ( import (
"context" "context"
"database/sql" "database/sql"
"encoding/json"
"fmt" "fmt"
"time" "time"
@ -16,8 +15,6 @@ import (
"github.com/matrix-org/dendrite/syncapi/types" "github.com/matrix-org/dendrite/syncapi/types"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/gomatrixserverlib/spec"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
"github.com/matrix-org/dendrite/syncapi/notifier" "github.com/matrix-org/dendrite/syncapi/notifier"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
@ -88,6 +85,11 @@ func (p *PDUStreamProvider) CompleteSync(
req.Log.WithError(err).Error("unable to update event filter with ignored users") req.Log.WithError(err).Error("unable to update event filter with ignored users")
} }
eventFormat := synctypes.FormatSync
if req.Filter.EventFormat == synctypes.EventFormatFederation {
eventFormat = synctypes.FormatSyncFederation
}
recentEvents, err := snapshot.RecentEvents(ctx, joinedRoomIDs, r, &eventFilter, true, true) recentEvents, err := snapshot.RecentEvents(ctx, joinedRoomIDs, r, &eventFilter, true, true)
if err != nil { if err != nil {
return from return from
@ -105,7 +107,7 @@ func (p *PDUStreamProvider) CompleteSync(
// get the join response for each room // get the join response for each room
jr, jerr := p.getJoinResponseForCompleteSync( jr, jerr := p.getJoinResponseForCompleteSync(
ctx, snapshot, roomID, &stateFilter, req.WantFullState, req.Device, false, ctx, snapshot, roomID, &stateFilter, req.WantFullState, req.Device, false,
events.Events, events.Limited, events.Events, events.Limited, eventFormat,
) )
if jerr != nil { if jerr != nil {
req.Log.WithError(jerr).Error("p.getJoinResponseForCompleteSync failed") req.Log.WithError(jerr).Error("p.getJoinResponseForCompleteSync failed")
@ -142,7 +144,7 @@ func (p *PDUStreamProvider) CompleteSync(
events := recentEvents[roomID] events := recentEvents[roomID]
jr, err = p.getJoinResponseForCompleteSync( jr, err = p.getJoinResponseForCompleteSync(
ctx, snapshot, roomID, &stateFilter, req.WantFullState, req.Device, true, ctx, snapshot, roomID, &stateFilter, req.WantFullState, req.Device, true,
events.Events, events.Limited, events.Events, events.Limited, eventFormat,
) )
if err != nil { if err != nil {
req.Log.WithError(err).Error("p.getJoinResponseForCompleteSync failed") req.Log.WithError(err).Error("p.getJoinResponseForCompleteSync failed")
@ -346,26 +348,14 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse(
return r.From, fmt.Errorf("p.DB.GetBackwardTopologyPos: %w", err) return r.From, fmt.Errorf("p.DB.GetBackwardTopologyPos: %w", err)
} }
eventFormat := synctypes.FormatSync
if req.Filter.EventFormat == synctypes.EventFormatFederation {
eventFormat = synctypes.FormatSyncFederation
}
// Now that we've filtered the timeline, work out which state events are still // 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 // left. Anything that appears in the filtered timeline will be removed from the
// "state" section and kept in "timeline". // "state" section and kept in "timeline".
// update the powerlevel event for timeline events
for i, ev := range events {
if ev.Version() != gomatrixserverlib.RoomVersionPseudoIDs {
continue
}
if ev.Type() != spec.MRoomPowerLevels || !ev.StateKeyEquals("") {
continue
}
var newEvent gomatrixserverlib.PDU
newEvent, err = p.updatePowerLevelEvent(ctx, ev)
if err != nil {
return r.From, err
}
events[i] = &rstypes.HeaderedEvent{PDU: newEvent}
}
sEvents := gomatrixserverlib.HeaderedReverseTopologicalOrdering( sEvents := gomatrixserverlib.HeaderedReverseTopologicalOrdering(
gomatrixserverlib.ToPDUs(removeDuplicates(delta.StateEvents, events)), gomatrixserverlib.ToPDUs(removeDuplicates(delta.StateEvents, events)),
gomatrixserverlib.TopologicalOrderByAuthEvents, gomatrixserverlib.TopologicalOrderByAuthEvents,
@ -380,15 +370,6 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse(
continue continue
} }
delta.StateEvents[i-skipped] = he delta.StateEvents[i-skipped] = he
// update the powerlevel event for state events
if ev.Version() == gomatrixserverlib.RoomVersionPseudoIDs && ev.Type() == spec.MRoomPowerLevels && ev.StateKeyEquals("") {
var newEvent gomatrixserverlib.PDU
newEvent, err = p.updatePowerLevelEvent(ctx, he)
if err != nil {
return r.From, err
}
delta.StateEvents[i-skipped] = &rstypes.HeaderedEvent{PDU: newEvent}
}
} }
delta.StateEvents = delta.StateEvents[:len(sEvents)-skipped] delta.StateEvents = delta.StateEvents[:len(sEvents)-skipped]
@ -413,13 +394,13 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse(
} }
} }
jr.Timeline.PrevBatch = &prevBatch jr.Timeline.PrevBatch = &prevBatch
jr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) { jr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), eventFormat, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID) return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
}) })
// If we are limited by the filter AND the history visibility filter // If we are limited by the filter AND the history visibility filter
// didn't "remove" events, return that the response is limited. // didn't "remove" events, return that the response is limited.
jr.Timeline.Limited = (limited && len(events) == len(recentEvents)) || delta.NewlyJoined jr.Timeline.Limited = (limited && len(events) == len(recentEvents)) || delta.NewlyJoined
jr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(delta.StateEvents), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) { jr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(delta.StateEvents), eventFormat, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID) return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
}) })
req.Response.Rooms.Join[delta.RoomID] = jr req.Response.Rooms.Join[delta.RoomID] = jr
@ -428,11 +409,11 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse(
jr := types.NewJoinResponse() jr := types.NewJoinResponse()
jr.Timeline.PrevBatch = &prevBatch jr.Timeline.PrevBatch = &prevBatch
// TODO: Apply history visibility on peeked rooms // TODO: Apply history visibility on peeked rooms
jr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(recentEvents), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) { jr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(recentEvents), eventFormat, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID) return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
}) })
jr.Timeline.Limited = limited jr.Timeline.Limited = limited
jr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(delta.StateEvents), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) { jr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(delta.StateEvents), eventFormat, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID) return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
}) })
req.Response.Rooms.Peek[delta.RoomID] = jr req.Response.Rooms.Peek[delta.RoomID] = jr
@ -443,13 +424,13 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse(
case spec.Ban: case spec.Ban:
lr := types.NewLeaveResponse() lr := types.NewLeaveResponse()
lr.Timeline.PrevBatch = &prevBatch lr.Timeline.PrevBatch = &prevBatch
lr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) { lr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), eventFormat, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID) return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
}) })
// If we are limited by the filter AND the history visibility filter // If we are limited by the filter AND the history visibility filter
// didn't "remove" events, return that the response is limited. // didn't "remove" events, return that the response is limited.
lr.Timeline.Limited = limited && len(events) == len(recentEvents) lr.Timeline.Limited = limited && len(events) == len(recentEvents)
lr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(delta.StateEvents), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) { lr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(delta.StateEvents), eventFormat, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID) return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
}) })
req.Response.Rooms.Leave[delta.RoomID] = lr req.Response.Rooms.Leave[delta.RoomID] = lr
@ -458,75 +439,6 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse(
return latestPosition, nil return latestPosition, nil
} }
func (p *PDUStreamProvider) updatePowerLevelEvent(ctx context.Context, ev *rstypes.HeaderedEvent) (gomatrixserverlib.PDU, error) {
pls, err := gomatrixserverlib.NewPowerLevelContentFromEvent(ev)
if err != nil {
return nil, err
}
newPls := make(map[string]int64)
var userID *spec.UserID
for user, level := range pls.Users {
validRoomID, _ := spec.NewRoomID(ev.RoomID())
userID, err = p.rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(user))
if err != nil {
return nil, err
}
newPls[userID.String()] = level
}
var newPlBytes, newEv []byte
newPlBytes, err = json.Marshal(newPls)
if err != nil {
return nil, err
}
newEv, err = sjson.SetRawBytes(ev.JSON(), "content.users", newPlBytes)
if err != nil {
return nil, err
}
// do the same for prev content
prevContent := gjson.GetBytes(ev.JSON(), "unsigned.prev_content")
if !prevContent.Exists() {
var evNew gomatrixserverlib.PDU
evNew, err = gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionPseudoIDs).NewEventFromTrustedJSON(newEv, false)
if err != nil {
return nil, err
}
return evNew, err
}
pls = gomatrixserverlib.PowerLevelContent{}
err = json.Unmarshal([]byte(prevContent.Raw), &pls)
if err != nil {
return nil, err
}
newPls = make(map[string]int64)
for user, level := range pls.Users {
validRoomID, _ := spec.NewRoomID(ev.RoomID())
userID, err = p.rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(user))
if err != nil {
return nil, err
}
newPls[userID.String()] = level
}
newPlBytes, err = json.Marshal(newPls)
if err != nil {
return nil, err
}
newEv, err = sjson.SetRawBytes(newEv, "unsigned.prev_content.users", newPlBytes)
if err != nil {
return nil, err
}
var evNew gomatrixserverlib.PDU
evNew, err = gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionPseudoIDs).NewEventFromTrustedJSONWithEventID(ev.EventID(), newEv, false)
if err != nil {
return nil, err
}
return evNew, err
}
// applyHistoryVisibilityFilter gets the current room state and supplies it to ApplyHistoryVisibilityFilter, to make // applyHistoryVisibilityFilter gets the current room state and supplies it to ApplyHistoryVisibilityFilter, to make
// sure we always return the required events in the timeline. // sure we always return the required events in the timeline.
func applyHistoryVisibilityFilter( func applyHistoryVisibilityFilter(
@ -592,6 +504,7 @@ func (p *PDUStreamProvider) getJoinResponseForCompleteSync(
isPeek bool, isPeek bool,
recentStreamEvents []types.StreamEvent, recentStreamEvents []types.StreamEvent,
limited bool, limited bool,
eventFormat synctypes.ClientEventFormat,
) (jr *types.JoinResponse, err error) { ) (jr *types.JoinResponse, err error) {
jr = types.NewJoinResponse() jr = types.NewJoinResponse()
// TODO: When filters are added, we may need to call this multiple times to get enough events. // TODO: When filters are added, we may need to call this multiple times to get enough events.
@ -675,43 +588,14 @@ func (p *PDUStreamProvider) getJoinResponseForCompleteSync(
prevBatch.Decrement() prevBatch.Decrement()
} }
// Update powerlevel events for timeline events
for i, ev := range events {
if ev.Version() != gomatrixserverlib.RoomVersionPseudoIDs {
continue
}
if ev.Type() != spec.MRoomPowerLevels || !ev.StateKeyEquals("") {
continue
}
newEvent, err := p.updatePowerLevelEvent(ctx, ev)
if err != nil {
return nil, err
}
events[i] = &rstypes.HeaderedEvent{PDU: newEvent}
}
// Update powerlevel events for state events
for i, ev := range stateEvents {
if ev.Version() != gomatrixserverlib.RoomVersionPseudoIDs {
continue
}
if ev.Type() != spec.MRoomPowerLevels || !ev.StateKeyEquals("") {
continue
}
newEvent, err := p.updatePowerLevelEvent(ctx, ev)
if err != nil {
return nil, err
}
stateEvents[i] = &rstypes.HeaderedEvent{PDU: newEvent}
}
jr.Timeline.PrevBatch = prevBatch jr.Timeline.PrevBatch = prevBatch
jr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) { jr.Timeline.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(events), eventFormat, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID) return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
}) })
// If we are limited by the filter AND the history visibility filter // If we are limited by the filter AND the history visibility filter
// didn't "remove" events, return that the response is limited. // didn't "remove" events, return that the response is limited.
jr.Timeline.Limited = limited && len(events) == len(recentEvents) jr.Timeline.Limited = limited && len(events) == len(recentEvents)
jr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(stateEvents), synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) { jr.State.Events = synctypes.ToClientEvents(gomatrixserverlib.ToPDUs(stateEvents), eventFormat, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID) return p.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
}) })
return jr, nil return jr, nil

View file

@ -209,6 +209,156 @@ func testSyncAccessTokens(t *testing.T, dbType test.DBType) {
} }
} }
func TestSyncAPIEventFormatPowerLevels(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
testSyncEventFormatPowerLevels(t, dbType)
})
}
func testSyncEventFormatPowerLevels(t *testing.T, dbType test.DBType) {
user := test.NewUser(t)
setRoomVersion := func(t *testing.T, r *test.Room) { r.Version = gomatrixserverlib.RoomVersionPseudoIDs }
room := test.NewRoom(t, user, setRoomVersion)
alice := userapi.Device{
ID: "ALICEID",
UserID: user.ID,
AccessToken: "ALICE_BEARER_TOKEN",
DisplayName: "Alice",
AccountType: userapi.AccountTypeUser,
}
room.CreateAndInsert(t, user, spec.MRoomPowerLevels, gomatrixserverlib.PowerLevelContent{
Users: map[string]int64{
user.ID: 100,
},
}, test.WithStateKey(""))
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
routers := httputil.NewRouters()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
natsInstance := jetstream.NATSInstance{}
defer close()
jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream)
msgs := toNATSMsgs(t, cfg, room.Events()...)
AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, &syncUserAPI{accounts: []userapi.Device{alice}}, &syncRoomserverAPI{rooms: []*test.Room{room}}, caches, caching.DisableMetrics)
testrig.MustPublishMsgs(t, jsctx, msgs...)
testCases := []struct {
name string
wantCode int
wantJoinedRooms []string
eventFormat synctypes.ClientEventFormat
}{
{
name: "Client format",
wantCode: 200,
wantJoinedRooms: []string{room.ID},
eventFormat: synctypes.FormatSync,
},
{
name: "Federation format",
wantCode: 200,
wantJoinedRooms: []string{room.ID},
eventFormat: synctypes.FormatSyncFederation,
},
}
syncUntil(t, routers, alice.AccessToken, false, func(syncBody string) bool {
// wait for the last sent eventID to come down sync
path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(event_id=="%s")`, room.ID, room.Events()[len(room.Events())-1].EventID())
return gjson.Get(syncBody, path).Exists()
})
for _, tc := range testCases {
format := ""
if tc.eventFormat == synctypes.FormatSyncFederation {
format = "federation"
}
w := httptest.NewRecorder()
routers.Client.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{
"access_token": alice.AccessToken,
"timeout": "0",
"filter": fmt.Sprintf(`{"event_format":"%s"}`, format),
})))
if w.Code != tc.wantCode {
t.Fatalf("%s: got HTTP %d want %d", tc.name, w.Code, tc.wantCode)
}
if tc.wantJoinedRooms != nil {
var res types.Response
if err := json.NewDecoder(w.Body).Decode(&res); err != nil {
t.Fatalf("%s: failed to decode response body: %s", tc.name, err)
}
if len(res.Rooms.Join) != len(tc.wantJoinedRooms) {
t.Errorf("%s: got %v joined rooms, want %v.\nResponse: %+v", tc.name, len(res.Rooms.Join), len(tc.wantJoinedRooms), res)
}
t.Logf("res: %+v", res.Rooms.Join[room.ID])
gotEventIDs := make([]string, len(res.Rooms.Join[room.ID].Timeline.Events))
for i, ev := range res.Rooms.Join[room.ID].Timeline.Events {
gotEventIDs[i] = ev.EventID
}
test.AssertEventIDsEqual(t, gotEventIDs, room.Events())
event := room.CreateAndInsert(t, user, spec.MRoomPowerLevels, gomatrixserverlib.PowerLevelContent{
Users: map[string]int64{
user.ID: 100,
"@otheruser:localhost": 50,
},
}, test.WithStateKey(""))
msgs := toNATSMsgs(t, cfg, event)
testrig.MustPublishMsgs(t, jsctx, msgs...)
syncUntil(t, routers, alice.AccessToken, false, func(syncBody string) bool {
// wait for the last sent eventID to come down sync
path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(event_id=="%s")`, room.ID, room.Events()[len(room.Events())-1].EventID())
return gjson.Get(syncBody, path).Exists()
})
since := res.NextBatch.String()
w := httptest.NewRecorder()
routers.Client.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{
"access_token": alice.AccessToken,
"timeout": "0",
"filter": fmt.Sprintf(`{"event_format":"%s"}`, format),
"since": since,
})))
if w.Code != 200 {
t.Errorf("since=%s got HTTP %d want 200", since, w.Code)
}
res = *types.NewResponse()
if err := json.NewDecoder(w.Body).Decode(&res); err != nil {
t.Errorf("failed to decode response body: %s", err)
}
if len(res.Rooms.Join) != 1 {
t.Fatalf("since=%s got %d joined rooms, want 1", since, len(res.Rooms.Join))
}
gotEventIDs = make([]string, len(res.Rooms.Join[room.ID].Timeline.Events))
for j, ev := range res.Rooms.Join[room.ID].Timeline.Events {
gotEventIDs[j] = ev.EventID
if ev.Type == spec.MRoomPowerLevels {
content := gomatrixserverlib.PowerLevelContent{}
err := json.Unmarshal(ev.Content, &content)
if err != nil {
t.Errorf("failed to unmarshal power level content: %s", err)
}
otherUserLevel := content.UserLevel("@otheruser:localhost")
if otherUserLevel != 50 {
t.Errorf("Expected user PL of %d but got %d", 50, otherUserLevel)
}
}
}
events := []*rstypes.HeaderedEvent{room.Events()[len(room.Events())-1]}
test.AssertEventIDsEqual(t, gotEventIDs, events)
}
}
}
// Tests what happens when we create a room and then /sync before all events from /createRoom have // Tests what happens when we create a room and then /sync before all events from /createRoom have
// been sent to the syncapi // been sent to the syncapi
func TestSyncAPICreateRoomSyncEarly(t *testing.T) { func TestSyncAPICreateRoomSyncEarly(t *testing.T) {
@ -1251,7 +1401,7 @@ func toNATSMsgs(t *testing.T, cfg *config.Dendrite, input ...*rstypes.HeaderedEv
if ev.StateKey() != nil { if ev.StateKey() != nil {
addsStateIDs = append(addsStateIDs, ev.EventID()) addsStateIDs = append(addsStateIDs, ev.EventID())
} }
result[i] = testrig.NewOutputEventMsg(t, cfg, ev.RoomID(), api.OutputEvent{ result[i] = testrig.NewOutputEventMsg(t, cfg, ev.RoomID().String(), api.OutputEvent{
Type: rsapi.OutputTypeNewRoomEvent, Type: rsapi.OutputTypeNewRoomEvent,
NewRoomEvent: &rsapi.OutputNewRoomEvent{ NewRoomEvent: &rsapi.OutputNewRoomEvent{
Event: ev, Event: ev,

View file

@ -16,12 +16,23 @@
package synctypes package synctypes
import ( import (
"encoding/json"
"fmt" "fmt"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/gomatrixserverlib/spec"
"github.com/sirupsen/logrus"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
) )
// PrevEventRef represents a reference to a previous event in a state event upgrade
type PrevEventRef struct {
PrevContent json.RawMessage `json:"prev_content"`
ReplacesState string `json:"replaces_state"`
PrevSenderID string `json:"prev_sender"`
}
type ClientEventFormat int type ClientEventFormat int
const ( const (
@ -30,8 +41,21 @@ const (
// FormatSync will include only the event keys required by the /sync API. Notably, this // FormatSync will include only the event keys required by the /sync API. Notably, this
// means the 'room_id' will be missing from the events. // means the 'room_id' will be missing from the events.
FormatSync FormatSync
// FormatSyncFederation will include all event keys normally included in federated events.
// This allows clients to request federated formatted events via the /sync API.
FormatSyncFederation
) )
// ClientFederationFields extends a ClientEvent to contain the additional fields present in a
// federation event. Used when the client requests `event_format` of type `federation`.
type ClientFederationFields struct {
Depth int64 `json:"depth,omitempty"`
PrevEvents []string `json:"prev_events,omitempty"`
AuthEvents []string `json:"auth_events,omitempty"`
Signatures spec.RawJSON `json:"signatures,omitempty"`
Hashes spec.RawJSON `json:"hashes,omitempty"`
}
// ClientEvent is an event which is fit for consumption by clients, in accordance with the specification. // ClientEvent is an event which is fit for consumption by clients, in accordance with the specification.
type ClientEvent struct { type ClientEvent struct {
Content spec.RawJSON `json:"content"` Content spec.RawJSON `json:"content"`
@ -44,6 +68,9 @@ type ClientEvent struct {
Type string `json:"type"` Type string `json:"type"`
Unsigned spec.RawJSON `json:"unsigned,omitempty"` Unsigned spec.RawJSON `json:"unsigned,omitempty"`
Redacts string `json:"redacts,omitempty"` Redacts string `json:"redacts,omitempty"`
// Only sent to clients when `event_format` == `federation`.
ClientFederationFields
} }
// ToClientEvents converts server events to client events. // ToClientEvents converts server events to client events.
@ -53,72 +80,24 @@ func ToClientEvents(serverEvs []gomatrixserverlib.PDU, format ClientEventFormat,
if se == nil { if se == nil {
continue // TODO: shouldn't happen? continue // TODO: shouldn't happen?
} }
sender := spec.UserID{} ev, err := ToClientEvent(se, format, userIDForSender)
validRoomID, err := spec.NewRoomID(se.RoomID())
if err != nil { if err != nil {
logrus.WithError(err).Warn("Failed converting event to ClientEvent")
continue continue
} }
userID, err := userIDForSender(*validRoomID, se.SenderID()) evs = append(evs, *ev)
if err == nil && userID != nil {
sender = *userID
}
sk := se.StateKey()
if sk != nil && *sk != "" {
skUserID, err := userIDForSender(*validRoomID, spec.SenderID(*sk))
if err == nil && skUserID != nil {
skString := skUserID.String()
sk = &skString
}
}
evs = append(evs, ToClientEvent(se, format, sender, sk))
} }
return evs return evs
} }
// ToClientEvent converts a single server event to a client event. // ToClientEventDefault converts a single server event to a client event.
func ToClientEvent(se gomatrixserverlib.PDU, format ClientEventFormat, sender spec.UserID, stateKey *string) ClientEvent {
ce := ClientEvent{
Content: spec.RawJSON(se.Content()),
Sender: sender.String(),
Type: se.Type(),
StateKey: stateKey,
Unsigned: spec.RawJSON(se.Unsigned()),
OriginServerTS: se.OriginServerTS(),
EventID: se.EventID(),
Redacts: se.Redacts(),
}
if format == FormatAll {
ce.RoomID = se.RoomID()
}
if se.Version() == gomatrixserverlib.RoomVersionPseudoIDs {
ce.SenderKey = se.SenderID()
}
return ce
}
// ToClientEvent converts a single server event to a client event.
// It provides default logic for event.SenderID & event.StateKey -> userID conversions. // It provides default logic for event.SenderID & event.StateKey -> userID conversions.
func ToClientEventDefault(userIDQuery spec.UserIDForSender, event gomatrixserverlib.PDU) ClientEvent { func ToClientEventDefault(userIDQuery spec.UserIDForSender, event gomatrixserverlib.PDU) ClientEvent {
sender := spec.UserID{} ev, err := ToClientEvent(event, FormatAll, userIDQuery)
validRoomID, err := spec.NewRoomID(event.RoomID())
if err != nil { if err != nil {
return ClientEvent{} return ClientEvent{}
} }
userID, err := userIDQuery(*validRoomID, event.SenderID()) return *ev
if err == nil && userID != nil {
sender = *userID
}
sk := event.StateKey()
if sk != nil && *sk != "" {
skUserID, err := userIDQuery(*validRoomID, spec.SenderID(*event.StateKey()))
if err == nil && skUserID != nil {
skString := skUserID.String()
sk = &skString
}
}
return ToClientEvent(event, FormatAll, sender, sk)
} }
// If provided state key is a user ID (state keys beginning with @ are reserved for this purpose) // If provided state key is a user ID (state keys beginning with @ are reserved for this purpose)
@ -132,11 +111,11 @@ func FromClientStateKey(roomID spec.RoomID, stateKey string, senderIDQuery spec.
parsedStateKey, err := spec.NewUserID(stateKey, true) parsedStateKey, err := spec.NewUserID(stateKey, true)
if err != nil { if err != nil {
// If invalid user ID, then there is no associated state event. // If invalid user ID, then there is no associated state event.
return nil, fmt.Errorf("Provided state key begins with @ but is not a valid user ID: %s", err.Error()) return nil, fmt.Errorf("Provided state key begins with @ but is not a valid user ID: %w", err)
} }
senderID, err := senderIDQuery(roomID, *parsedStateKey) senderID, err := senderIDQuery(roomID, *parsedStateKey)
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to query sender ID: %s", err.Error()) return nil, fmt.Errorf("Failed to query sender ID: %w", err)
} }
if senderID == nil { if senderID == nil {
// If no sender ID, then there is no associated state event. // If no sender ID, then there is no associated state event.
@ -148,3 +127,304 @@ func FromClientStateKey(roomID spec.RoomID, stateKey string, senderIDQuery spec.
return &stateKey, nil return &stateKey, nil
} }
} }
// ToClientEvent converts a single server event to a client event.
func ToClientEvent(se gomatrixserverlib.PDU, format ClientEventFormat, userIDForSender spec.UserIDForSender) (*ClientEvent, error) {
ce := ClientEvent{
Content: se.Content(),
Sender: string(se.SenderID()),
Type: se.Type(),
StateKey: se.StateKey(),
Unsigned: se.Unsigned(),
OriginServerTS: se.OriginServerTS(),
EventID: se.EventID(),
Redacts: se.Redacts(),
}
switch format {
case FormatAll:
ce.RoomID = se.RoomID().String()
case FormatSync:
case FormatSyncFederation:
ce.RoomID = se.RoomID().String()
ce.AuthEvents = se.AuthEventIDs()
ce.PrevEvents = se.PrevEventIDs()
ce.Depth = se.Depth()
// TODO: Set Signatures & Hashes fields
}
if format != FormatSyncFederation && se.Version() == gomatrixserverlib.RoomVersionPseudoIDs {
err := updatePseudoIDs(&ce, se, userIDForSender, format)
if err != nil {
return nil, err
}
}
return &ce, nil
}
func updatePseudoIDs(ce *ClientEvent, se gomatrixserverlib.PDU, userIDForSender spec.UserIDForSender, format ClientEventFormat) error {
ce.SenderKey = se.SenderID()
userID, err := userIDForSender(se.RoomID(), se.SenderID())
if err == nil && userID != nil {
ce.Sender = userID.String()
}
sk := se.StateKey()
if sk != nil && *sk != "" {
skUserID, err := userIDForSender(se.RoomID(), spec.SenderID(*sk))
if err == nil && skUserID != nil {
skString := skUserID.String()
ce.StateKey = &skString
}
}
var prev PrevEventRef
if err := json.Unmarshal(se.Unsigned(), &prev); err == nil && prev.PrevSenderID != "" {
prevUserID, err := userIDForSender(se.RoomID(), spec.SenderID(prev.PrevSenderID))
if err == nil && userID != nil {
prev.PrevSenderID = prevUserID.String()
} else {
errString := "userID unknown"
if err != nil {
errString = err.Error()
}
logrus.Warnf("Failed to find userID for prev_sender in ClientEvent: %s", errString)
// NOTE: Not much can be done here, so leave the previous value in place.
}
ce.Unsigned, err = json.Marshal(prev)
if err != nil {
err = fmt.Errorf("Failed to marshal unsigned content for ClientEvent: %w", err)
return err
}
}
switch se.Type() {
case spec.MRoomCreate:
updatedContent, err := updateCreateEvent(se.Content(), userIDForSender, se.RoomID())
if err != nil {
err = fmt.Errorf("Failed to update m.room.create event for ClientEvent: %w", err)
return err
}
ce.Content = updatedContent
case spec.MRoomMember:
updatedEvent, err := updateInviteEvent(userIDForSender, se, format)
if err != nil {
err = fmt.Errorf("Failed to update m.room.member event for ClientEvent: %w", err)
return err
}
if updatedEvent != nil {
ce.Unsigned = updatedEvent.Unsigned()
}
case spec.MRoomPowerLevels:
updatedEvent, err := updatePowerLevelEvent(userIDForSender, se, format)
if err != nil {
err = fmt.Errorf("Failed update m.room.power_levels event for ClientEvent: %w", err)
return err
}
if updatedEvent != nil {
ce.Content = updatedEvent.Content()
ce.Unsigned = updatedEvent.Unsigned()
}
}
return nil
}
func updateCreateEvent(content spec.RawJSON, userIDForSender spec.UserIDForSender, roomID spec.RoomID) (spec.RawJSON, error) {
if creator := gjson.GetBytes(content, "creator"); creator.Exists() {
oldCreator := creator.Str
userID, err := userIDForSender(roomID, spec.SenderID(oldCreator))
if err != nil {
err = fmt.Errorf("Failed to find userID for creator in ClientEvent: %w", err)
return nil, err
}
if userID != nil {
var newCreatorBytes, newContent []byte
newCreatorBytes, err = json.Marshal(userID.String())
if err != nil {
err = fmt.Errorf("Failed to marshal new creator for ClientEvent: %w", err)
return nil, err
}
newContent, err = sjson.SetRawBytes([]byte(content), "creator", newCreatorBytes)
if err != nil {
err = fmt.Errorf("Failed to set new creator for ClientEvent: %w", err)
return nil, err
}
return newContent, nil
}
}
return content, nil
}
func updateInviteEvent(userIDForSender spec.UserIDForSender, ev gomatrixserverlib.PDU, eventFormat ClientEventFormat) (gomatrixserverlib.PDU, error) {
if inviteRoomState := gjson.GetBytes(ev.Unsigned(), "invite_room_state"); inviteRoomState.Exists() {
userID, err := userIDForSender(ev.RoomID(), ev.SenderID())
if err != nil || userID == nil {
if err != nil {
err = fmt.Errorf("invalid userID found when updating invite_room_state: %w", err)
}
return nil, err
}
newState, err := GetUpdatedInviteRoomState(userIDForSender, inviteRoomState, ev, ev.RoomID(), eventFormat)
if err != nil {
return nil, err
}
var newEv []byte
newEv, err = sjson.SetRawBytes(ev.JSON(), "unsigned.invite_room_state", newState)
if err != nil {
return nil, err
}
return gomatrixserverlib.MustGetRoomVersion(ev.Version()).NewEventFromTrustedJSON(newEv, false)
}
return ev, nil
}
type InviteRoomStateEvent struct {
Content spec.RawJSON `json:"content"`
SenderID string `json:"sender"`
StateKey *string `json:"state_key"`
Type string `json:"type"`
}
func GetUpdatedInviteRoomState(userIDForSender spec.UserIDForSender, inviteRoomState gjson.Result, event gomatrixserverlib.PDU, roomID spec.RoomID, eventFormat ClientEventFormat) (spec.RawJSON, error) {
var res spec.RawJSON
inviteStateEvents := []InviteRoomStateEvent{}
err := json.Unmarshal([]byte(inviteRoomState.Raw), &inviteStateEvents)
if err != nil {
return nil, err
}
if event.Version() == gomatrixserverlib.RoomVersionPseudoIDs && eventFormat != FormatSyncFederation {
for i, ev := range inviteStateEvents {
userID, userIDErr := userIDForSender(roomID, spec.SenderID(ev.SenderID))
if userIDErr != nil {
return nil, userIDErr
}
if userID != nil {
inviteStateEvents[i].SenderID = userID.String()
}
if ev.StateKey != nil && *ev.StateKey != "" {
userID, senderErr := userIDForSender(roomID, spec.SenderID(*ev.StateKey))
if senderErr != nil {
return nil, senderErr
}
if userID != nil {
user := userID.String()
inviteStateEvents[i].StateKey = &user
}
}
updatedContent, updateErr := updateCreateEvent(ev.Content, userIDForSender, roomID)
if updateErr != nil {
updateErr = fmt.Errorf("Failed to update m.room.create event for ClientEvent: %w", userIDErr)
return nil, updateErr
}
inviteStateEvents[i].Content = updatedContent
}
}
res, err = json.Marshal(inviteStateEvents)
if err != nil {
return nil, err
}
return res, nil
}
func updatePowerLevelEvent(userIDForSender spec.UserIDForSender, se gomatrixserverlib.PDU, eventFormat ClientEventFormat) (gomatrixserverlib.PDU, error) {
if !se.StateKeyEquals("") {
return se, nil
}
newEv := se.JSON()
usersField := gjson.GetBytes(se.JSON(), "content.users")
if usersField.Exists() {
pls, err := gomatrixserverlib.NewPowerLevelContentFromEvent(se)
if err != nil {
return nil, err
}
newPls := make(map[string]int64)
var userID *spec.UserID
for user, level := range pls.Users {
if eventFormat != FormatSyncFederation {
userID, err = userIDForSender(se.RoomID(), spec.SenderID(user))
if err != nil {
return nil, err
}
user = userID.String()
}
newPls[user] = level
}
var newPlBytes []byte
newPlBytes, err = json.Marshal(newPls)
if err != nil {
return nil, err
}
newEv, err = sjson.SetRawBytes(se.JSON(), "content.users", newPlBytes)
if err != nil {
return nil, err
}
}
// do the same for prev content
prevUsersField := gjson.GetBytes(se.JSON(), "unsigned.prev_content.users")
if prevUsersField.Exists() {
prevContent := gjson.GetBytes(se.JSON(), "unsigned.prev_content")
if !prevContent.Exists() {
evNew, err := gomatrixserverlib.MustGetRoomVersion(se.Version()).NewEventFromTrustedJSON(newEv, false)
if err != nil {
return nil, err
}
return evNew, err
}
pls := gomatrixserverlib.PowerLevelContent{}
err := json.Unmarshal([]byte(prevContent.Raw), &pls)
if err != nil {
return nil, err
}
newPls := make(map[string]int64)
for user, level := range pls.Users {
if eventFormat != FormatSyncFederation {
userID, userErr := userIDForSender(se.RoomID(), spec.SenderID(user))
if userErr != nil {
return nil, userErr
}
user = userID.String()
}
newPls[user] = level
}
var newPlBytes []byte
newPlBytes, err = json.Marshal(newPls)
if err != nil {
return nil, err
}
newEv, err = sjson.SetRawBytes(newEv, "unsigned.prev_content.users", newPlBytes)
if err != nil {
return nil, err
}
}
evNew, err := gomatrixserverlib.MustGetRoomVersion(se.Version()).NewEventFromTrustedJSONWithEventID(se.EventID(), newEv, false)
if err != nil {
return nil, err
}
return evNew, err
}

View file

@ -18,12 +18,77 @@ package synctypes
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"reflect"
"testing" "testing"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/gomatrixserverlib/spec"
) )
func queryUserIDForSender(senderID spec.SenderID) (*spec.UserID, error) {
if senderID == "" {
return nil, nil
}
return spec.NewUserID(string(senderID), true)
}
const testSenderID = "testSenderID"
const testUserID = "@test:localhost"
type EventFieldsToVerify struct {
EventID string
Type string
OriginServerTS spec.Timestamp
StateKey *string
Content spec.RawJSON
Unsigned spec.RawJSON
Sender string
Depth int64
PrevEvents []string
AuthEvents []string
}
func verifyEventFields(t *testing.T, got EventFieldsToVerify, want EventFieldsToVerify) {
if got.EventID != want.EventID {
t.Errorf("ClientEvent.EventID: wanted %s, got %s", want.EventID, got.EventID)
}
if got.OriginServerTS != want.OriginServerTS {
t.Errorf("ClientEvent.OriginServerTS: wanted %d, got %d", want.OriginServerTS, got.OriginServerTS)
}
if got.StateKey == nil && want.StateKey != nil {
t.Errorf("ClientEvent.StateKey: no state key present when one was wanted: %s", *want.StateKey)
}
if got.StateKey != nil && want.StateKey == nil {
t.Errorf("ClientEvent.StateKey: state key present when one was not wanted: %s", *got.StateKey)
}
if got.StateKey != nil && want.StateKey != nil && *got.StateKey != *want.StateKey {
t.Errorf("ClientEvent.StateKey: wanted %s, got %s", *want.StateKey, *got.StateKey)
}
if got.Type != want.Type {
t.Errorf("ClientEvent.Type: wanted %s, got %s", want.Type, got.Type)
}
if !bytes.Equal(got.Content, want.Content) {
t.Errorf("ClientEvent.Content: wanted %s, got %s", string(want.Content), string(got.Content))
}
if !bytes.Equal(got.Unsigned, want.Unsigned) {
t.Errorf("ClientEvent.Unsigned: wanted %s, got %s", string(want.Unsigned), string(got.Unsigned))
}
if got.Sender != want.Sender {
t.Errorf("ClientEvent.Sender: wanted %s, got %s", want.Sender, got.Sender)
}
if got.Depth != want.Depth {
t.Errorf("ClientEvent.Depth: wanted %d, got %d", want.Depth, got.Depth)
}
if !reflect.DeepEqual(got.PrevEvents, want.PrevEvents) {
t.Errorf("ClientEvent.PrevEvents: wanted %v, got %v", want.PrevEvents, got.PrevEvents)
}
if !reflect.DeepEqual(got.AuthEvents, want.AuthEvents) {
t.Errorf("ClientEvent.AuthEvents: wanted %v, got %v", want.AuthEvents, got.AuthEvents)
}
}
func TestToClientEvent(t *testing.T) { // nolint: gocyclo func TestToClientEvent(t *testing.T) { // nolint: gocyclo
ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionV1).NewEventFromTrustedJSON([]byte(`{ ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionV1).NewEventFromTrustedJSON([]byte(`{
"type": "m.room.name", "type": "m.room.name",
@ -49,28 +114,33 @@ func TestToClientEvent(t *testing.T) { // nolint: gocyclo
t.Fatalf("failed to create userID: %s", err) t.Fatalf("failed to create userID: %s", err)
} }
sk := "" sk := ""
ce := ToClientEvent(ev, FormatAll, *userID, &sk) ce, err := ToClientEvent(ev, FormatAll, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
if ce.EventID != ev.EventID() { return queryUserIDForSender(senderID)
t.Errorf("ClientEvent.EventID: wanted %s, got %s", ev.EventID(), ce.EventID) })
} if err != nil {
if ce.OriginServerTS != ev.OriginServerTS() { t.Fatalf("failed to create ClientEvent: %s", err)
t.Errorf("ClientEvent.OriginServerTS: wanted %d, got %d", ev.OriginServerTS(), ce.OriginServerTS)
}
if ce.StateKey == nil || *ce.StateKey != "" {
t.Errorf("ClientEvent.StateKey: wanted '', got %v", ce.StateKey)
}
if ce.Type != ev.Type() {
t.Errorf("ClientEvent.Type: wanted %s, got %s", ev.Type(), ce.Type)
}
if !bytes.Equal(ce.Content, ev.Content()) {
t.Errorf("ClientEvent.Content: wanted %s, got %s", string(ev.Content()), string(ce.Content))
}
if !bytes.Equal(ce.Unsigned, ev.Unsigned()) {
t.Errorf("ClientEvent.Unsigned: wanted %s, got %s", string(ev.Unsigned()), string(ce.Unsigned))
}
if ce.Sender != userID.String() {
t.Errorf("ClientEvent.Sender: wanted %s, got %s", userID.String(), ce.Sender)
} }
verifyEventFields(t,
EventFieldsToVerify{
EventID: ce.EventID,
Type: ce.Type,
OriginServerTS: ce.OriginServerTS,
StateKey: ce.StateKey,
Content: ce.Content,
Unsigned: ce.Unsigned,
Sender: ce.Sender,
},
EventFieldsToVerify{
EventID: ev.EventID(),
Type: ev.Type(),
OriginServerTS: ev.OriginServerTS(),
StateKey: &sk,
Content: ev.Content(),
Unsigned: ev.Unsigned(),
Sender: userID.String(),
})
j, err := json.Marshal(ce) j, err := json.Marshal(ce)
if err != nil { if err != nil {
t.Fatalf("failed to Marshal ClientEvent: %s", err) t.Fatalf("failed to Marshal ClientEvent: %s", err)
@ -104,13 +174,388 @@ func TestToClientFormatSync(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to create Event: %s", err) t.Fatalf("failed to create Event: %s", err)
} }
ce, err := ToClientEvent(ev, FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return queryUserIDForSender(senderID)
})
if err != nil {
t.Fatalf("failed to create ClientEvent: %s", err)
}
if ce.RoomID != "" {
t.Errorf("ClientEvent.RoomID: wanted '', got %s", ce.RoomID)
}
}
func TestToClientEventFormatSyncFederation(t *testing.T) { // nolint: gocyclo
ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionV10).NewEventFromTrustedJSON([]byte(`{
"type": "m.room.name",
"state_key": "",
"event_id": "$test:localhost",
"room_id": "!test:localhost",
"sender": "@test:localhost",
"content": {
"name": "Hello World"
},
"origin_server_ts": 123456,
"unsigned": {
"prev_content": {
"name": "Goodbye World"
}
},
"depth": 8,
"prev_events": [
"$f597Tp0Mm1PPxEgiprzJc2cZAjVhxCxACOGuwJb33Oo"
],
"auth_events": [
"$Bj0ZGgX6VTqAQdqKH4ZG3l6rlbxY3rZlC5D3MeuK1OQ",
"$QsMs6A1PUVUhgSvmHBfpqEYJPgv4DXt96r8P2AK7iXQ",
"$tBteKtlnFiwlmPJsv0wkKTMEuUVWpQH89H7Xskxve1Q"
]
}`), false)
if err != nil {
t.Fatalf("failed to create Event: %s", err)
}
userID, err := spec.NewUserID("@test:localhost", true) userID, err := spec.NewUserID("@test:localhost", true)
if err != nil { if err != nil {
t.Fatalf("failed to create userID: %s", err) t.Fatalf("failed to create userID: %s", err)
} }
sk := "" sk := ""
ce := ToClientEvent(ev, FormatSync, *userID, &sk) ce, err := ToClientEvent(ev, FormatSyncFederation, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
if ce.RoomID != "" { return queryUserIDForSender(senderID)
t.Errorf("ClientEvent.RoomID: wanted '', got %s", ce.RoomID) })
if err != nil {
t.Fatalf("failed to create ClientEvent: %s", err)
} }
verifyEventFields(t,
EventFieldsToVerify{
EventID: ce.EventID,
Type: ce.Type,
OriginServerTS: ce.OriginServerTS,
StateKey: ce.StateKey,
Content: ce.Content,
Unsigned: ce.Unsigned,
Sender: ce.Sender,
Depth: ce.Depth,
PrevEvents: ce.PrevEvents,
AuthEvents: ce.AuthEvents,
},
EventFieldsToVerify{
EventID: ev.EventID(),
Type: ev.Type(),
OriginServerTS: ev.OriginServerTS(),
StateKey: &sk,
Content: ev.Content(),
Unsigned: ev.Unsigned(),
Sender: userID.String(),
Depth: ev.Depth(),
PrevEvents: ev.PrevEventIDs(),
AuthEvents: ev.AuthEventIDs(),
})
}
func userIDForSender(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
if senderID == "unknownSenderID" {
return nil, fmt.Errorf("Cannot find userID")
}
return spec.NewUserID(testUserID, true)
}
func TestToClientEventsFormatSyncFederation(t *testing.T) { // nolint: gocyclo
ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionPseudoIDs).NewEventFromTrustedJSON([]byte(`{
"type": "m.room.name",
"state_key": "testSenderID",
"event_id": "$test:localhost",
"room_id": "!test:localhost",
"sender": "testSenderID",
"content": {
"name": "Hello World"
},
"origin_server_ts": 123456,
"unsigned": {
"prev_content": {
"name": "Goodbye World"
}
},
"depth": 8,
"prev_events": [
"$f597Tp0Mm1PPxEgiprzJc2cZAjVhxCxACOGuwJb33Oo"
],
"auth_events": [
"$Bj0ZGgX6VTqAQdqKH4ZG3l6rlbxY3rZlC5D3MeuK1OQ",
"$QsMs6A1PUVUhgSvmHBfpqEYJPgv4DXt96r8P2AK7iXQ",
"$tBteKtlnFiwlmPJsv0wkKTMEuUVWpQH89H7Xskxve1Q"
]
}`), false)
if err != nil {
t.Fatalf("failed to create Event: %s", err)
}
ev2, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionPseudoIDs).NewEventFromTrustedJSON([]byte(`{
"type": "m.room.name",
"state_key": "testSenderID",
"event_id": "$test2:localhost",
"room_id": "!test:localhost",
"sender": "testSenderID",
"content": {
"name": "Hello World 2"
},
"origin_server_ts": 1234567,
"unsigned": {
"prev_content": {
"name": "Goodbye World 2"
},
"prev_sender": "testSenderID"
},
"depth": 9,
"prev_events": [
"$f597Tp0Mm1PPxEgiprzJc2cZAjVhxCxACOGuwJb33Oo"
],
"auth_events": [
"$Bj0ZGgX6VTqAQdqKH4ZG3l6rlbxY3rZlC5D3MeuK1OQ",
"$QsMs6A1PUVUhgSvmHBfpqEYJPgv4DXt96r8P2AK7iXQ",
"$tBteKtlnFiwlmPJsv0wkKTMEuUVWpQH89H7Xskxve1Q"
]
}`), false)
if err != nil {
t.Fatalf("failed to create Event: %s", err)
}
clientEvents := ToClientEvents([]gomatrixserverlib.PDU{ev, ev2}, FormatSyncFederation, userIDForSender)
ce := clientEvents[0]
sk := testSenderID
verifyEventFields(t,
EventFieldsToVerify{
EventID: ce.EventID,
Type: ce.Type,
OriginServerTS: ce.OriginServerTS,
StateKey: ce.StateKey,
Content: ce.Content,
Unsigned: ce.Unsigned,
Sender: ce.Sender,
Depth: ce.Depth,
PrevEvents: ce.PrevEvents,
AuthEvents: ce.AuthEvents,
},
EventFieldsToVerify{
EventID: ev.EventID(),
Type: ev.Type(),
OriginServerTS: ev.OriginServerTS(),
StateKey: &sk,
Content: ev.Content(),
Unsigned: ev.Unsigned(),
Sender: testSenderID,
Depth: ev.Depth(),
PrevEvents: ev.PrevEventIDs(),
AuthEvents: ev.AuthEventIDs(),
})
ce2 := clientEvents[1]
verifyEventFields(t,
EventFieldsToVerify{
EventID: ce2.EventID,
Type: ce2.Type,
OriginServerTS: ce2.OriginServerTS,
StateKey: ce2.StateKey,
Content: ce2.Content,
Unsigned: ce2.Unsigned,
Sender: ce2.Sender,
Depth: ce2.Depth,
PrevEvents: ce2.PrevEvents,
AuthEvents: ce2.AuthEvents,
},
EventFieldsToVerify{
EventID: ev2.EventID(),
Type: ev2.Type(),
OriginServerTS: ev2.OriginServerTS(),
StateKey: &sk,
Content: ev2.Content(),
Unsigned: ev2.Unsigned(),
Sender: testSenderID,
Depth: ev2.Depth(),
PrevEvents: ev2.PrevEventIDs(),
AuthEvents: ev2.AuthEventIDs(),
})
}
func TestToClientEventsFormatSync(t *testing.T) { // nolint: gocyclo
ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionPseudoIDs).NewEventFromTrustedJSON([]byte(`{
"type": "m.room.name",
"state_key": "testSenderID",
"event_id": "$test:localhost",
"room_id": "!test:localhost",
"sender": "testSenderID",
"content": {
"name": "Hello World"
},
"origin_server_ts": 123456,
"unsigned": {
"prev_content": {
"name": "Goodbye World"
}
}
}`), false)
if err != nil {
t.Fatalf("failed to create Event: %s", err)
}
ev2, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionPseudoIDs).NewEventFromTrustedJSON([]byte(`{
"type": "m.room.name",
"state_key": "testSenderID",
"event_id": "$test2:localhost",
"room_id": "!test:localhost",
"sender": "testSenderID",
"content": {
"name": "Hello World 2"
},
"origin_server_ts": 1234567,
"unsigned": {
"prev_content": {
"name": "Goodbye World 2"
},
"prev_sender": "testSenderID"
},
"depth": 9
}`), false)
if err != nil {
t.Fatalf("failed to create Event: %s", err)
}
clientEvents := ToClientEvents([]gomatrixserverlib.PDU{ev, ev2}, FormatSync, userIDForSender)
ce := clientEvents[0]
sk := testUserID
verifyEventFields(t,
EventFieldsToVerify{
EventID: ce.EventID,
Type: ce.Type,
OriginServerTS: ce.OriginServerTS,
StateKey: ce.StateKey,
Content: ce.Content,
Unsigned: ce.Unsigned,
Sender: ce.Sender,
},
EventFieldsToVerify{
EventID: ev.EventID(),
Type: ev.Type(),
OriginServerTS: ev.OriginServerTS(),
StateKey: &sk,
Content: ev.Content(),
Unsigned: ev.Unsigned(),
Sender: testUserID,
})
var prev PrevEventRef
prev.PrevContent = []byte(`{"name": "Goodbye World 2"}`)
prev.PrevSenderID = testUserID
expectedUnsigned, _ := json.Marshal(prev)
ce2 := clientEvents[1]
verifyEventFields(t,
EventFieldsToVerify{
EventID: ce2.EventID,
Type: ce2.Type,
OriginServerTS: ce2.OriginServerTS,
StateKey: ce2.StateKey,
Content: ce2.Content,
Unsigned: ce2.Unsigned,
Sender: ce2.Sender,
},
EventFieldsToVerify{
EventID: ev2.EventID(),
Type: ev2.Type(),
OriginServerTS: ev2.OriginServerTS(),
StateKey: &sk,
Content: ev2.Content(),
Unsigned: expectedUnsigned,
Sender: testUserID,
})
}
func TestToClientEventsFormatSyncUnknownPrevSender(t *testing.T) { // nolint: gocyclo
ev, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionPseudoIDs).NewEventFromTrustedJSON([]byte(`{
"type": "m.room.name",
"state_key": "testSenderID",
"event_id": "$test:localhost",
"room_id": "!test:localhost",
"sender": "testSenderID",
"content": {
"name": "Hello World"
},
"origin_server_ts": 123456,
"unsigned": {
"prev_content": {
"name": "Goodbye World"
}
}
}`), false)
if err != nil {
t.Fatalf("failed to create Event: %s", err)
}
ev2, err := gomatrixserverlib.MustGetRoomVersion(gomatrixserverlib.RoomVersionPseudoIDs).NewEventFromTrustedJSON([]byte(`{
"type": "m.room.name",
"state_key": "testSenderID",
"event_id": "$test2:localhost",
"room_id": "!test:localhost",
"sender": "testSenderID",
"content": {
"name": "Hello World 2"
},
"origin_server_ts": 1234567,
"unsigned": {
"prev_content": {
"name": "Goodbye World 2"
},
"prev_sender": "unknownSenderID"
},
"depth": 9
}`), false)
if err != nil {
t.Fatalf("failed to create Event: %s", err)
}
clientEvents := ToClientEvents([]gomatrixserverlib.PDU{ev, ev2}, FormatSync, userIDForSender)
ce := clientEvents[0]
sk := testUserID
verifyEventFields(t,
EventFieldsToVerify{
EventID: ce.EventID,
Type: ce.Type,
OriginServerTS: ce.OriginServerTS,
StateKey: ce.StateKey,
Content: ce.Content,
Unsigned: ce.Unsigned,
Sender: ce.Sender,
},
EventFieldsToVerify{
EventID: ev.EventID(),
Type: ev.Type(),
OriginServerTS: ev.OriginServerTS(),
StateKey: &sk,
Content: ev.Content(),
Unsigned: ev.Unsigned(),
Sender: testUserID,
})
var prev PrevEventRef
prev.PrevContent = []byte(`{"name": "Goodbye World 2"}`)
prev.PrevSenderID = "unknownSenderID"
expectedUnsigned, _ := json.Marshal(prev)
ce2 := clientEvents[1]
verifyEventFields(t,
EventFieldsToVerify{
EventID: ce2.EventID,
Type: ce2.Type,
OriginServerTS: ce2.OriginServerTS,
StateKey: ce2.StateKey,
Content: ce2.Content,
Unsigned: ce2.Unsigned,
Sender: ce2.Sender,
},
EventFieldsToVerify{
EventID: ev2.EventID(),
Type: ev2.Type(),
OriginServerTS: ev2.OriginServerTS(),
StateKey: &sk,
Content: ev2.Content(),
Unsigned: expectedUnsigned,
Sender: testUserID,
})
} }

View file

@ -78,9 +78,14 @@ type RoomEventFilter struct {
ContainsURL *bool `json:"contains_url,omitempty"` ContainsURL *bool `json:"contains_url,omitempty"`
} }
const (
EventFormatClient = "client"
EventFormatFederation = "federation"
)
// Validate checks if the filter contains valid property values // Validate checks if the filter contains valid property values
func (filter *Filter) Validate() error { func (filter *Filter) Validate() error {
if filter.EventFormat != "" && filter.EventFormat != "client" && filter.EventFormat != "federation" { if filter.EventFormat != "" && filter.EventFormat != EventFormatClient && filter.EventFormat != EventFormatFederation {
return errors.New("Bad event_format value. Must be one of [\"client\", \"federation\"]") return errors.New("Bad event_format value. Must be one of [\"client\", \"federation\"]")
} }
return nil return nil

View file

@ -15,6 +15,7 @@
package types package types
import ( import (
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -339,13 +340,6 @@ func NewStreamTokenFromString(tok string) (token StreamingToken, err error) {
return token, nil return token, nil
} }
// PrevEventRef represents a reference to a previous event in a state event upgrade
type PrevEventRef struct {
PrevContent json.RawMessage `json:"prev_content"`
ReplacesState string `json:"replaces_state"`
PrevSenderID string `json:"prev_sender"`
}
type DeviceLists struct { type DeviceLists struct {
Changed []string `json:"changed,omitempty"` Changed []string `json:"changed,omitempty"`
Left []string `json:"left,omitempty"` Left []string `json:"left,omitempty"`
@ -539,7 +533,7 @@ type InviteResponse struct {
} }
// NewInviteResponse creates an empty response with initialised arrays. // NewInviteResponse creates an empty response with initialised arrays.
func NewInviteResponse(event *types.HeaderedEvent, userID spec.UserID, stateKey *string) *InviteResponse { func NewInviteResponse(ctx context.Context, rsAPI api.QuerySenderIDAPI, event *types.HeaderedEvent, eventFormat synctypes.ClientEventFormat) (*InviteResponse, error) {
res := InviteResponse{} res := InviteResponse{}
res.InviteState.Events = []json.RawMessage{} res.InviteState.Events = []json.RawMessage{}
@ -547,18 +541,42 @@ func NewInviteResponse(event *types.HeaderedEvent, userID spec.UserID, stateKey
// If there is then unmarshal it into the response. This will contain the // If there is then unmarshal it into the response. This will contain the
// partial room state such as join rules, room name etc. // partial room state such as join rules, room name etc.
if inviteRoomState := gjson.GetBytes(event.Unsigned(), "invite_room_state"); inviteRoomState.Exists() { if inviteRoomState := gjson.GetBytes(event.Unsigned(), "invite_room_state"); inviteRoomState.Exists() {
_ = json.Unmarshal([]byte(inviteRoomState.Raw), &res.InviteState.Events) if event.Version() == gomatrixserverlib.RoomVersionPseudoIDs && eventFormat != synctypes.FormatSyncFederation {
updatedInvite, err := synctypes.GetUpdatedInviteRoomState(func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
}, inviteRoomState, event.PDU, event.RoomID(), eventFormat)
if err != nil {
return nil, err
}
_ = json.Unmarshal(updatedInvite, &res.InviteState.Events)
} else {
_ = json.Unmarshal([]byte(inviteRoomState.Raw), &res.InviteState.Events)
}
}
// Clear unsigned so it doesn't have pseudoIDs converted during ToClientEvent
eventNoUnsigned, err := event.SetUnsigned(nil)
if err != nil {
return nil, err
} }
// Then we'll see if we can create a partial of the invite event itself. // 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. // This is needed for clients to work out *who* sent the invite.
inviteEvent := synctypes.ToClientEvent(event.PDU, synctypes.FormatSync, userID, stateKey) inviteEvent, err := synctypes.ToClientEvent(eventNoUnsigned, eventFormat, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
})
if err != nil {
return nil, err
}
// Ensure unsigned field is empty so it isn't marshalled into the final JSON
inviteEvent.Unsigned = nil inviteEvent.Unsigned = nil
if ev, err := json.Marshal(inviteEvent); err == nil {
if ev, err := json.Marshal(*inviteEvent); err == nil {
res.InviteState.Events = append(res.InviteState.Events, ev) res.InviteState.Events = append(res.InviteState.Events, ev)
} }
return &res return &res, nil
} }
// LeaveResponse represents a /sync response for a room which is under the 'leave' key. // LeaveResponse represents a /sync response for a room which is under the 'leave' key.

View file

@ -1,6 +1,7 @@
package types package types
import ( import (
"context"
"encoding/json" "encoding/json"
"reflect" "reflect"
"testing" "testing"
@ -11,8 +12,19 @@ import (
"github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/gomatrixserverlib/spec"
) )
func UserIDForSender(roomID string, senderID string) (*spec.UserID, error) { type FakeRoomserverAPI struct{}
return spec.NewUserID(senderID, true)
func (f *FakeRoomserverAPI) QueryUserIDForSender(ctx context.Context, roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
if senderID == "" {
return nil, nil
}
return spec.NewUserID(string(senderID), true)
}
func (f *FakeRoomserverAPI) QuerySenderIDForUser(ctx context.Context, roomID spec.RoomID, userID spec.UserID) (*spec.SenderID, error) {
sender := spec.SenderID(userID.String())
return &sender, nil
} }
func TestSyncTokens(t *testing.T) { func TestSyncTokens(t *testing.T) {
@ -61,25 +73,18 @@ func TestNewInviteResponse(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
sender, err := spec.NewUserID("@neilalexander:matrix.org", true) rsAPI := FakeRoomserverAPI{}
res, err := NewInviteResponse(context.Background(), &rsAPI, &types.HeaderedEvent{PDU: ev}, synctypes.FormatSync)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
skUserID, err := spec.NewUserID("@neilalexander:dendrite.neilalexander.dev", true)
if err != nil {
t.Fatal(err)
}
skString := skUserID.String()
sk := &skString
res := NewInviteResponse(&types.HeaderedEvent{PDU: ev}, *sender, sk)
j, err := json.Marshal(res) j, err := json.Marshal(res)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if string(j) != expected { if string(j) != expected {
t.Fatalf("Invite response didn't contain correct info") t.Fatalf("Invite response didn't contain correct info, \nexpected: %s \ngot: %s", expected, string(j))
} }
} }

View file

@ -783,4 +783,16 @@ Invited user can reject invite for empty room
Invited user can reject local invite after originator leaves Invited user can reject local invite after originator leaves
Guest users can join guest_access rooms Guest users can join guest_access rooms
Forgotten room messages cannot be paginated Forgotten room messages cannot be paginated
Local device key changes get to remote servers with correct prev_id Local device key changes get to remote servers with correct prev_id
HS provides query metadata
HS can provide query metadata on a single protocol
Invites over federation are correctly pushed
Invites over federation are correctly pushed with name
User can create and send/receive messages in a room with version 11
local user can join room with version 11
User can invite local user to room with version 11
remote user can join room with version 11
User can invite remote user to room with version 11
Remote user can backfill in a room with version 11
Can reject invites over federation for rooms with version 11
Can receive redactions from regular users over federation in room version 11

View file

@ -92,30 +92,43 @@ func (s *OutputRoomEventConsumer) Start() error {
func (s *OutputRoomEventConsumer) onMessage(ctx context.Context, msgs []*nats.Msg) bool { func (s *OutputRoomEventConsumer) onMessage(ctx context.Context, msgs []*nats.Msg) bool {
msg := msgs[0] // Guaranteed to exist if onMessage is called msg := msgs[0] // Guaranteed to exist if onMessage is called
// Only handle events we care about // Only handle events we care about
if rsapi.OutputType(msg.Header.Get(jetstream.RoomEventType)) != rsapi.OutputTypeNewRoomEvent {
return true var event *rstypes.HeaderedEvent
} var isNewRoomEvent bool
var output rsapi.OutputEvent switch rsapi.OutputType(msg.Header.Get(jetstream.RoomEventType)) {
if err := json.Unmarshal(msg.Data, &output); err != nil { case rsapi.OutputTypeNewRoomEvent:
// If the message was invalid, log it and move on to the next message in the stream isNewRoomEvent = true
log.WithError(err).Errorf("roomserver output log: message parse failure") fallthrough
return true case rsapi.OutputTypeNewInviteEvent:
} var output rsapi.OutputEvent
event := output.NewRoomEvent.Event if err := json.Unmarshal(msg.Data, &output); err != nil {
if event == nil { // If the message was invalid, log it and move on to the next message in the stream
log.Errorf("userapi consumer: expected event") log.WithError(err).Errorf("roomserver output log: message parse failure")
return true
}
if isNewRoomEvent {
event = output.NewRoomEvent.Event
} else {
event = output.NewInviteEvent.Event
}
if event == nil {
log.Errorf("userapi consumer: expected event")
return true
}
log.WithFields(log.Fields{
"event_id": event.EventID(),
"event_type": event.Type(),
}).Tracef("Received message from roomserver: %#v", output)
default:
return true return true
} }
if s.cfg.Matrix.ReportStats.Enabled { if s.cfg.Matrix.ReportStats.Enabled {
go s.storeMessageStats(ctx, event.Type(), string(event.SenderID()), event.RoomID()) go s.storeMessageStats(ctx, event.Type(), string(event.SenderID()), event.RoomID().String())
} }
log.WithFields(log.Fields{
"event_id": event.EventID(),
"event_type": event.Type(),
}).Tracef("Received message from roomserver: %#v", output)
metadata, err := msg.Metadata() metadata, err := msg.Metadata()
if err != nil { if err != nil {
return true return true
@ -253,8 +266,8 @@ func (s *OutputRoomEventConsumer) updateMDirect(ctx context.Context, oldRoomID,
directChats := gjson.ParseBytes(directChatsRaw) directChats := gjson.ParseBytes(directChatsRaw)
newDirectChats := make(map[string][]string) newDirectChats := make(map[string][]string)
// iterate over all userID -> roomIDs // iterate over all userID -> roomIDs
var found bool
directChats.ForEach(func(userID, roomIDs gjson.Result) bool { directChats.ForEach(func(userID, roomIDs gjson.Result) bool {
var found bool
for _, roomID := range roomIDs.Array() { for _, roomID := range roomIDs.Array() {
newDirectChats[userID.Str] = append(newDirectChats[userID.Str], roomID.Str) newDirectChats[userID.Str] = append(newDirectChats[userID.Str], roomID.Str)
// add the new roomID to m.direct // add the new roomID to m.direct
@ -263,22 +276,21 @@ func (s *OutputRoomEventConsumer) updateMDirect(ctx context.Context, oldRoomID,
newDirectChats[userID.Str] = append(newDirectChats[userID.Str], newRoomID) newDirectChats[userID.Str] = append(newDirectChats[userID.Str], newRoomID)
} }
} }
// Only hit the database if we found the old room as a DM for this user
if found {
var data []byte
data, err = json.Marshal(newDirectChats)
if err != nil {
return true
}
if err = s.db.SaveAccountData(ctx, localpart, serverName, "", "m.direct", data); err != nil {
return true
}
}
return true return true
}) })
if err != nil {
return fmt.Errorf("failed to update m.direct state") // Only hit the database if we found the old room as a DM for this user
if found {
var data []byte
data, err = json.Marshal(newDirectChats)
if err != nil {
return err
}
if err = s.db.SaveAccountData(ctx, localpart, serverName, "", "m.direct", data); err != nil {
return fmt.Errorf("failed to update m.direct state: %w", err)
}
} }
return nil return nil
} }
@ -294,36 +306,21 @@ func (s *OutputRoomEventConsumer) copyTags(ctx context.Context, oldRoomID, newRo
} }
func (s *OutputRoomEventConsumer) processMessage(ctx context.Context, event *rstypes.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()) members, roomSize, err := s.localRoomMembers(ctx, event.RoomID().String())
if err != nil { if err != nil {
return fmt.Errorf("s.localRoomMembers: %w", err) return fmt.Errorf("s.localRoomMembers: %w", err)
} }
switch { switch {
case event.Type() == spec.MRoomMember: case event.Type() == spec.MRoomMember:
sender := spec.UserID{} cevent, clientEvErr := synctypes.ToClientEvent(event, synctypes.FormatAll, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
validRoomID, roomErr := spec.NewRoomID(event.RoomID()) return s.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
if roomErr != nil { })
return roomErr if clientEvErr != nil {
return clientEvErr
} }
userID, queryErr := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, event.SenderID())
if queryErr == nil && userID != nil {
sender = *userID
}
sk := event.StateKey()
if sk != nil && *sk != "" {
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)
var member *localMembership var member *localMembership
member, err = newLocalMembership(&cevent) member, err = newLocalMembership(cevent)
if err != nil { if err != nil {
return fmt.Errorf("newLocalMembership: %w", err) return fmt.Errorf("newLocalMembership: %w", err)
} }
@ -334,7 +331,7 @@ func (s *OutputRoomEventConsumer) processMessage(ctx context.Context, event *rst
} }
case event.Type() == "m.room.tombstone" && event.StateKeyEquals(""): case event.Type() == "m.room.tombstone" && event.StateKeyEquals(""):
// Handle room upgrades // Handle room upgrades
oldRoomID := event.RoomID() oldRoomID := event.RoomID().String()
newRoomID := gjson.GetBytes(event.Content(), "replacement_room").Str newRoomID := gjson.GetBytes(event.Content(), "replacement_room").Str
if err = s.handleRoomUpgrade(ctx, oldRoomID, newRoomID, members, roomSize); err != nil { if err = s.handleRoomUpgrade(ctx, oldRoomID, newRoomID, members, roomSize); err != nil {
// while inconvenient, this shouldn't stop us from sending push notifications // while inconvenient, this shouldn't stop us from sending push notifications
@ -351,7 +348,7 @@ func (s *OutputRoomEventConsumer) processMessage(ctx context.Context, event *rst
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"event_id": event.EventID(), "event_id": event.EventID(),
"room_id": event.RoomID(), "room_id": event.RoomID().String(),
"num_members": len(members), "num_members": len(members),
"room_size": roomSize, "room_size": roomSize,
}).Tracef("Notifying members") }).Tracef("Notifying members")
@ -463,8 +460,21 @@ func (s *OutputRoomEventConsumer) roomName(ctx context.Context, event *rstypes.H
} }
} }
// Special case for invites, as we don't store any "current state" for these events,
// we need to make sure that, if present, the m.room.name is sent as well.
if event.Type() == spec.MRoomMember &&
gjson.GetBytes(event.Content(), "membership").Str == "invite" {
invState := gjson.GetBytes(event.JSON(), "unsigned.invite_room_state")
for _, ev := range invState.Array() {
if ev.Get("type").Str == spec.MRoomName {
name := ev.Get("content.name").Str
return name, nil
}
}
}
req := &rsapi.QueryCurrentStateRequest{ req := &rsapi.QueryCurrentStateRequest{
RoomID: event.RoomID(), RoomID: event.RoomID().String(),
StateTuples: []gomatrixserverlib.StateKeyTuple{roomNameTuple, canonicalAliasTuple}, StateTuples: []gomatrixserverlib.StateKeyTuple{roomNameTuple, canonicalAliasTuple},
} }
var res rsapi.QueryCurrentStateResponse var res rsapi.QueryCurrentStateResponse
@ -532,7 +542,7 @@ func (s *OutputRoomEventConsumer) notifyLocal(ctx context.Context, event *rstype
if a != pushrules.NotifyAction && a != pushrules.CoalesceAction { if a != pushrules.NotifyAction && a != pushrules.CoalesceAction {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"event_id": event.EventID(), "event_id": event.EventID(),
"room_id": event.RoomID(), "room_id": event.RoomID().String(),
"localpart": mem.Localpart, "localpart": mem.Localpart,
}).Tracef("Push rule evaluation rejected the event") }).Tracef("Push rule evaluation rejected the event")
return nil return nil
@ -542,44 +552,32 @@ func (s *OutputRoomEventConsumer) notifyLocal(ctx context.Context, event *rstype
if err != nil { if err != nil {
return fmt.Errorf("s.localPushDevices: %w", err) return fmt.Errorf("s.localPushDevices: %w", err)
} }
clientEvent, err := synctypes.ToClientEvent(event, synctypes.FormatSync, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
sender := spec.UserID{} return s.rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
validRoomID, err := spec.NewRoomID(event.RoomID()) })
if err != nil { if err != nil {
return err return err
} }
userID, err := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, event.SenderID())
if err == nil && userID != nil {
sender = *userID
}
sk := event.StateKey()
if sk != nil && *sk != "" {
skUserID, queryErr := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, spec.SenderID(*event.StateKey()))
if queryErr == nil && skUserID != nil {
skString := skUserID.String()
sk = &skString
}
}
n := &api.Notification{ n := &api.Notification{
Actions: actions, Actions: actions,
// UNSPEC: the spec doesn't say this is a ClientEvent, but the // UNSPEC: the spec doesn't say this is a ClientEvent, but the
// fields seem to match. room_id should be missing, which // fields seem to match. room_id should be missing, which
// matches the behaviour of FormatSync. // matches the behaviour of FormatSync.
Event: synctypes.ToClientEvent(event, synctypes.FormatSync, sender, sk), Event: *clientEvent,
// TODO: this is per-device, but it's not part of the primary // TODO: this is per-device, but it's not part of the primary
// key. So inserting one notification per profile tag doesn't // key. So inserting one notification per profile tag doesn't
// make sense. What is this supposed to be? Sytests require it // make sense. What is this supposed to be? Sytests require it
// to "work", but they only use a single device. // to "work", but they only use a single device.
ProfileTag: profileTag, ProfileTag: profileTag,
RoomID: event.RoomID(), RoomID: event.RoomID().String(),
TS: spec.AsTimestamp(time.Now()), TS: spec.AsTimestamp(time.Now()),
} }
if err = s.db.InsertNotification(ctx, mem.Localpart, mem.Domain, event.EventID(), streamPos, tweaks, n); err != nil { if err = s.db.InsertNotification(ctx, mem.Localpart, mem.Domain, event.EventID(), streamPos, tweaks, n); err != nil {
return fmt.Errorf("s.db.InsertNotification: %w", err) return fmt.Errorf("s.db.InsertNotification: %w", err)
} }
if err = s.syncProducer.GetAndSendNotificationData(ctx, mem.UserID, event.RoomID()); err != nil { if err = s.syncProducer.GetAndSendNotificationData(ctx, mem.UserID, event.RoomID().String()); err != nil {
return fmt.Errorf("s.syncProducer.GetAndSendNotificationData: %w", err) return fmt.Errorf("s.syncProducer.GetAndSendNotificationData: %w", err)
} }
@ -591,7 +589,7 @@ func (s *OutputRoomEventConsumer) notifyLocal(ctx context.Context, event *rstype
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"event_id": event.EventID(), "event_id": event.EventID(),
"room_id": event.RoomID(), "room_id": event.RoomID().String(),
"localpart": mem.Localpart, "localpart": mem.Localpart,
"num_urls": len(devicesByURLAndFormat), "num_urls": len(devicesByURLAndFormat),
"num_unread": userNumUnreadNotifs, "num_unread": userNumUnreadNotifs,
@ -648,11 +646,7 @@ func (s *OutputRoomEventConsumer) notifyLocal(ctx context.Context, event *rstype
// user. Returns actions (including dont_notify). // user. Returns actions (including dont_notify).
func (s *OutputRoomEventConsumer) evaluatePushRules(ctx context.Context, event *rstypes.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) {
user := "" user := ""
validRoomID, err := spec.NewRoomID(event.RoomID()) sender, err := s.rsAPI.QueryUserIDForSender(ctx, event.RoomID(), event.SenderID())
if err != nil {
return nil, err
}
sender, err := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, event.SenderID())
if err == nil { if err == nil {
user = sender.String() user = sender.String()
} }
@ -686,7 +680,7 @@ func (s *OutputRoomEventConsumer) evaluatePushRules(ctx context.Context, event *
ctx: ctx, ctx: ctx,
rsAPI: s.rsAPI, rsAPI: s.rsAPI,
mem: mem, mem: mem,
roomID: event.RoomID(), roomID: event.RoomID().String(),
roomSize: roomSize, roomSize: roomSize,
} }
eval := pushrules.NewRuleSetEvaluator(ec, &ruleSets.Global) eval := pushrules.NewRuleSetEvaluator(ec, &ruleSets.Global)
@ -704,7 +698,7 @@ func (s *OutputRoomEventConsumer) evaluatePushRules(ctx context.Context, event *
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"event_id": event.EventID(), "event_id": event.EventID(),
"room_id": event.RoomID(), "room_id": event.RoomID().String(),
"localpart": mem.Localpart, "localpart": mem.Localpart,
"rule_id": rule.RuleID, "rule_id": rule.RuleID,
}).Trace("Matched a push rule") }).Trace("Matched a push rule")
@ -793,16 +787,12 @@ func (s *OutputRoomEventConsumer) notifyHTTP(ctx context.Context, event *rstypes
}, },
Devices: devices, Devices: devices,
EventID: event.EventID(), EventID: event.EventID(),
RoomID: event.RoomID(), RoomID: event.RoomID().String(),
}, },
} }
default: default:
validRoomID, err := spec.NewRoomID(event.RoomID()) sender, err := s.rsAPI.QueryUserIDForSender(ctx, event.RoomID(), event.SenderID())
if err != nil {
return nil, err
}
sender, err := s.rsAPI.QueryUserIDForSender(ctx, *validRoomID, event.SenderID())
if err != nil { if err != nil {
logger.WithError(err).Errorf("Failed to get userID for sender %s", event.SenderID()) logger.WithError(err).Errorf("Failed to get userID for sender %s", event.SenderID())
return nil, err return nil, err
@ -816,7 +806,7 @@ func (s *OutputRoomEventConsumer) notifyHTTP(ctx context.Context, event *rstypes
Devices: devices, Devices: devices,
EventID: event.EventID(), EventID: event.EventID(),
ID: event.EventID(), ID: event.EventID(),
RoomID: event.RoomID(), RoomID: event.RoomID().String(),
RoomName: roomName, RoomName: roomName,
Sender: sender.String(), Sender: sender.String(),
Type: event.Type(), Type: event.Type(),
@ -830,19 +820,13 @@ func (s *OutputRoomEventConsumer) notifyHTTP(ctx context.Context, event *rstypes
logger.WithError(err).Errorf("Failed to convert local user to userID %s", localpart) logger.WithError(err).Errorf("Failed to convert local user to userID %s", localpart)
return nil, err return nil, err
} }
roomID, err := spec.NewRoomID(event.RoomID()) localSender, err := s.rsAPI.QuerySenderIDForUser(ctx, event.RoomID(), *userID)
if err != nil { if err != nil {
logger.WithError(err).Errorf("event roomID is invalid %s", event.RoomID()) logger.WithError(err).Errorf("Failed to get local user senderID for room %s: %s", userID.String(), event.RoomID().String())
return nil, err
}
localSender, err := s.rsAPI.QuerySenderIDForUser(ctx, *roomID, *userID)
if err != nil {
logger.WithError(err).Errorf("Failed to get local user senderID for room %s: %s", userID.String(), event.RoomID())
return nil, err return nil, err
} else if localSender == nil { } else if localSender == nil {
logger.WithError(err).Errorf("Failed to get local user senderID for room %s: %s", userID.String(), event.RoomID()) logger.WithError(err).Errorf("Failed to get local user senderID for room %s: %s", userID.String(), event.RoomID().String())
return nil, fmt.Errorf("no sender ID for user %s in %s", userID.String(), roomID.String()) return nil, fmt.Errorf("no sender ID for user %s in %s", userID.String(), event.RoomID().String())
} }
if event.StateKey() != nil && *event.StateKey() == string(*localSender) { if event.StateKey() != nil && *event.StateKey() == string(*localSender) {
req.Notification.UserIsTarget = true req.Notification.UserIsTarget = true

View file

@ -563,12 +563,15 @@ func (a *UserInternalAPI) QueryAccountData(ctx context.Context, req *api.QueryAc
func (a *UserInternalAPI) QueryAccessToken(ctx context.Context, req *api.QueryAccessTokenRequest, res *api.QueryAccessTokenResponse) error { func (a *UserInternalAPI) QueryAccessToken(ctx context.Context, req *api.QueryAccessTokenRequest, res *api.QueryAccessTokenResponse) error {
if req.AppServiceUserID != "" { if req.AppServiceUserID != "" {
appServiceDevice, err := a.queryAppServiceToken(ctx, req.AccessToken, req.AppServiceUserID) appServiceDevice, err := a.queryAppServiceToken(ctx, req.AccessToken, req.AppServiceUserID)
if err != nil { if err != nil || appServiceDevice != nil {
res.Err = err.Error() if err != nil {
} res.Err = err.Error()
res.Device = appServiceDevice }
res.Device = appServiceDevice
return nil return nil
}
// If the provided token wasn't an as_token (both err and appServiceDevice are nil), continue with normal auth.
} }
device, err := a.DB.GetDeviceByAccessToken(ctx, req.AccessToken) device, err := a.DB.GetDeviceByAccessToken(ctx, req.AccessToken)
if err != nil { if err != nil {

View file

@ -23,6 +23,14 @@ import (
userUtil "github.com/matrix-org/dendrite/userapi/util" userUtil "github.com/matrix-org/dendrite/userapi/util"
) )
func queryUserIDForSender(senderID spec.SenderID) (*spec.UserID, error) {
if senderID == "" {
return nil, nil
}
return spec.NewUserID(string(senderID), true)
}
func TestNotifyUserCountsAsync(t *testing.T) { func TestNotifyUserCountsAsync(t *testing.T) {
alice := test.NewUser(t) alice := test.NewUser(t)
aliceLocalpart, serverName, err := gomatrixserverlib.SplitID('@', alice.ID) aliceLocalpart, serverName, err := gomatrixserverlib.SplitID('@', alice.ID)
@ -100,13 +108,14 @@ func TestNotifyUserCountsAsync(t *testing.T) {
} }
// Insert a dummy event // Insert a dummy event
sender, err := spec.NewUserID(alice.ID, true) ev, err := synctypes.ToClientEvent(dummyEvent, synctypes.FormatAll, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
return queryUserIDForSender(senderID)
})
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
sk := ""
if err := db.InsertNotification(ctx, aliceLocalpart, serverName, dummyEvent.EventID(), 0, nil, &api.Notification{ if err := db.InsertNotification(ctx, aliceLocalpart, serverName, dummyEvent.EventID(), 0, nil, &api.Notification{
Event: synctypes.ToClientEvent(dummyEvent, synctypes.FormatAll, *sender, &sk), Event: *ev,
}); err != nil { }); err != nil {
t.Error(err) t.Error(err)
} }