Skip to content

Commit

Permalink
Add dedicated federation.Event
Browse files Browse the repository at this point in the history
Fixes #381
  • Loading branch information
kegsay committed Oct 3, 2023
1 parent 81193ac commit d68b044
Show file tree
Hide file tree
Showing 11 changed files with 65 additions and 61 deletions.
3 changes: 3 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@ func (c *CSAPI) Unsafe_SendEventUnsyncedWithTxnID(t TestLike, roomID string, e b
if e.StateKey != nil {
paths = []string{"_matrix", "client", "v3", "rooms", roomID, "state", e.Type, *e.StateKey}
}
if e.Sender != "" {
t.Fatalf("Event.Sender must not be set, as this is set by the client in use (%s)", c.UserID)
}
res := c.MustDo(t, "PUT", paths, WithJSONBody(t, e.Content))
body := ParseJSON(t, res)
eventID := GetJSONFieldStr(t, body, "event_id")
Expand Down
18 changes: 0 additions & 18 deletions internal/b/blueprints.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,24 +97,6 @@ type Event struct {
Sender string
StateKey *string
Content map[string]interface{}

/* The following fields are ignored in blueprints as clients are unable to set them.
* They are used with federation.Server.
*/

Unsigned map[string]interface{}

// The events needed to authenticate this event.
// This can be either []EventReference for room v1/v2, or []string for room v3 onwards.
// If it is left at nil, MustCreateEvent will populate it automatically based on the room state.
AuthEvents interface{}

// The prev events of the event if we want to override or falsify them.
// If it is left at nil, MustCreateEvent will populate it automatically based on the forward extremities.
PrevEvents interface{}

// If this is a redaction, the event that it redacts
Redacts string
}

func MustValidate(bp Blueprint) Blueprint {
Expand Down
7 changes: 3 additions & 4 deletions internal/federation/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util"

"github.com/matrix-org/complement/internal/b"
"github.com/matrix-org/complement/internal/config"
"github.com/matrix-org/complement/internal/docker"
)
Expand Down Expand Up @@ -162,7 +161,7 @@ func (s *Server) MakeAliasMapping(aliasLocalpart, roomID string) string {

// MustMakeRoom will add a room to this server so it is accessible to other servers when prompted via federation.
// The `events` will be added to this room. Returns the created room.
func (s *Server) MustMakeRoom(t *testing.T, roomVer gomatrixserverlib.RoomVersion, events []b.Event) *ServerRoom {
func (s *Server) MustMakeRoom(t *testing.T, roomVer gomatrixserverlib.RoomVersion, events []Event) *ServerRoom {
if !s.listening {
s.t.Fatalf("MustMakeRoom() called before Listen() - this is not supported because Listen() chooses a high-numbered port and thus changes the server name and thus changes the room ID. Ensure you Listen() first!")
}
Expand Down Expand Up @@ -291,7 +290,7 @@ func (s *Server) DoFederationRequest(

// MustCreateEvent will create and sign a new latest event for the given room.
// It does not insert this event into the room however. See ServerRoom.AddEvent for that.
func (s *Server) MustCreateEvent(t *testing.T, room *ServerRoom, ev b.Event) gomatrixserverlib.PDU {
func (s *Server) MustCreateEvent(t *testing.T, room *ServerRoom, ev Event) gomatrixserverlib.PDU {
t.Helper()
content, err := json.Marshal(ev.Content)
if err != nil {
Expand Down Expand Up @@ -451,7 +450,7 @@ func (s *Server) MustLeaveRoom(t *testing.T, deployment *docker.Deployment, remo
}
} else {
// make the leave event
leaveEvent = s.MustCreateEvent(t, room, b.Event{
leaveEvent = s.MustCreateEvent(t, room, Event{
Type: "m.room.member",
StateKey: &userID,
Sender: userID,
Expand Down
22 changes: 20 additions & 2 deletions internal/federation/server_room.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@ import (
"github.com/matrix-org/complement/internal/b"
)

type Event struct {
Type string
Sender string
StateKey *string
Content map[string]interface{}

Unsigned map[string]interface{}
// The events needed to authenticate this event.
// This can be either []EventReference for room v1/v2, or []string for room v3 onwards.
// If it is left at nil, MustCreateEvent will populate it automatically based on the room state.
AuthEvents interface{}
// The prev events of the event if we want to override or falsify them.
// If it is left at nil, MustCreateEvent will populate it automatically based on the forward extremities.
PrevEvents interface{}
// If this is a redaction, the event that it redacts
Redacts string
}

// ServerRoom represents a room on this test federation server
type ServerRoom struct {
Version gomatrixserverlib.RoomVersion
Expand Down Expand Up @@ -212,13 +230,13 @@ func initialPowerLevelsContent(roomCreator string) (c gomatrixserverlib.PowerLev
}

// InitialRoomEvents returns the initial set of events that get created when making a room.
func InitialRoomEvents(roomVer gomatrixserverlib.RoomVersion, creator string) []b.Event {
func InitialRoomEvents(roomVer gomatrixserverlib.RoomVersion, creator string) []Event {
// need to serialise/deserialise to get map[string]interface{} annoyingly
plContent := initialPowerLevelsContent(creator)
plBytes, _ := json.Marshal(plContent)
var plContentMap map[string]interface{}
json.Unmarshal(plBytes, &plContentMap)
return []b.Event{
return []Event{
{
Type: "m.room.create",
StateKey: b.Ptr(""),
Expand Down
9 changes: 4 additions & 5 deletions tests/csapi/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,17 +291,16 @@ func TestSync(t *testing.T) {
// a good event - in another room - to act as a sentinel. It's not
// guaranteed, but hopefully if the sentinel is received, so was the
// redaction.
redactionEvent := srv.MustCreateEvent(t, redactionRoom, b.Event{
redactionEvent := srv.MustCreateEvent(t, redactionRoom, federation.Event{
Type: "m.room.redaction",
Sender: charlie,
Content: map[string]interface{}{},
Redacts: "$12345",
})
Redacts: "$12345"})
redactionRoom.AddEvent(redactionEvent)
t.Logf("Created redaction event %s", redactionEvent.EventID())
srv.MustSendTransaction(t, deployment, "hs1", []json.RawMessage{redactionEvent.JSON()}, nil)

sentinelEvent := srv.MustCreateEvent(t, sentinelRoom, b.Event{
sentinelEvent := srv.MustCreateEvent(t, sentinelRoom, federation.Event{
Type: "m.room.test",
Sender: charlie,
Content: map[string]interface{}{"body": "1234"},
Expand All @@ -318,7 +317,7 @@ func TestSync(t *testing.T) {
pdus := make([]json.RawMessage, 11)
var lastSentEventId string
for i := range pdus {
ev := srv.MustCreateEvent(t, redactionRoom, b.Event{
ev := srv.MustCreateEvent(t, redactionRoom, federation.Event{
Type: "m.room.message",
Sender: charlie,
Content: map[string]interface{}{},
Expand Down
2 changes: 1 addition & 1 deletion tests/direct_messaging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func TestIsDirectFlagFederation(t *testing.T) {

bob := srv.UserID("bob")
room := srv.MustMakeRoom(t, roomVer, federation.InitialRoomEvents(roomVer, bob))
dmInviteEvent := srv.MustCreateEvent(t, room, b.Event{
dmInviteEvent := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.member",
StateKey: &alice.UserID,
Sender: bob,
Expand Down
19 changes: 11 additions & 8 deletions tests/federation_redaction_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package tests

import (
"testing"
"time"

"github.com/matrix-org/complement/internal/b"
"github.com/matrix-org/complement/internal/federation"
"github.com/matrix-org/complement/runtime"
"github.com/matrix-org/gomatrixserverlib"
"testing"
"time"
)

// test that a redaction is sent out over federation even if we don't have the original event
Expand Down Expand Up @@ -56,23 +57,25 @@ func TestFederationRedactSendsWithoutEvent(t *testing.T) {
alice.JoinRoom(t, roomAlias, []string{srv.ServerName()})

// inject event to redact in the room
badEvent := srv.MustCreateEvent(t, serverRoom, b.Event{
badEvent := srv.MustCreateEvent(t, serverRoom, federation.Event{
Type: "m.room.message",
Sender: charlie,
Content: map[string]interface{}{
"body": "666",
},
})
}})
serverRoom.AddEvent(badEvent)

eventID := badEvent.EventID()
fullServerName := srv.ServerName()
eventToRedact := eventID + ":" + fullServerName

// the client sends a request to the local homeserver to send the redaction
res := alice.SendRedaction(t, serverRoom.RoomID, b.Event{Type: wantEventType, Content: map[string]interface{}{
"msgtype": "m.room.redaction"},
Redacts: eventToRedact}, eventToRedact)
res := alice.SendRedaction(t, serverRoom.RoomID, b.Event{
Type: wantEventType,
Content: map[string]interface{}{
"reason": "reasons...",
},
}, eventToRedact)

// wait for redaction to arrive at remote homeserver
waiter.Wait(t, 1*time.Second)
Expand Down
10 changes: 5 additions & 5 deletions tests/federation_room_event_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) {
charlieMembershipEvent := room.CurrentState("m.room.member", charlie)

// have Charlie send a PL event which will be rejected
rejectedEvent := srv.MustCreateEvent(t, room, b.Event{
rejectedEvent := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.power_levels",
StateKey: b.Ptr(""),
Sender: charlie,
Expand All @@ -140,7 +140,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) {

// create an event to be pulled in as an outlier, which is valid according to its prev events,
// but uses the rejected event among its auth events.
outlierEvent := srv.MustCreateEvent(t, room, b.Event{
outlierEvent := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.member",
StateKey: &charlie,
Sender: charlie,
Expand All @@ -166,7 +166,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) {
charlieMembershipEvent,
outlierEvent,
}
sentEvent1 := srv.MustCreateEvent(t, room, b.Event{
sentEvent1 := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.message",
Sender: charlie,
Content: map[string]interface{}{"body": "sentEvent1"},
Expand All @@ -178,7 +178,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) {

// another a regular event which refers to the outlier event, but
// this time we will give a different answer to /event_auth
sentEvent2 := srv.MustCreateEvent(t, room, b.Event{
sentEvent2 := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.message",
Sender: charlie,
Content: map[string]interface{}{"body": "sentEvent1"},
Expand All @@ -190,7 +190,7 @@ func TestInboundFederationRejectsEventsWithRejectedAuthEvents(t *testing.T) {
t.Logf("Created sent event 2 %s", sentEvent2.EventID())

// finally, a genuine regular event.
sentinelEvent := srv.MustCreateEvent(t, room, b.Event{
sentinelEvent := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.message",
Sender: charlie,
Content: map[string]interface{}{"body": "sentinelEvent"},
Expand Down
8 changes: 4 additions & 4 deletions tests/federation_room_get_missing_events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestGetMissingEventsGapFilling(t *testing.T) {
var missingEventIDs []string
numMissingEvents := 5
for i := 0; i < numMissingEvents; i++ {
missingEvent := srv.MustCreateEvent(t, srvRoom, b.Event{
missingEvent := srv.MustCreateEvent(t, srvRoom, federation.Event{
Sender: bob,
Type: "m.room.message",
Content: map[string]interface{}{
Expand All @@ -86,7 +86,7 @@ func TestGetMissingEventsGapFilling(t *testing.T) {
}

// 3) Inject a final event into Complement
mostRecentEvent := srv.MustCreateEvent(t, srvRoom, b.Event{
mostRecentEvent := srv.MustCreateEvent(t, srvRoom, federation.Event{
Sender: bob,
Type: "m.room.message",
Content: map[string]interface{}{
Expand Down Expand Up @@ -237,7 +237,7 @@ func TestOutboundFederationIgnoresMissingEventWithBadJSONForRoomVersion6(t *test
room.AddEvent(signedBadEvent)

// send the first "good" event, referencing the broken event as a prev_event
sentEvent := srv.MustCreateEvent(t, room, b.Event{
sentEvent := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.message",
Sender: charlie,
Content: map[string]interface{}{
Expand Down Expand Up @@ -291,7 +291,7 @@ func TestOutboundFederationIgnoresMissingEventWithBadJSONForRoomVersion6(t *test
// it just ignores it, so we need to send another event referring to the
// first one and check that we get a /get_missing_events request.

message3 := srv.MustCreateEvent(t, room, b.Event{
message3 := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.message",
Sender: charlie,
Content: map[string]interface{}{
Expand Down
18 changes: 9 additions & 9 deletions tests/federation_room_join_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) {
room := srv.MustMakeRoom(t, ver, federation.InitialRoomEvents(ver, charlie))
roomAlias := srv.MakeAliasMapping("MissingSignatures", room.RoomID)
// create a normal event then remove the signatures key
signedEvent := srv.MustCreateEvent(t, room, b.Event{
signedEvent := srv.MustCreateEvent(t, room, federation.Event{
Sender: charlie,
StateKey: b.Ptr(""),
Type: "m.room.name",
Expand All @@ -181,7 +181,7 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) {
room := srv.MustMakeRoom(t, ver, federation.InitialRoomEvents(ver, charlie))
roomAlias := srv.MakeAliasMapping("BadSignatures", room.RoomID)
// create a normal event then modify the signatures
signedEvent := srv.MustCreateEvent(t, room, b.Event{
signedEvent := srv.MustCreateEvent(t, room, federation.Event{
Sender: charlie,
StateKey: b.Ptr(""),
Type: "m.room.name",
Expand Down Expand Up @@ -212,7 +212,7 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) {
roomAlias := srv.MakeAliasMapping("UnobtainableKeys", room.RoomID)
// create a normal event then modify the signatures to have a bogus key ID which Complement does
// not have the keys for
signedEvent := srv.MustCreateEvent(t, room, b.Event{
signedEvent := srv.MustCreateEvent(t, room, federation.Event{
Sender: charlie,
StateKey: b.Ptr(""),
Type: "m.room.name",
Expand Down Expand Up @@ -246,7 +246,7 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) {
roomAlias := srv.MakeAliasMapping("UnverifiableAuthEvents", room.RoomID)

// create a normal event then modify the signatures
rawEvent := srv.MustCreateEvent(t, room, b.Event{
rawEvent := srv.MustCreateEvent(t, room, federation.Event{
Sender: charlie,
StateKey: &charlie,
Type: "m.room.member",
Expand All @@ -271,7 +271,7 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) {
t.Logf("Created badly signed auth event %s", badlySignedEvent.EventID())

// and now add another event which will use it as an auth event.
goodEvent := srv.MustCreateEvent(t, room, b.Event{
goodEvent := srv.MustCreateEvent(t, room, federation.Event{
Sender: charlie,
StateKey: &charlie,
Type: "m.room.member",
Expand Down Expand Up @@ -453,15 +453,15 @@ func testValidationForSendMembershipEndpoint(t *testing.T, baseApiPath, expected
}

t.Run("regular event", func(t *testing.T) {
event := srv.MustCreateEvent(t, room, b.Event{
event := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.message",
Sender: charlie,
Content: map[string]interface{}{"body": "bzz"},
})
assertRequestFails(t, event)
})
t.Run("non-state membership event", func(t *testing.T) {
event := srv.MustCreateEvent(t, room, b.Event{
event := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.member",
Sender: charlie,
Content: map[string]interface{}{"body": "bzz"},
Expand All @@ -475,7 +475,7 @@ func testValidationForSendMembershipEndpoint(t *testing.T, baseApiPath, expected
if membershipType == expectedMembership {
continue
}
event := srv.MustCreateEvent(t, room, b.Event{
event := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.member",
Sender: charlie,
StateKey: &charlie,
Expand All @@ -488,7 +488,7 @@ func testValidationForSendMembershipEndpoint(t *testing.T, baseApiPath, expected

// right sort of membership, but mismatched state_key
t.Run("event with mismatched state key", func(t *testing.T) {
event := srv.MustCreateEvent(t, room, b.Event{
event := srv.MustCreateEvent(t, room, federation.Event{
Type: "m.room.member",
Sender: charlie,
StateKey: b.Ptr(srv.UserID("doris")),
Expand Down
10 changes: 5 additions & 5 deletions tests/federation_unreject_rejected_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,20 @@ func TestUnrejectRejectedEvents(t *testing.T) {
// Create the events. Event A will have whatever the current forward
// extremities are as prev events. Event B will refer to event A only
// to guarantee the test will work.
eventA := srv.MustCreateEvent(t, serverRoom, b.Event{
eventA := srv.MustCreateEvent(t, serverRoom, federation.Event{
Type: "m.event.a",
Sender: bob,
Content: map[string]interface{}{
"event": "A",
},
})
eventB := srv.MustCreateEvent(t, serverRoom, b.Event{
Type: "m.event.b",
Sender: bob,
PrevEvents: []string{eventA.EventID()},
eventB := srv.MustCreateEvent(t, serverRoom, federation.Event{
Type: "m.event.b",
Sender: bob,
Content: map[string]interface{}{
"event": "B",
},
PrevEvents: []string{eventA.EventID()},
})

// Send event B into the room. Event A at this point is unknown
Expand Down

0 comments on commit d68b044

Please sign in to comment.