diff --git a/src/github.com/matrix-org/dendrite/clientapi/producers/roomserver.go b/src/github.com/matrix-org/dendrite/clientapi/producers/roomserver.go index 02a5956ce..aea912c25 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/producers/roomserver.go +++ b/src/github.com/matrix-org/dendrite/clientapi/producers/roomserver.go @@ -49,7 +49,7 @@ func (c *RoomserverProducer) SendEvents(events []gomatrixserverlib.Event, sendAs ires[i] = api.InputRoomEvent{ Kind: api.KindNew, Event: event.JSON(), - AuthEventIDs: authEventIDs(event), + AuthEventIDs: event.AuthEventIDs(), SendAsServer: string(sendAsServer), } eventIDs[i] = event.EventID() @@ -71,7 +71,7 @@ func (c *RoomserverProducer) SendEventWithState(state gomatrixserverlib.RespStat ires[i] = api.InputRoomEvent{ Kind: api.KindOutlier, Event: outlier.JSON(), - AuthEventIDs: authEventIDs(outlier), + AuthEventIDs: outlier.AuthEventIDs(), } eventIDs[i] = outlier.EventID() } @@ -84,7 +84,7 @@ func (c *RoomserverProducer) SendEventWithState(state gomatrixserverlib.RespStat ires[len(outliers)] = api.InputRoomEvent{ Kind: api.KindNew, Event: event.JSON(), - AuthEventIDs: authEventIDs(event), + AuthEventIDs: event.AuthEventIDs(), HasState: true, StateEventIDs: stateEventIDs, } @@ -93,14 +93,6 @@ func (c *RoomserverProducer) SendEventWithState(state gomatrixserverlib.RespStat return c.SendInputRoomEvents(ires, eventIDs) } -// TODO Make this a method on gomatrixserverlib.Event -func authEventIDs(event gomatrixserverlib.Event) (ids []string) { - for _, ref := range event.AuthEvents() { - ids = append(ids, ref.EventID) - } - return -} - // SendInputRoomEvents writes the given input room events to the roomserver input log. The length of both // arrays must match, and each element must correspond to the same event. func (c *RoomserverProducer) SendInputRoomEvents(ires []api.InputRoomEvent, eventIDs []string) error { diff --git a/src/github.com/matrix-org/dendrite/clientapi/readers/directory.go b/src/github.com/matrix-org/dendrite/clientapi/readers/directory.go index db8e75247..10e760943 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/readers/directory.go +++ b/src/github.com/matrix-org/dendrite/clientapi/readers/directory.go @@ -16,6 +16,8 @@ package readers import ( "fmt" + "net/http" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" @@ -23,8 +25,6 @@ import ( "github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" - "net/http" - "strings" ) // DirectoryRoom looks up a room alias @@ -35,7 +35,7 @@ func DirectoryRoom( federation *gomatrixserverlib.FederationClient, cfg *config.Dendrite, ) util.JSONResponse { - domain, err := domainFromID(roomAlias) + _, domain, err := gomatrixserverlib.ParseID('#', roomAlias) if err != nil { return util.JSONResponse{ Code: 400, @@ -69,19 +69,3 @@ func DirectoryRoom( } } } - -// domainFromID returns everything after the first ":" character to extract -// the domain part of a matrix ID. -// TODO: duplicated from gomatrixserverlib. -func domainFromID(id string) (gomatrixserverlib.ServerName, error) { - // IDs have the format: SIGIL LOCALPART ":" DOMAIN - // Split on the first ":" character since the domain can contain ":" - // characters. - parts := strings.SplitN(id, ":", 2) - if len(parts) != 2 { - // The ID must have a ":" character. - return "", fmt.Errorf("invalid ID: %q", id) - } - // Return everything after the first ":" character. - return gomatrixserverlib.ServerName(parts[1]), nil -} diff --git a/src/github.com/matrix-org/dendrite/clientapi/writers/createroom.go b/src/github.com/matrix-org/dendrite/clientapi/writers/createroom.go index fccc42b7e..731519836 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/writers/createroom.go +++ b/src/github.com/matrix-org/dendrite/clientapi/writers/createroom.go @@ -60,14 +60,7 @@ func (r createRoomRequest) Validate() *util.JSONResponse { // It should be a struct (with pointers into a single string to avoid copying) and // we should update all refs to use UserID types rather than strings. // https://github.com/matrix-org/synapse/blob/v0.19.2/synapse/types.py#L92 - if len(userID) == 0 || userID[0] != '@' { - return &util.JSONResponse{ - Code: 400, - JSON: jsonerror.BadJSON("user id must start with '@'"), - } - } - parts := strings.SplitN(userID[1:], ":", 2) - if len(parts) != 2 { + if _, _, err := gomatrixserverlib.ParseID('@', userID); err != nil { return &util.JSONResponse{ Code: 400, JSON: jsonerror.BadJSON("user id must be in the form @localpart:domain"), diff --git a/src/github.com/matrix-org/dendrite/clientapi/writers/joinroom.go b/src/github.com/matrix-org/dendrite/clientapi/writers/joinroom.go index 57bc3e86b..09051c8f1 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/writers/joinroom.go +++ b/src/github.com/matrix-org/dendrite/clientapi/writers/joinroom.go @@ -16,6 +16,10 @@ package writers import ( "fmt" + "net/http" + "strings" + "time" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" @@ -25,9 +29,6 @@ import ( "github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" - "net/http" - "strings" - "time" ) // JoinRoomByIDOrAlias implements the "/join/{roomIDOrAlias}" API. @@ -88,7 +89,7 @@ func (r joinRoomReq) joinRoomByID() util.JSONResponse { // joinRoomByAlias joins a room using a room alias. func (r joinRoomReq) joinRoomByAlias(roomAlias string) util.JSONResponse { - domain, err := domainFromID(roomAlias) + _, domain, err := gomatrixserverlib.ParseID('#', roomAlias) if err != nil { return util.JSONResponse{ Code: 400, @@ -245,19 +246,3 @@ func (r joinRoomReq) joinRoomUsingServer(roomID string, server gomatrixserverlib }{roomID}, }, nil } - -// domainFromID returns everything after the first ":" character to extract -// the domain part of a matrix ID. -// TODO: duplicated from gomatrixserverlib. -func domainFromID(id string) (gomatrixserverlib.ServerName, error) { - // IDs have the format: SIGIL LOCALPART ":" DOMAIN - // Split on the first ":" character since the domain can contain ":" - // characters. - parts := strings.SplitN(id, ":", 2) - if len(parts) != 2 { - // The ID must have a ":" character. - return "", fmt.Errorf("invalid ID: %q", id) - } - // Return everything after the first ":" character. - return gomatrixserverlib.ServerName(parts[1]), nil -} diff --git a/src/github.com/matrix-org/dendrite/federationapi/writers/send.go b/src/github.com/matrix-org/dendrite/federationapi/writers/send.go index a6013cea2..67ee6b027 100644 --- a/src/github.com/matrix-org/dendrite/federationapi/writers/send.go +++ b/src/github.com/matrix-org/dendrite/federationapi/writers/send.go @@ -118,11 +118,7 @@ type unknownRoomError struct { func (e unknownRoomError) Error() string { return fmt.Sprintf("unknown room %q", e.roomID) } func (t *txnReq) processEvent(e gomatrixserverlib.Event) error { - refs := e.PrevEvents() - prevEventIDs := make([]string, len(refs)) - for i := range refs { - prevEventIDs[i] = refs[i].EventID - } + prevEventIDs := e.PrevEventIDs() // Fetch the state needed to authenticate the event. needed := gomatrixserverlib.StateNeededForAuth([]gomatrixserverlib.Event{e}) diff --git a/src/github.com/matrix-org/dendrite/federationsender/consumers/roomserver.go b/src/github.com/matrix-org/dendrite/federationsender/consumers/roomserver.go index 9ac0e9880..340875318 100644 --- a/src/github.com/matrix-org/dendrite/federationsender/consumers/roomserver.go +++ b/src/github.com/matrix-org/dendrite/federationsender/consumers/roomserver.go @@ -17,7 +17,6 @@ package consumers import ( "encoding/json" "fmt" - "strings" log "github.com/Sirupsen/logrus" "github.com/matrix-org/dendrite/common" @@ -220,16 +219,14 @@ func joinedHostsFromEvents(evs []gomatrixserverlib.Event) ([]types.JoinedHost, e if ev.Type() != "m.room.member" || ev.StateKey() == nil { continue } - var content struct { - Membership string `json:"membership"` - } - if err := json.Unmarshal(ev.Content(), &content); err != nil { + membership, err := ev.Membership() + if err != nil { return nil, err } - if content.Membership != "join" { + if *membership != "join" { continue } - serverName, err := domainFromID(*ev.StateKey()) + _, serverName, err := gomatrixserverlib.ParseID('@', *ev.StateKey()) if err != nil { return nil, err } @@ -343,19 +340,3 @@ func missingEventsFrom(events []gomatrixserverlib.Event, required []string) []st } return missing } - -// domainFromID returns everything after the first ":" character to extract -// the domain part of a matrix ID. -// TODO: duplicated from gomatrixserverlib. -func domainFromID(id string) (gomatrixserverlib.ServerName, error) { - // IDs have the format: SIGIL LOCALPART ":" DOMAIN - // Split on the first ":" character since the domain can contain ":" - // characters. - parts := strings.SplitN(id, ":", 2) - if len(parts) != 2 { - // The ID must have a ":" character. - return "", fmt.Errorf("invalid ID: %q", id) - } - // Return everything after the first ":" character. - return gomatrixserverlib.ServerName(parts[1]), nil -} diff --git a/src/github.com/matrix-org/dendrite/mediaapi/writers/upload.go b/src/github.com/matrix-org/dendrite/mediaapi/writers/upload.go index 163ea7b68..275e6e9b3 100644 --- a/src/github.com/matrix-org/dendrite/mediaapi/writers/upload.go +++ b/src/github.com/matrix-org/dendrite/mediaapi/writers/upload.go @@ -20,7 +20,6 @@ import ( "net/http" "net/url" "path" - "strings" log "github.com/Sirupsen/logrus" "github.com/matrix-org/dendrite/clientapi/jsonerror" @@ -29,6 +28,7 @@ import ( "github.com/matrix-org/dendrite/mediaapi/storage" "github.com/matrix-org/dendrite/mediaapi/thumbnailer" "github.com/matrix-org/dendrite/mediaapi/types" + "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" ) @@ -193,14 +193,7 @@ func (r *uploadRequest) Validate(maxFileSizeBytes config.FileSizeBytes) *util.JS // It should be a struct (with pointers into a single string to avoid copying) and // we should update all refs to use UserID types rather than strings. // https://github.com/matrix-org/synapse/blob/v0.19.2/synapse/types.py#L92 - if len(r.MediaMetadata.UserID) == 0 || r.MediaMetadata.UserID[0] != '@' { - return &util.JSONResponse{ - Code: 400, - JSON: jsonerror.Unknown("user id must start with '@'"), - } - } - parts := strings.SplitN(string(r.MediaMetadata.UserID[1:]), ":", 2) - if len(parts) != 2 { + if _, _, err := gomatrixserverlib.ParseID('@', string(r.MediaMetadata.UserID)); err != nil { return &util.JSONResponse{ Code: 400, JSON: jsonerror.BadJSON("user id must be in the form @localpart:domain"), diff --git a/src/github.com/matrix-org/dendrite/syncapi/storage/syncserver.go b/src/github.com/matrix-org/dendrite/syncapi/storage/syncserver.go index ce2e7f234..dfb94a9ea 100644 --- a/src/github.com/matrix-org/dendrite/syncapi/storage/syncserver.go +++ b/src/github.com/matrix-org/dendrite/syncapi/storage/syncserver.go @@ -16,11 +16,9 @@ package storage import ( "database/sql" - "encoding/json" "fmt" // Import the postgres database driver. _ "github.com/lib/pq" - "github.com/matrix-org/dendrite/clientapi/events" "github.com/matrix-org/dendrite/common" "github.com/matrix-org/dendrite/syncapi/types" "github.com/matrix-org/gomatrixserverlib" @@ -127,13 +125,15 @@ func (d *SyncServerDatabase) updateRoomState( // ignore non state events continue } - var membership *string + var ( + membership *string + err error + ) if event.Type() == "m.room.member" { - var memberContent events.MemberContent - if err := json.Unmarshal(event.Content(), &memberContent); err != nil { + membership, err = event.Membership() + if err != nil { return err } - membership = &memberContent.Membership } if err := d.roomstate.upsertRoomState(txn, event, membership, int64(streamPos)); err != nil { return err @@ -473,11 +473,11 @@ func removeDuplicates(stateEvents, recentEvents []gomatrixserverlib.Event) []gom // with type 'm.room.member' and state_key of userID. Otherwise, an empty string is returned. func getMembershipFromEvent(ev *gomatrixserverlib.Event, userID string) string { if ev.Type() == "m.room.member" && ev.StateKeyEquals(userID) { - var memberContent events.MemberContent - if err := json.Unmarshal(ev.Content(), &memberContent); err != nil { + membership, err := ev.Membership() + if err != nil { return "" } - return memberContent.Membership + return *membership } return "" } diff --git a/src/github.com/matrix-org/dendrite/syncapi/sync/notifier.go b/src/github.com/matrix-org/dendrite/syncapi/sync/notifier.go index 1cc9c4e28..31f0fe4e1 100644 --- a/src/github.com/matrix-org/dendrite/syncapi/sync/notifier.go +++ b/src/github.com/matrix-org/dendrite/syncapi/sync/notifier.go @@ -15,11 +15,9 @@ package sync import ( - "encoding/json" "sync" log "github.com/Sirupsen/logrus" - "github.com/matrix-org/dendrite/clientapi/events" "github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/types" "github.com/matrix-org/gomatrixserverlib" @@ -68,14 +66,14 @@ func (n *Notifier) OnNewEvent(ev *gomatrixserverlib.Event, pos types.StreamPosit // If this is an invite, also add in the invitee to this list. if ev.Type() == "m.room.member" && ev.StateKey() != nil { userID := *ev.StateKey() - var memberContent events.MemberContent - if err := json.Unmarshal(ev.Content(), &memberContent); err != nil { + membership, err := ev.Membership() + if err != nil { log.WithError(err).WithField("event_id", ev.EventID()).Errorf( "Notifier.OnNewEvent: Failed to unmarshal member event", ) } else { // Keep the joined user map up-to-date - switch memberContent.Membership { + switch *membership { case "invite": userIDs = append(userIDs, userID) case "join": diff --git a/vendor/src/github.com/matrix-org/gomatrixserverlib/event.go b/vendor/src/github.com/matrix-org/gomatrixserverlib/event.go index 11a165131..896a6cf0c 100644 --- a/vendor/src/github.com/matrix-org/gomatrixserverlib/event.go +++ b/vendor/src/github.com/matrix-org/gomatrixserverlib/event.go @@ -18,8 +18,10 @@ package gomatrixserverlib import ( "encoding/json" "fmt" - "golang.org/x/crypto/ed25519" + "strings" "time" + + "golang.org/x/crypto/ed25519" ) // A StateKeyTuple is the combination of an event type and an event state key. @@ -54,7 +56,7 @@ type EventBuilder struct { Type string `json:"type"` // The state_key of the event if the event is a state event or nil if the event is not a state event. StateKey *string `json:"state_key,omitempty"` - // The events that immediately preceeded this event in the room history. + // The events that immediately preceded this event in the room history. PrevEvents []EventReference `json:"prev_events"` // The events needed to authenticate this event. AuthEvents []EventReference `json:"auth_events"` @@ -112,7 +114,7 @@ var emptyEventReferenceList = []EventReference{} // Build a new Event. // This is used when a local event is created on this server. // Call this after filling out the necessary fields. -// This can be called mutliple times on the same builder. +// This can be called multiple times on the same builder. // A different event ID must be supplied each time this is called. func (eb *EventBuilder) Build(eventID string, now time.Time, origin ServerName, keyID KeyID, privateKey ed25519.PrivateKey) (result Event, err error) { var event struct { @@ -467,11 +469,44 @@ func (e Event) PrevEvents() []EventReference { return e.fields.PrevEvents } +// PrevEventIDs returns the event IDs of the direct ancestors of the event. +func (e Event) PrevEventIDs() []string { + result := make([]string, len(e.fields.PrevEvents)) + for i := range e.fields.PrevEvents { + result[i] = e.fields.PrevEvents[i].EventID + } + return result +} + +// Membership returns the value of the content.membership field if this event +// is an "m.room.member" event. +// Returns an error if the event is not a m.room.member event or if the content +// is not valid m.room.member content. +func (e Event) Membership() (*string, error) { + if e.fields.Type != MRoomMember { + return nil, fmt.Errorf("gomatrixserverlib: not an m.room.member event") + } + var content memberContent + if err := json.Unmarshal(e.fields.Content, &content); err != nil { + return nil, err + } + return &content.Membership, nil +} + // AuthEvents returns references to the events needed to auth the event. func (e Event) AuthEvents() []EventReference { return e.fields.AuthEvents } +// AuthEventIDs returns the event IDs of the events needed to auth the event. +func (e Event) AuthEventIDs() []string { + result := make([]string, len(e.fields.PrevEvents)) + for i := range e.fields.PrevEvents { + result[i] = e.fields.PrevEvents[i].EventID + } + return result +} + // Redacts returns the event ID of the event this event redacts. func (e Event) Redacts() string { return e.fields.Redacts @@ -534,3 +569,19 @@ func (er EventReference) MarshalJSON() ([]byte, error) { return json.Marshal(&tuple) } + +// ParseID splits a matrix ID into a local part and a server name. +func ParseID(sigil byte, id string) (local string, domain ServerName, err error) { + // IDs have the format: SIGIL LOCALPART ":" DOMAIN + // Split on the first ":" character since the domain can contain ":" + // characters. + if len(id) == 0 || id[0] != sigil { + return "", "", fmt.Errorf("gomatriserverlib: invalid ID %q doesn't start with %q", id, sigil) + } + parts := strings.SplitN(id, ":", 2) + if len(parts) != 2 { + // The ID must have a ":" character. + return "", "", fmt.Errorf("gomatrixserverlib: invalid ID %q missing ':'", id) + } + return parts[0][1:], ServerName(parts[1]), nil +}