5
5
"encoding/json"
6
6
"fmt"
7
7
"net/http"
8
+ "strings"
8
9
"testing"
9
10
"time"
10
11
@@ -17,8 +18,8 @@ import (
17
18
18
19
"github.com/matrix-org/complement/b"
19
20
"github.com/matrix-org/complement/client"
20
- "github.com/matrix-org/complement/helpers"
21
21
"github.com/matrix-org/complement/federation"
22
+ "github.com/matrix-org/complement/helpers"
22
23
"github.com/matrix-org/complement/match"
23
24
"github.com/matrix-org/complement/must"
24
25
)
@@ -466,3 +467,134 @@ func TestInboundCanReturnMissingEvents(t *testing.T) {
466
467
})
467
468
}
468
469
}
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