diff options
author | Brendan Abolivier <contact@brendanabolivier.com> | 2017-09-08 15:17:12 +0100 |
---|---|---|
committer | Mark Haines <mjark@negativecurvature.net> | 2017-09-08 15:17:12 +0100 |
commit | 4d1d503d43232192d9581c498af0aaf71afb7f81 (patch) | |
tree | 04ffc2ef8fc8a32c3c41bf9837b43589e8e1fdc8 /src | |
parent | fad997303b96885eb8ee5365710d9bce91003b52 (diff) |
Processing of pending invites on 3PID binding (#218)
* Add missing file headers
* Move the ID server's signatures verification to common
* Allow verification without specifying a server name
* Add third-party structs to membership events content
* Add processing of 3PID onbind requests
* Use reference for third party invite data
* Fix return arguments order
* Revert "Move the ID server's signatures verification to common"
This reverts commit 93442010316ce71a77ac58ffd3613754ce8fe969.
* Revert "Allow verification without specifying a server name"
This reverts commit fd27afbf82eac50fe9f7b83b26cfce3c66d530d2.
* Remove checks that are already occurring in gomatrixserverlib
* Change return type of createInviteFrom3PIDInvite
* Add doc, add checks in fillDisplayName
* Use MakeFedAPI
* Invert condition
* Use AuthEvents to retrieve the 3PID invite
* Update comment
* Remove unused parameter
* gb vendor update github.com/matrix-org/gomatrixserverlib
Diffstat (limited to 'src')
5 files changed, 245 insertions, 5 deletions
diff --git a/src/github.com/matrix-org/dendrite/common/eventcontent.go b/src/github.com/matrix-org/dendrite/common/eventcontent.go index 0dfb37a1..971c4f0a 100644 --- a/src/github.com/matrix-org/dendrite/common/eventcontent.go +++ b/src/github.com/matrix-org/dendrite/common/eventcontent.go @@ -22,11 +22,24 @@ type CreateContent struct { // MemberContent is the event content for http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-member type MemberContent struct { - Membership string `json:"membership"` - DisplayName string `json:"displayname,omitempty"` - AvatarURL string `json:"avatar_url,omitempty"` - Reason string `json:"reason,omitempty"` - // TODO: ThirdPartyInvite string `json:"third_party_invite,omitempty"` + Membership string `json:"membership"` + DisplayName string `json:"displayname,omitempty"` + AvatarURL string `json:"avatar_url,omitempty"` + Reason string `json:"reason,omitempty"` + ThirdPartyInvite *TPInvite `json:"third_party_invite,omitempty"` +} + +// TPInvite is the "Invite" structure defined at http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-member +type TPInvite struct { + DisplayName string `json:"display_name"` + Signed TPInviteSigned `json:"signed"` +} + +// TPInviteSigned is the "signed" structure defined at http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-member +type TPInviteSigned struct { + MXID string `json:"mxid"` + Signatures map[string]map[string]string `json:"signatures"` + Token string `json:"token"` } // ThirdPartyInviteContent is the content event for https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-third-party-invite diff --git a/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go b/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go index b4d01dab..8d49800d 100644 --- a/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go +++ b/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go @@ -79,6 +79,13 @@ func Setup( }, )) + v1fedmux.Handle("/3pid/onbind", common.MakeFedAPI( + "3pid_onbind", cfg.Matrix.ServerName, keys, + func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { + return writers.CreateInvitesFrom3PIDInvites(httpReq, query, cfg, producer) + }, + )) + v1fedmux.Handle("/event/{eventID}", common.MakeFedAPI( "federation_get_event", cfg.Matrix.ServerName, keys, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse { diff --git a/src/github.com/matrix-org/dendrite/federationapi/writers/invite.go b/src/github.com/matrix-org/dendrite/federationapi/writers/invite.go index 03972d36..20048103 100644 --- a/src/github.com/matrix-org/dendrite/federationapi/writers/invite.go +++ b/src/github.com/matrix-org/dendrite/federationapi/writers/invite.go @@ -1,3 +1,17 @@ +// Copyright 2017 Vector Creations Ltd +// +// 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 writers import ( 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 f253162b..cd276f52 100644 --- a/src/github.com/matrix-org/dendrite/federationapi/writers/send.go +++ b/src/github.com/matrix-org/dendrite/federationapi/writers/send.go @@ -1,3 +1,17 @@ +// Copyright 2017 Vector Creations Ltd +// +// 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 writers import ( diff --git a/src/github.com/matrix-org/dendrite/federationapi/writers/threepid.go b/src/github.com/matrix-org/dendrite/federationapi/writers/threepid.go new file mode 100644 index 00000000..ad9b4856 --- /dev/null +++ b/src/github.com/matrix-org/dendrite/federationapi/writers/threepid.go @@ -0,0 +1,192 @@ +// Copyright 2017 Vector Creations Ltd +// +// 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 writers + +import ( + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/matrix-org/dendrite/clientapi/httputil" + "github.com/matrix-org/dendrite/clientapi/producers" + "github.com/matrix-org/dendrite/common" + "github.com/matrix-org/dendrite/common/config" + "github.com/matrix-org/dendrite/roomserver/api" + + "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/util" +) + +type invite struct { + MXID string `json:"mxid"` + RoomID string `json:"room_id"` + Sender string `json:"sender"` + Token string `json:"token"` + Signed common.TPInviteSigned `json:"signed"` +} + +type invites struct { + Medium string `json:"medium"` + Address string `json:"address"` + MXID string `json:"mxid"` + Invites []invite `json:"invites"` +} + +// CreateInvitesFrom3PIDInvites implements POST /_matrix/federation/v1/3pid/onbind +func CreateInvitesFrom3PIDInvites( + req *http.Request, queryAPI api.RoomserverQueryAPI, cfg config.Dendrite, + producer *producers.RoomserverProducer, +) util.JSONResponse { + var body invites + if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil { + return *reqErr + } + + evs := []gomatrixserverlib.Event{} + for _, inv := range body.Invites { + event, err := createInviteFrom3PIDInvite(queryAPI, cfg, inv) + if err != nil { + return httputil.LogThenError(req, err) + } + if event != nil { + evs = append(evs, *event) + } + } + + // Send all the events + if err := producer.SendEvents(evs, cfg.Matrix.ServerName); err != nil { + return httputil.LogThenError(req, err) + } + + return util.JSONResponse{ + Code: 200, + JSON: struct{}{}, + } +} + +// createInviteFrom3PIDInvite processes an invite provided by the identity server +// and creates a m.room.member event (with "invite" membership) from it. +// Returns an error if there was a problem building the event or fetching the +// necessary data to do so. +func createInviteFrom3PIDInvite( + queryAPI api.RoomserverQueryAPI, cfg config.Dendrite, inv invite, +) (*gomatrixserverlib.Event, error) { + // Build the event + builder := &gomatrixserverlib.EventBuilder{ + Type: "m.room.member", + Sender: inv.Sender, + RoomID: inv.RoomID, + StateKey: &inv.MXID, + } + + content := common.MemberContent{ + // TODO: Load the profile + Membership: "invite", + ThirdPartyInvite: &common.TPInvite{ + Signed: inv.Signed, + }, + } + + if err := builder.SetContent(content); err != nil { + return nil, err + } + + eventsNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(builder) + if err != nil { + return nil, err + } + + // Ask the roomserver for information about this room + queryReq := api.QueryLatestEventsAndStateRequest{ + RoomID: builder.RoomID, + StateToFetch: eventsNeeded.Tuples(), + } + var queryRes api.QueryLatestEventsAndStateResponse + if err = queryAPI.QueryLatestEventsAndState(&queryReq, &queryRes); err != nil { + return nil, err + } + + if !queryRes.RoomExists { + // TODO: Use federation to auth the event + return nil, nil + } + + // Finish building the event + builder.Depth = queryRes.Depth + builder.PrevEvents = queryRes.LatestEvents + + authEvents := gomatrixserverlib.NewAuthEvents(nil) + + for i := range queryRes.StateEvents { + authEvents.AddEvent(&queryRes.StateEvents[i]) + } + + if err = fillDisplayName(builder, content, authEvents); err != nil { + return nil, err + } + + refs, err := eventsNeeded.AuthEventReferences(&authEvents) + if err != nil { + return nil, err + } + builder.AuthEvents = refs + + eventID := fmt.Sprintf("$%s:%s", util.RandomString(16), cfg.Matrix.ServerName) + now := time.Now() + event, err := builder.Build(eventID, now, cfg.Matrix.ServerName, cfg.Matrix.KeyID, cfg.Matrix.PrivateKey) + if err != nil { + return nil, err + } + + return &event, nil +} + +// fillDisplayName looks in a list of auth events for a m.room.third_party_invite +// event with the state key matching a given m.room.member event's content's token. +// If such an event is found, fills the "display_name" attribute of the +// "third_party_invite" structure in the m.room.member event with the display_name +// from the m.room.third_party_invite event. +// Returns an error if there was a problem parsing the m.room.third_party_invite +// event's content or updating the m.room.member event's content. +// Returns nil if no m.room.third_party_invite with a matching token could be +// found. Returning an error isn't necessary in this case as the event will be +// rejected by gomatrixserverlib. +func fillDisplayName( + builder *gomatrixserverlib.EventBuilder, content common.MemberContent, + authEvents gomatrixserverlib.AuthEvents, +) error { + // Look for the m.room.third_party_invite event + thirdPartyInviteEvent, _ := authEvents.ThirdPartyInvite(content.ThirdPartyInvite.Signed.Token) + + if thirdPartyInviteEvent == nil { + // If the third party invite event doesn't exist then we can't use it to set the display name. + return nil + } + + var thirdPartyInviteContent common.ThirdPartyInviteContent + if err := json.Unmarshal(thirdPartyInviteEvent.Content(), &thirdPartyInviteContent); err != nil { + return err + } + + // Use the m.room.third_party_invite event to fill the "displayname" and + // update the m.room.member event's content with it + content.ThirdPartyInvite.DisplayName = thirdPartyInviteContent.DisplayName + if err := builder.SetContent(content); err != nil { + return err + } + + return nil +} |