diff --git a/src/github.com/matrix-org/dendrite/clientapi/httputil/parse.go b/src/github.com/matrix-org/dendrite/clientapi/httputil/parse.go new file mode 100644 index 000000000..754fa2427 --- /dev/null +++ b/src/github.com/matrix-org/dendrite/clientapi/httputil/parse.go @@ -0,0 +1,38 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package httputil + +import ( + "net/http" + "strconv" + "time" +) + +// ParseTSParam takes a req (typically from an application service) and parses a Time object +// from the req if it exists in the query parameters. If it doesn't exist, the +// current time is returned. +func ParseTSParam(req *http.Request) time.Time { + // Use the ts parameter's value for event time if present + tsStr := req.URL.Query().Get("ts") + if tsStr == "" { + return time.Now() + } + + // The parameter exists, parse into a Time object + ts, err := strconv.ParseInt(tsStr, 10, 64) + if err != nil { + return time.Unix(ts/1000, 0) + } + + return time.Unix(ts/1000, 0) +} diff --git a/src/github.com/matrix-org/dendrite/clientapi/routing/createroom.go b/src/github.com/matrix-org/dendrite/clientapi/routing/createroom.go index 06d768200..9924f9725 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/routing/createroom.go +++ b/src/github.com/matrix-org/dendrite/clientapi/routing/createroom.go @@ -18,6 +18,7 @@ import ( "fmt" "net/http" "strings" + "time" "github.com/matrix-org/dendrite/roomserver/api" @@ -143,8 +144,8 @@ func createRoom( return *resErr } + evTime := httputil.ParseTSParam(req) // TODO: visibility/presets/raw initial state/creation content - // TODO: Create room alias association // Make sure this doesn't fall into an application service's namespace though! @@ -249,7 +250,7 @@ func createRoom( builder.PrevEvents = []gomatrixserverlib.EventReference{builtEvents[i-1].EventReference()} } var ev *gomatrixserverlib.Event - ev, err = buildEvent(req, &builder, &authEvents, cfg) + ev, err = buildEvent(&builder, &authEvents, cfg, evTime) if err != nil { return httputil.LogThenError(req, err) } @@ -309,12 +310,11 @@ func createRoom( // buildEvent fills out auth_events for the builder then builds the event func buildEvent( - req *http.Request, builder *gomatrixserverlib.EventBuilder, provider gomatrixserverlib.AuthEventProvider, cfg config.Dendrite, + evTime time.Time, ) (*gomatrixserverlib.Event, error) { - eventsNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(builder) if err != nil { return nil, err @@ -325,8 +325,7 @@ func buildEvent( } builder.AuthEvents = refs eventID := fmt.Sprintf("$%s:%s", util.RandomString(16), cfg.Matrix.ServerName) - eventTime := common.ParseTSParam(req) - event, err := builder.Build(eventID, eventTime, cfg.Matrix.ServerName, cfg.Matrix.KeyID, cfg.Matrix.PrivateKey) + event, err := builder.Build(eventID, evTime, cfg.Matrix.ServerName, cfg.Matrix.KeyID, cfg.Matrix.PrivateKey) if err != nil { return nil, fmt.Errorf("cannot build event %s : Builder failed to build. %s", builder.Type, err) } diff --git a/src/github.com/matrix-org/dendrite/clientapi/routing/joinroom.go b/src/github.com/matrix-org/dendrite/clientapi/routing/joinroom.go index 84c1f24c9..be4647aa1 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/routing/joinroom.go +++ b/src/github.com/matrix-org/dendrite/clientapi/routing/joinroom.go @@ -213,8 +213,9 @@ func (r joinRoomReq) joinRoomUsingServers( return httputil.LogThenError(r.req, err) } + evTime := httputil.ParseTSParam(r.req) var queryRes roomserverAPI.QueryLatestEventsAndStateResponse - event, err := common.BuildEvent(r.req, &eb, r.cfg, r.queryAPI, &queryRes) + event, err := common.BuildEvent(r.req.Context(), &eb, r.cfg, evTime, r.queryAPI, &queryRes) if err == nil { if _, err = r.producer.SendEvents(r.req.Context(), []gomatrixserverlib.Event{*event}, r.cfg.Matrix.ServerName, nil); err != nil { return httputil.LogThenError(r.req, err) @@ -284,10 +285,10 @@ func (r joinRoomReq) joinRoomUsingServer(roomID string, server gomatrixserverlib return nil, err } + evTime := httputil.ParseTSParam(r.req) eventID := fmt.Sprintf("$%s:%s", util.RandomString(16), r.cfg.Matrix.ServerName) - eventTime := common.ParseTSParam(r.req) event, err := respMakeJoin.JoinEvent.Build( - eventID, eventTime, r.cfg.Matrix.ServerName, r.cfg.Matrix.KeyID, r.cfg.Matrix.PrivateKey, + eventID, evTime, r.cfg.Matrix.ServerName, r.cfg.Matrix.KeyID, r.cfg.Matrix.PrivateKey, ) if err != nil { res := httputil.LogThenError(r.req, err) diff --git a/src/github.com/matrix-org/dendrite/clientapi/routing/membership.go b/src/github.com/matrix-org/dendrite/clientapi/routing/membership.go index cf4d075eb..d134b9fb1 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/routing/membership.go +++ b/src/github.com/matrix-org/dendrite/clientapi/routing/membership.go @@ -18,6 +18,7 @@ import ( "context" "errors" "net/http" + "time" "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts" @@ -47,8 +48,10 @@ func SendMembership( return *reqErr } + evTime := httputil.ParseTSParam(req) inviteStored, err := threepid.CheckAndProcessInvite( - req, device, &body, cfg, queryAPI, accountDB, producer, membership, roomID, + req.Context(), device, &body, cfg, queryAPI, accountDB, producer, + membership, roomID, evTime, ) if err == threepid.ErrMissingParameter { return util.JSONResponse{ @@ -80,7 +83,7 @@ func SendMembership( } event, err := buildMembershipEvent( - req, body, accountDB, device, membership, roomID, cfg, queryAPI, + req.Context(), body, accountDB, device, membership, roomID, cfg, evTime, queryAPI, ) if err == errMissingUserID { return util.JSONResponse{ @@ -109,17 +112,17 @@ func SendMembership( } func buildMembershipEvent( - req *http.Request, + ctx context.Context, body threepid.MembershipRequest, accountDB *accounts.Database, device *authtypes.Device, membership string, roomID string, cfg config.Dendrite, - queryAPI api.RoomserverQueryAPI, + evTime time.Time, queryAPI api.RoomserverQueryAPI, ) (*gomatrixserverlib.Event, error) { stateKey, reason, err := getMembershipStateKey(body, device, membership) if err != nil { return nil, err } - profile, err := loadProfile(req.Context(), stateKey, cfg, accountDB) + profile, err := loadProfile(ctx, stateKey, cfg, accountDB) if err != nil { return nil, err } @@ -147,7 +150,7 @@ func buildMembershipEvent( return nil, err } - return common.BuildEvent(req, &builder, cfg, queryAPI, nil) + return common.BuildEvent(ctx, &builder, cfg, evTime, queryAPI, nil) } // loadProfile lookups the profile of a given user from the database and returns diff --git a/src/github.com/matrix-org/dendrite/clientapi/routing/profile.go b/src/github.com/matrix-org/dendrite/clientapi/routing/profile.go index 35b7226ac..2cb60896c 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/routing/profile.go +++ b/src/github.com/matrix-org/dendrite/clientapi/routing/profile.go @@ -15,8 +15,10 @@ package routing import ( + "context" "database/sql" "net/http" + "time" "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts" @@ -150,7 +152,9 @@ func SetAvatarURL( AvatarURL: r.AvatarURL, } - events, err := buildMembershipEvents(req, memberships, newProfile, userID, cfg, queryAPI) + events, err := buildMembershipEvents( + req.Context(), memberships, newProfile, userID, cfg, httputil.ParseTSParam(req), queryAPI, + ) if err != nil { return httputil.LogThenError(req, err) } @@ -238,7 +242,9 @@ func SetDisplayName( AvatarURL: oldProfile.AvatarURL, } - events, err := buildMembershipEvents(req, memberships, newProfile, userID, cfg, queryAPI) + events, err := buildMembershipEvents( + req.Context(), memberships, newProfile, userID, cfg, httputil.ParseTSParam(req), queryAPI, + ) if err != nil { return httputil.LogThenError(req, err) } @@ -258,10 +264,10 @@ func SetDisplayName( } func buildMembershipEvents( - req *http.Request, + ctx context.Context, memberships []authtypes.Membership, newProfile authtypes.Profile, userID string, cfg *config.Dendrite, - queryAPI api.RoomserverQueryAPI, + evTime time.Time, queryAPI api.RoomserverQueryAPI, ) ([]gomatrixserverlib.Event, error) { evs := []gomatrixserverlib.Event{} @@ -284,7 +290,7 @@ func buildMembershipEvents( return nil, err } - event, err := common.BuildEvent(req, &builder, *cfg, queryAPI, nil) + event, err := common.BuildEvent(ctx, &builder, *cfg, evTime, queryAPI, nil) if err != nil { return nil, err } diff --git a/src/github.com/matrix-org/dendrite/clientapi/routing/sendevent.go b/src/github.com/matrix-org/dendrite/clientapi/routing/sendevent.go index 52d2b107f..9176f4c87 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/routing/sendevent.go +++ b/src/github.com/matrix-org/dendrite/clientapi/routing/sendevent.go @@ -63,6 +63,8 @@ func SendEvent( return *resErr } + evTime := httputil.ParseTSParam(req) + // create the new event and set all the fields we can builder := gomatrixserverlib.EventBuilder{ Sender: userID, @@ -76,7 +78,7 @@ func SendEvent( } var queryRes api.QueryLatestEventsAndStateResponse - e, err := common.BuildEvent(req, &builder, cfg, queryAPI, &queryRes) + e, err := common.BuildEvent(req.Context(), &builder, cfg, evTime, queryAPI, &queryRes) if err == common.ErrRoomNoExists { return util.JSONResponse{ Code: http.StatusNotFound, diff --git a/src/github.com/matrix-org/dendrite/clientapi/threepid/invites.go b/src/github.com/matrix-org/dendrite/clientapi/threepid/invites.go index 44c0c9a13..2538577fd 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/threepid/invites.go +++ b/src/github.com/matrix-org/dendrite/clientapi/threepid/invites.go @@ -85,10 +85,11 @@ var ( // fills the Matrix ID in the request body so a normal invite membership event // can be emitted. func CheckAndProcessInvite( - req *http.Request, + ctx context.Context, device *authtypes.Device, body *MembershipRequest, cfg config.Dendrite, queryAPI api.RoomserverQueryAPI, db *accounts.Database, producer *producers.RoomserverProducer, membership string, roomID string, + evTime time.Time, ) (inviteStoredOnIDServer bool, err error) { if membership != "invite" || (body.Address == "" && body.IDServer == "" && body.Medium == "") { // If none of the 3PID-specific fields are supplied, it's a standard invite @@ -101,7 +102,7 @@ func CheckAndProcessInvite( return } - lookupRes, storeInviteRes, err := queryIDServer(req.Context(), db, cfg, device, body, roomID) + lookupRes, storeInviteRes, err := queryIDServer(ctx, db, cfg, device, body, roomID) if err != nil { return } @@ -110,7 +111,9 @@ func CheckAndProcessInvite( // No Matrix ID could be found for this 3PID, meaning that a // "m.room.third_party_invite" have to be emitted from the data in // storeInviteRes. - err = emit3PIDInviteEvent(req, body, storeInviteRes, device, roomID, cfg, queryAPI, producer) + err = emit3PIDInviteEvent( + ctx, body, storeInviteRes, device, roomID, cfg, queryAPI, producer, evTime, + ) inviteStoredOnIDServer = err == nil return @@ -325,10 +328,11 @@ func checkIDServerSignatures( // emit3PIDInviteEvent builds and sends a "m.room.third_party_invite" event. // Returns an error if something failed in the process. func emit3PIDInviteEvent( - req *http.Request, + ctx context.Context, body *MembershipRequest, res *idServerStoreInviteResponse, device *authtypes.Device, roomID string, cfg config.Dendrite, queryAPI api.RoomserverQueryAPI, producer *producers.RoomserverProducer, + evTime time.Time, ) error { builder := &gomatrixserverlib.EventBuilder{ Sender: device.UserID, @@ -350,11 +354,11 @@ func emit3PIDInviteEvent( } var queryRes *api.QueryLatestEventsAndStateResponse - event, err := common.BuildEvent(req, builder, cfg, queryAPI, queryRes) + event, err := common.BuildEvent(ctx, builder, cfg, evTime, queryAPI, queryRes) if err != nil { return err } - _, err = producer.SendEvents(req.Context(), []gomatrixserverlib.Event{*event}, cfg.Matrix.ServerName, nil) + _, err = producer.SendEvents(ctx, []gomatrixserverlib.Event{*event}, cfg.Matrix.ServerName, nil) return err } diff --git a/src/github.com/matrix-org/dendrite/common/events.go b/src/github.com/matrix-org/dendrite/common/events.go index 41022c7ce..5c87c0e56 100644 --- a/src/github.com/matrix-org/dendrite/common/events.go +++ b/src/github.com/matrix-org/dendrite/common/events.go @@ -18,8 +18,6 @@ import ( "context" "errors" "fmt" - "net/http" - "strconv" "time" "github.com/matrix-org/dendrite/common/config" @@ -40,18 +38,17 @@ var ErrRoomNoExists = errors.New("Room does not exist") // the room doesn't exist // Returns an error if something else went wrong func BuildEvent( - req *http.Request, - builder *gomatrixserverlib.EventBuilder, cfg config.Dendrite, + ctx context.Context, + builder *gomatrixserverlib.EventBuilder, cfg config.Dendrite, evTime time.Time, queryAPI api.RoomserverQueryAPI, queryRes *api.QueryLatestEventsAndStateResponse, ) (*gomatrixserverlib.Event, error) { - err := AddPrevEventsToEvent(req.Context(), builder, queryAPI, queryRes) + err := AddPrevEventsToEvent(ctx, builder, queryAPI, queryRes) if err != nil { return nil, err } eventID := fmt.Sprintf("$%s:%s", util.RandomString(16), cfg.Matrix.ServerName) - eventTime := ParseTSParam(req) - event, err := builder.Build(eventID, eventTime, cfg.Matrix.ServerName, cfg.Matrix.KeyID, cfg.Matrix.PrivateKey) + event, err := builder.Build(eventID, evTime, cfg.Matrix.ServerName, cfg.Matrix.KeyID, cfg.Matrix.PrivateKey) if err != nil { return nil, err } @@ -59,25 +56,6 @@ func BuildEvent( return &event, nil } -// ParseTSParam takes a req from an application service and parses a Time object -// from the req if it exists in the query parameters. If it doesn't exist, the -// current time is returned. -func ParseTSParam(req *http.Request) time.Time { - // Use the ts parameter's value for event time if present - tsStr := req.URL.Query().Get("ts") - if tsStr == "" { - return time.Now() - } - - // The parameter exists, parse into a Time object - ts, err := strconv.ParseInt(tsStr, 10, 64) - if err != nil { - return time.Unix(ts/1000, 0) - } - - return time.Unix(ts/1000, 0) -} - // AddPrevEventsToEvent fills out the prev_events and auth_events fields in builder func AddPrevEventsToEvent( ctx context.Context, diff --git a/src/github.com/matrix-org/dendrite/federationapi/routing/join.go b/src/github.com/matrix-org/dendrite/federationapi/routing/join.go index 6df049bd3..0b60408f7 100644 --- a/src/github.com/matrix-org/dendrite/federationapi/routing/join.go +++ b/src/github.com/matrix-org/dendrite/federationapi/routing/join.go @@ -17,6 +17,7 @@ package routing import ( "encoding/json" "net/http" + "time" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" @@ -63,7 +64,7 @@ func MakeJoin( } var queryRes api.QueryLatestEventsAndStateResponse - event, err := common.BuildEvent(httpReq, &builder, cfg, query, &queryRes) + event, err := common.BuildEvent(httpReq.Context(), &builder, cfg, time.Now(), query, &queryRes) if err == common.ErrRoomNoExists { return util.JSONResponse{ Code: http.StatusNotFound, diff --git a/src/github.com/matrix-org/dendrite/federationapi/routing/leave.go b/src/github.com/matrix-org/dendrite/federationapi/routing/leave.go index c2e78fb63..3c57d39d1 100644 --- a/src/github.com/matrix-org/dendrite/federationapi/routing/leave.go +++ b/src/github.com/matrix-org/dendrite/federationapi/routing/leave.go @@ -15,6 +15,7 @@ package routing import ( "encoding/json" "net/http" + "time" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" @@ -61,7 +62,7 @@ func MakeLeave( } var queryRes api.QueryLatestEventsAndStateResponse - event, err := common.BuildEvent(httpReq, &builder, cfg, query, &queryRes) + event, err := common.BuildEvent(httpReq.Context(), &builder, cfg, time.Now(), query, &queryRes) if err == common.ErrRoomNoExists { return util.JSONResponse{ Code: http.StatusNotFound, diff --git a/src/github.com/matrix-org/dendrite/federationapi/routing/threepid.go b/src/github.com/matrix-org/dendrite/federationapi/routing/threepid.go index 606190a76..06bebc62f 100644 --- a/src/github.com/matrix-org/dendrite/federationapi/routing/threepid.go +++ b/src/github.com/matrix-org/dendrite/federationapi/routing/threepid.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "net/http" + "time" "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts" "github.com/matrix-org/dendrite/clientapi/httputil" @@ -69,7 +70,7 @@ func CreateInvitesFrom3PIDInvites( evs := []gomatrixserverlib.Event{} for _, inv := range body.Invites { event, err := createInviteFrom3PIDInvite( - req, queryAPI, cfg, inv, federation, accountDB, + req.Context(), queryAPI, cfg, inv, federation, accountDB, ) if err != nil { return httputil.LogThenError(req, err) @@ -134,7 +135,7 @@ func ExchangeThirdPartyInvite( } // Auth and build the event from what the remote server sent us - event, err := buildMembershipEvent(httpReq, &builder, queryAPI, cfg) + event, err := buildMembershipEvent(httpReq.Context(), &builder, queryAPI, cfg) if err == errNotInRoom { return util.JSONResponse{ Code: http.StatusNotFound, @@ -169,7 +170,7 @@ func ExchangeThirdPartyInvite( // Returns an error if there was a problem building the event or fetching the // necessary data to do so. func createInviteFrom3PIDInvite( - req *http.Request, queryAPI api.RoomserverQueryAPI, cfg config.Dendrite, + ctx context.Context, queryAPI api.RoomserverQueryAPI, cfg config.Dendrite, inv invite, federation *gomatrixserverlib.FederationClient, accountDB *accounts.Database, ) (*gomatrixserverlib.Event, error) { @@ -190,7 +191,7 @@ func createInviteFrom3PIDInvite( StateKey: &inv.MXID, } - profile, err := accountDB.GetProfileByLocalpart(req.Context(), localpart) + profile, err := accountDB.GetProfileByLocalpart(ctx, localpart) if err != nil { return nil, err } @@ -208,9 +209,9 @@ func createInviteFrom3PIDInvite( return nil, err } - event, err := buildMembershipEvent(req, builder, queryAPI, cfg) + event, err := buildMembershipEvent(ctx, builder, queryAPI, cfg) if err == errNotInRoom { - return nil, sendToRemoteServer(req.Context(), inv, federation, cfg, *builder) + return nil, sendToRemoteServer(ctx, inv, federation, cfg, *builder) } if err != nil { return nil, err @@ -225,7 +226,7 @@ func createInviteFrom3PIDInvite( // Returns errNotInRoom if the server is not in the room the invite is for. // Returns an error if something failed during the process. func buildMembershipEvent( - req *http.Request, + ctx context.Context, builder *gomatrixserverlib.EventBuilder, queryAPI api.RoomserverQueryAPI, cfg config.Dendrite, ) (*gomatrixserverlib.Event, error) { @@ -240,7 +241,7 @@ func buildMembershipEvent( StateToFetch: eventsNeeded.Tuples(), } var queryRes api.QueryLatestEventsAndStateResponse - if err = queryAPI.QueryLatestEventsAndState(req.Context(), &queryReq, &queryRes); err != nil { + if err = queryAPI.QueryLatestEventsAndState(ctx, &queryReq, &queryRes); err != nil { return nil, err } @@ -273,8 +274,9 @@ func buildMembershipEvent( builder.AuthEvents = refs eventID := fmt.Sprintf("$%s:%s", util.RandomString(16), cfg.Matrix.ServerName) - eventTime := common.ParseTSParam(req) - event, err := builder.Build(eventID, eventTime, cfg.Matrix.ServerName, cfg.Matrix.KeyID, cfg.Matrix.PrivateKey) + event, err := builder.Build( + eventID, time.Now(), cfg.Matrix.ServerName, cfg.Matrix.KeyID, cfg.Matrix.PrivateKey, + ) return &event, err }