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