Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test for state_key size #642

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions tests/federation_room_get_missing_events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -454,3 +455,132 @@ func TestInboundCanReturnMissingEvents(t *testing.T) {
})
}
}

// This test verifies that an event with a too large state_key can be used as a prev_event
// it is returned by a call to /get_missing_events and should pass event size checks.
// TODO: Do the same checks for type, user_id and sender
func TestOutboundFederationEventSizeGetMissingEvents(t *testing.T) {
deployment := Deploy(t, b.BlueprintAlice)
defer deployment.Destroy(t)

alice := deployment.Client(t, "hs1", "@alice:hs1")

srv := federation.NewServer(t, deployment,
federation.HandleKeyRequests(),
federation.HandleMakeSendJoinRequests(),
// Handle any transactions that the homeserver may send when connecting to another homeserver (such as presence)
federation.HandleTransactionRequests(nil, nil),
)
cancel := srv.Listen()
defer cancel()

// register a handler for /get_missing_events, via a shim so that we can
// behave differently as the test progresses.
var onGetMissingEvents func(w http.ResponseWriter, req *http.Request)
srv.Mux().HandleFunc("/_matrix/federation/v1/get_missing_events/{roomID}", func(w http.ResponseWriter, req *http.Request) {
onGetMissingEvents(w, req)
}).Methods("POST")

ver := alice.GetDefaultRoomVersion(t)
charlie := srv.UserID("charlie")
room := srv.MustMakeRoom(t, ver, federation.InitialRoomEvents(ver, charlie))
roomAlias := srv.MakeAliasMapping("flibble", room.RoomID)
// join the room
alice.JoinRoom(t, roomAlias, nil)

latestEvent := room.Timeline[len(room.Timeline)-1]

// Sign this bad event which has a too large stateKey
// Synapse always enforced 255 codepoints, but accepts events > 255 bytes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/events/state_keys?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or "events with state keys"?

// Dendrite would fail to parse this event because it enforced 255 bytes, breaking older rooms.
stateKey := strings.Repeat("💥", 70) // 280 bytes, 70 codepoints
badEvent := b.Event{
Type: "my.room.breaker",
StateKey: &stateKey,
Sender: charlie,
Content: map[string]interface{}{},
}
content, err := json.Marshal(badEvent.Content)
if err != nil {
t.Fatalf("failed to marshal badEvent content %+v", badEvent.Content)
}
eb := gomatrixserverlib.EventBuilder{
Sender: badEvent.Sender,
Depth: int64(room.Depth + 1), // depth starts at 1
Type: badEvent.Type,
StateKey: badEvent.StateKey,
Content: content,
RoomID: room.RoomID,
PrevEvents: room.ForwardExtremities,
}
stateNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(&eb)
if err != nil {
t.Fatalf("failed to work out auth_events : %s", err)
}
eb.AuthEvents = room.AuthEvents(stateNeeded)

signedBadEvent, err := eb.Build(time.Now(), gomatrixserverlib.ServerName(srv.ServerName()), srv.KeyID, srv.Priv, ver)
switch e := err.(type) {
case nil:
case gomatrixserverlib.EventValidationError:
// ignore for now
t.Logf("EventValidationError: %v", e)
default:
t.Fatalf("failed to sign event: %s: %s", err, signedBadEvent.JSON())
}
room.AddEvent(signedBadEvent)

// send the first "good" event, referencing the broken event as a prev_event
sentEvent := srv.MustCreateEvent(t, room, b.Event{
Type: "m.room.message",
Sender: charlie,
Content: map[string]interface{}{
"body": "Message 2",
},
})
room.AddEvent(sentEvent)

waiter := NewWaiter()
onGetMissingEvents = func(w http.ResponseWriter, req *http.Request) {
defer waiter.Finish()
must.MatchRequest(t, req, match.HTTPRequest{
JSON: []match.JSON{
match.JSONKeyEqual("earliest_events", []interface{}{latestEvent.EventID()}),
match.JSONKeyEqual("latest_events", []interface{}{sentEvent.EventID()}),
},
})
// return the bad event, which should result in the transaction failing.
w.WriteHeader(200)
res := struct {
Events []*gomatrixserverlib.Event `json:"events"`
}{
Events: []*gomatrixserverlib.Event{signedBadEvent},
}
var responseBytes []byte
responseBytes, err = json.Marshal(&res)
must.NotError(t, "failed to marshal response", err)
w.Write(responseBytes)
}

fedClient := srv.FederationClient(deployment)
resp, err := fedClient.SendTransaction(context.Background(), gomatrixserverlib.Transaction{
TransactionID: "wut",
Origin: gomatrixserverlib.ServerName(srv.ServerName()),
Destination: gomatrixserverlib.ServerName("hs1"),
PDUs: []json.RawMessage{
sentEvent.JSON(),
},
})
waiter.Wait(t, 5*time.Second)
must.NotError(t, "SendTransaction errored", err)
if len(resp.PDUs) != 1 {
t.Fatalf("got %d errors, want 1", len(resp.PDUs))
}
_, ok := resp.PDUs[sentEvent.EventID()]
if !ok {
t.Fatalf("wrong PDU returned from send transaction, got %v want %s", resp.PDUs, sentEvent.EventID())
}

// Alice should receive the sent event, even though the "bad" event has a too large state key
alice.MustSyncUntil(t, client.SyncReq{}, client.SyncTimelineHasEventID(room.RoomID, sentEvent.EventID()))
}