Skip to content

Commit f8e4e05

Browse files
committed
Add test for state_key event size
1 parent 39436e9 commit f8e4e05

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed

tests/federation_room_get_missing_events_test.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"fmt"
77
"net/http"
8+
"strings"
89
"testing"
910
"time"
1011

@@ -454,3 +455,132 @@ func TestInboundCanReturnMissingEvents(t *testing.T) {
454455
})
455456
}
456457
}
458+
459+
// This test verifies that an event with a too large state_key can be used as a prev_event
460+
// it is returned by a call to /get_missing_events and should pass event size checks.
461+
// TODO: Do the same checks for type, user_id and sender
462+
func TestOutboundFederationEventSizeGetMissingEvents(t *testing.T) {
463+
deployment := Deploy(t, b.BlueprintAlice)
464+
defer deployment.Destroy(t)
465+
466+
alice := deployment.Client(t, "hs1", "@alice:hs1")
467+
468+
srv := federation.NewServer(t, deployment,
469+
federation.HandleKeyRequests(),
470+
federation.HandleMakeSendJoinRequests(),
471+
// Handle any transactions that the homeserver may send when connecting to another homeserver (such as presence)
472+
federation.HandleTransactionRequests(nil, nil),
473+
)
474+
cancel := srv.Listen()
475+
defer cancel()
476+
477+
// register a handler for /get_missing_events, via a shim so that we can
478+
// behave differently as the test progresses.
479+
var onGetMissingEvents func(w http.ResponseWriter, req *http.Request)
480+
srv.Mux().HandleFunc("/_matrix/federation/v1/get_missing_events/{roomID}", func(w http.ResponseWriter, req *http.Request) {
481+
onGetMissingEvents(w, req)
482+
}).Methods("POST")
483+
484+
ver := alice.GetDefaultRoomVersion(t)
485+
charlie := srv.UserID("charlie")
486+
room := srv.MustMakeRoom(t, ver, federation.InitialRoomEvents(ver, charlie))
487+
roomAlias := srv.MakeAliasMapping("flibble", room.RoomID)
488+
// join the room
489+
alice.JoinRoom(t, roomAlias, nil)
490+
491+
latestEvent := room.Timeline[len(room.Timeline)-1]
492+
493+
// Sign this bad event which has a too large stateKey
494+
// Synapse always enforced 255 codepoints, but accepts events > 255 bytes.
495+
// Dendrite would fail to parse this event because it enforced 255 bytes, breaking older rooms.
496+
stateKey := strings.Repeat("💥", 70) // 280 bytes, 70 codepoints
497+
badEvent := b.Event{
498+
Type: "my.room.breaker",
499+
StateKey: &stateKey,
500+
Sender: charlie,
501+
Content: map[string]interface{}{},
502+
}
503+
content, err := json.Marshal(badEvent.Content)
504+
if err != nil {
505+
t.Fatalf("failed to marshal badEvent content %+v", badEvent.Content)
506+
}
507+
eb := gomatrixserverlib.EventBuilder{
508+
Sender: badEvent.Sender,
509+
Depth: int64(room.Depth + 1), // depth starts at 1
510+
Type: badEvent.Type,
511+
StateKey: badEvent.StateKey,
512+
Content: content,
513+
RoomID: room.RoomID,
514+
PrevEvents: room.ForwardExtremities,
515+
}
516+
stateNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(&eb)
517+
if err != nil {
518+
t.Fatalf("failed to work out auth_events : %s", err)
519+
}
520+
eb.AuthEvents = room.AuthEvents(stateNeeded)
521+
522+
signedBadEvent, err := eb.Build(time.Now(), gomatrixserverlib.ServerName(srv.ServerName()), srv.KeyID, srv.Priv, ver)
523+
switch e := err.(type) {
524+
case nil:
525+
case gomatrixserverlib.EventValidationError:
526+
// ignore for now
527+
t.Logf("EventValidationError: %v", e)
528+
default:
529+
t.Fatalf("failed to sign event: %s: %s", err, signedBadEvent.JSON())
530+
}
531+
room.AddEvent(signedBadEvent)
532+
533+
// send the first "good" event, referencing the broken event as a prev_event
534+
sentEvent := srv.MustCreateEvent(t, room, b.Event{
535+
Type: "m.room.message",
536+
Sender: charlie,
537+
Content: map[string]interface{}{
538+
"body": "Message 2",
539+
},
540+
})
541+
room.AddEvent(sentEvent)
542+
543+
waiter := NewWaiter()
544+
onGetMissingEvents = func(w http.ResponseWriter, req *http.Request) {
545+
defer waiter.Finish()
546+
must.MatchRequest(t, req, match.HTTPRequest{
547+
JSON: []match.JSON{
548+
match.JSONKeyEqual("earliest_events", []interface{}{latestEvent.EventID()}),
549+
match.JSONKeyEqual("latest_events", []interface{}{sentEvent.EventID()}),
550+
},
551+
})
552+
// return the bad event, which should result in the transaction failing.
553+
w.WriteHeader(200)
554+
res := struct {
555+
Events []*gomatrixserverlib.Event `json:"events"`
556+
}{
557+
Events: []*gomatrixserverlib.Event{signedBadEvent},
558+
}
559+
var responseBytes []byte
560+
responseBytes, err = json.Marshal(&res)
561+
must.NotError(t, "failed to marshal response", err)
562+
w.Write(responseBytes)
563+
}
564+
565+
fedClient := srv.FederationClient(deployment)
566+
resp, err := fedClient.SendTransaction(context.Background(), gomatrixserverlib.Transaction{
567+
TransactionID: "wut",
568+
Origin: gomatrixserverlib.ServerName(srv.ServerName()),
569+
Destination: gomatrixserverlib.ServerName("hs1"),
570+
PDUs: []json.RawMessage{
571+
sentEvent.JSON(),
572+
},
573+
})
574+
waiter.Wait(t, 5*time.Second)
575+
must.NotError(t, "SendTransaction errored", err)
576+
if len(resp.PDUs) != 1 {
577+
t.Fatalf("got %d errors, want 1", len(resp.PDUs))
578+
}
579+
_, ok := resp.PDUs[sentEvent.EventID()]
580+
if !ok {
581+
t.Fatalf("wrong PDU returned from send transaction, got %v want %s", resp.PDUs, sentEvent.EventID())
582+
}
583+
584+
// Alice should receive the sent event, even though the "bad" event has a too large state key
585+
alice.MustSyncUntil(t, client.SyncReq{}, client.SyncTimelineHasEventID(room.RoomID, sentEvent.EventID()))
586+
}

0 commit comments

Comments
 (0)