Handle event_format federation in /sync responses (#3192)

This commit is contained in:
devonh 2023-08-31 15:33:38 +00:00 committed by GitHub
parent 11fd2f019b
commit bb2ab62cbf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 739 additions and 84 deletions

View file

@ -16,12 +16,21 @@
package synctypes
import (
"encoding/json"
"fmt"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/spec"
"github.com/sirupsen/logrus"
)
// PrevEventRef represents a reference to a previous event in a state event upgrade
type PrevEventRef struct {
PrevContent json.RawMessage `json:"prev_content"`
ReplacesState string `json:"replaces_state"`
PrevSenderID string `json:"prev_sender"`
}
type ClientEventFormat int
const (
@ -30,8 +39,21 @@ const (
// FormatSync will include only the event keys required by the /sync API. Notably, this
// means the 'room_id' will be missing from the events.
FormatSync
// FormatSyncFederation will include all event keys normally included in federated events.
// This allows clients to request federated formatted events via the /sync API.
FormatSyncFederation
)
// ClientFederationFields extends a ClientEvent to contain the additional fields present in a
// federation event. Used when the client requests `event_format` of type `federation`.
type ClientFederationFields struct {
Depth int64 `json:"depth,omitempty"`
PrevEvents []string `json:"prev_events,omitempty"`
AuthEvents []string `json:"auth_events,omitempty"`
Signatures spec.RawJSON `json:"signatures,omitempty"`
Hashes spec.RawJSON `json:"hashes,omitempty"`
}
// ClientEvent is an event which is fit for consumption by clients, in accordance with the specification.
type ClientEvent struct {
Content spec.RawJSON `json:"content"`
@ -44,6 +66,9 @@ type ClientEvent struct {
Type string `json:"type"`
Unsigned spec.RawJSON `json:"unsigned,omitempty"`
Redacts string `json:"redacts,omitempty"`
// Only sent to clients when `event_format` == `federation`.
ClientFederationFields
}
// ToClientEvents converts server events to client events.
@ -53,6 +78,11 @@ func ToClientEvents(serverEvs []gomatrixserverlib.PDU, format ClientEventFormat,
if se == nil {
continue // TODO: shouldn't happen?
}
if format == FormatSyncFederation {
evs = append(evs, ToClientEvent(se, format, string(se.SenderID()), se.StateKey(), spec.RawJSON(se.Unsigned())))
continue
}
sender := spec.UserID{}
validRoomID, err := spec.NewRoomID(se.RoomID())
if err != nil {
@ -71,28 +101,61 @@ func ToClientEvents(serverEvs []gomatrixserverlib.PDU, format ClientEventFormat,
sk = &skString
}
}
evs = append(evs, ToClientEvent(se, format, sender, sk))
unsigned := se.Unsigned()
var prev PrevEventRef
if err := json.Unmarshal(se.Unsigned(), &prev); err == nil && prev.PrevSenderID != "" {
prevUserID, err := userIDForSender(*validRoomID, spec.SenderID(prev.PrevSenderID))
if err == nil && userID != nil {
prev.PrevSenderID = prevUserID.String()
} else {
errString := "userID unknown"
if err != nil {
errString = err.Error()
}
logrus.Warnf("Failed to find userID for prev_sender in ClientEvent: %s", errString)
// NOTE: Not much can be done here, so leave the previous value in place.
}
unsigned, err = json.Marshal(prev)
if err != nil {
logrus.Errorf("Failed to marshal unsigned content for ClientEvent: %s", err.Error())
continue
}
}
evs = append(evs, ToClientEvent(se, format, sender.String(), sk, spec.RawJSON(unsigned)))
}
return evs
}
// ToClientEvent converts a single server event to a client event.
func ToClientEvent(se gomatrixserverlib.PDU, format ClientEventFormat, sender spec.UserID, stateKey *string) ClientEvent {
func ToClientEvent(se gomatrixserverlib.PDU, format ClientEventFormat, sender string, stateKey *string, unsigned spec.RawJSON) ClientEvent {
ce := ClientEvent{
Content: spec.RawJSON(se.Content()),
Sender: sender.String(),
Sender: sender,
Type: se.Type(),
StateKey: stateKey,
Unsigned: spec.RawJSON(se.Unsigned()),
Unsigned: unsigned,
OriginServerTS: se.OriginServerTS(),
EventID: se.EventID(),
Redacts: se.Redacts(),
}
if format == FormatAll {
switch format {
case FormatAll:
ce.RoomID = se.RoomID()
case FormatSync:
case FormatSyncFederation:
ce.RoomID = se.RoomID()
ce.AuthEvents = se.AuthEventIDs()
ce.PrevEvents = se.PrevEventIDs()
ce.Depth = se.Depth()
// TODO: Set Signatures & Hashes fields
}
if se.Version() == gomatrixserverlib.RoomVersionPseudoIDs {
ce.SenderKey = se.SenderID()
if format != FormatSyncFederation {
if se.Version() == gomatrixserverlib.RoomVersionPseudoIDs {
ce.SenderKey = se.SenderID()
}
}
return ce
}
@ -118,7 +181,7 @@ func ToClientEventDefault(userIDQuery spec.UserIDForSender, event gomatrixserver
sk = &skString
}
}
return ToClientEvent(event, FormatAll, sender, sk)
return ToClientEvent(event, FormatAll, sender.String(), sk, event.Unsigned())
}
// If provided state key is a user ID (state keys beginning with @ are reserved for this purpose)