|
5 | 5 | "encoding/json"
|
6 | 6 | "fmt"
|
7 | 7 | "net/http"
|
| 8 | + "strings" |
8 | 9 | "testing"
|
9 | 10 | "time"
|
10 | 11 |
|
@@ -454,3 +455,132 @@ func TestInboundCanReturnMissingEvents(t *testing.T) {
|
454 | 455 | })
|
455 | 456 | }
|
456 | 457 | }
|
| 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