diff --git a/clientapi/routing/auth_fallback.go b/clientapi/routing/auth_fallback.go new file mode 100644 index 000000000..cd4530d1b --- /dev/null +++ b/clientapi/routing/auth_fallback.go @@ -0,0 +1,210 @@ +// Copyright 2019 Parminder Singh +// +// 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 routing + +import ( + "html/template" + "net/http" + + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" + "github.com/matrix-org/dendrite/clientapi/httputil" + "github.com/matrix-org/dendrite/clientapi/jsonerror" + "github.com/matrix-org/dendrite/common/config" + "github.com/matrix-org/util" +) + +// recaptchaTemplate is an HTML webpage template for recaptcha auth +const recaptchaTemplate = ` + + +Authentication + + + + + + +
+
+

+ Hello! We need to prevent computer programs and other automated + things from creating accounts on this server. +

+

+ Please verify that you're not a robot. +

+ +
+
+ +
+ +
+ + +` + +// successTemplate is an HTML template presented to the user after successful +// recaptcha completion +const successTemplate = ` + + +Success! + + + + +
+

Thank you!

+

You may now close this window and return to the application.

+
+ + +` + +// serveTemplate fills template data and serves it using http.ResponseWriter +func serveTemplate(w http.ResponseWriter, templateHTML string, data map[string]string) { + t := template.Must(template.New("response").Parse(templateHTML)) + if err := t.Execute(w, data); err != nil { + panic(err) + } +} + +// AuthFallback implements GET and POST /auth/{authType}/fallback/web?session={sessionID} +func AuthFallback( + w http.ResponseWriter, req *http.Request, authType string, + cfg config.Dendrite, +) *util.JSONResponse { + sessionID := req.URL.Query().Get("session") + + if sessionID == "" { + return writeHTTPMessage(w, req, + "Session ID not provided", + http.StatusBadRequest, + ) + } + + serveRecaptcha := func() { + data := map[string]string{ + "myUrl": req.URL.String(), + "session": sessionID, + "siteKey": cfg.Matrix.RecaptchaPublicKey, + } + serveTemplate(w, recaptchaTemplate, data) + } + + serveSuccess := func() { + data := map[string]string{} + serveTemplate(w, successTemplate, data) + } + + if req.Method == http.MethodGet { + // Handle Recaptcha + if authType == authtypes.LoginTypeRecaptcha { + if err := checkRecaptchaEnabled(&cfg, w, req); err != nil { + return err + } + + serveRecaptcha() + return nil + } + return &util.JSONResponse{ + Code: http.StatusNotFound, + JSON: jsonerror.NotFound("Unknown auth stage type"), + } + } else if req.Method == http.MethodPost { + // Handle Recaptcha + if authType == authtypes.LoginTypeRecaptcha { + if err := checkRecaptchaEnabled(&cfg, w, req); err != nil { + return err + } + + clientIP := req.RemoteAddr + err := req.ParseForm() + if err != nil { + res := httputil.LogThenError(req, err) + return &res + } + + response := req.Form.Get("g-recaptcha-response") + if err := validateRecaptcha(&cfg, response, clientIP); err != nil { + util.GetLogger(req.Context()).Error(err) + return err + } + + // Success. Add recaptcha as a completed login flow + AddCompletedSessionStage(sessionID, authtypes.LoginTypeRecaptcha) + + serveSuccess() + return nil + } + + return &util.JSONResponse{ + Code: http.StatusNotFound, + JSON: jsonerror.NotFound("Unknown auth stage type"), + } + } + return &util.JSONResponse{ + Code: http.StatusMethodNotAllowed, + JSON: jsonerror.NotFound("Bad method"), + } +} + +// checkRecaptchaEnabled creates an error response if recaptcha is not usable on homeserver. +func checkRecaptchaEnabled( + cfg *config.Dendrite, + w http.ResponseWriter, + req *http.Request, +) *util.JSONResponse { + if !cfg.Matrix.RecaptchaEnabled { + return writeHTTPMessage(w, req, + "Recaptcha login is disabled on this Homeserver", + http.StatusBadRequest, + ) + } + return nil +} + +// writeHTTPMessage writes the given header and message to the HTTP response writer. +// Returns an error JSONResponse obtained through httputil.LogThenError if the writing failed, otherwise nil. +func writeHTTPMessage( + w http.ResponseWriter, req *http.Request, + message string, header int, +) *util.JSONResponse { + w.WriteHeader(header) + _, err := w.Write([]byte(message)) + if err != nil { + res := httputil.LogThenError(req, err) + return &res + } + return nil +} diff --git a/clientapi/routing/createroom.go b/clientapi/routing/createroom.go index 4a76e1b06..620246d28 100644 --- a/clientapi/routing/createroom.go +++ b/clientapi/routing/createroom.go @@ -106,7 +106,7 @@ func (r createRoomRequest) Validate() *util.JSONResponse { } } - var CreationContent common.CreateContent + var CreationContent gomatrixserverlib.CreateContent err = json.Unmarshal(creationContentBytes, &CreationContent) if err != nil { return &util.JSONResponse{ @@ -196,7 +196,7 @@ func createRoom( return httputil.LogThenError(req, err) } - membershipContent := common.MemberContent{ + membershipContent := gomatrixserverlib.MemberContent{ Membership: gomatrixserverlib.Join, DisplayName: profile.DisplayName, AvatarURL: profile.AvatarURL, @@ -246,7 +246,7 @@ func createRoom( {"m.room.member", userID, membershipContent}, {"m.room.power_levels", "", common.InitialPowerLevelsContent(userID)}, // TODO: m.room.canonical_alias - {"m.room.join_rules", "", common.JoinRulesContent{JoinRule: joinRules}}, + {"m.room.join_rules", "", gomatrixserverlib.JoinRuleContent{JoinRule: joinRules}}, {"m.room.history_visibility", "", common.HistoryVisibilityContent{HistoryVisibility: historyVisibility}}, } if r.GuestCanJoin { diff --git a/clientapi/routing/membership.go b/clientapi/routing/membership.go index 5e183fa0f..c71ac2de2 100644 --- a/clientapi/routing/membership.go +++ b/clientapi/routing/membership.go @@ -144,7 +144,7 @@ func buildMembershipEvent( membership = gomatrixserverlib.Leave } - content := common.MemberContent{ + content := gomatrixserverlib.MemberContent{ Membership: membership, DisplayName: profile.DisplayName, AvatarURL: profile.AvatarURL, diff --git a/clientapi/routing/profile.go b/clientapi/routing/profile.go index e8ea6cf13..a87c6f743 100644 --- a/clientapi/routing/profile.go +++ b/clientapi/routing/profile.go @@ -332,7 +332,7 @@ func buildMembershipEvents( StateKey: &userID, } - content := common.MemberContent{ + content := gomatrixserverlib.MemberContent{ Membership: gomatrixserverlib.Join, } diff --git a/clientapi/routing/register.go b/clientapi/routing/register.go index c5a3d3018..d0f36a6fd 100644 --- a/clientapi/routing/register.go +++ b/clientapi/routing/register.go @@ -29,6 +29,7 @@ import ( "sort" "strconv" "strings" + "sync" "time" "github.com/matrix-org/dendrite/common/config" @@ -70,12 +71,17 @@ func init() { } // sessionsDict keeps track of completed auth stages for each session. +// It shouldn't be passed by value because it contains a mutex. type sessionsDict struct { + sync.Mutex sessions map[string][]authtypes.LoginType } // GetCompletedStages returns the completed stages for a session. -func (d sessionsDict) GetCompletedStages(sessionID string) []authtypes.LoginType { +func (d *sessionsDict) GetCompletedStages(sessionID string) []authtypes.LoginType { + d.Lock() + defer d.Unlock() + if completedStages, ok := d.sessions[sessionID]; ok { return completedStages } @@ -83,23 +89,25 @@ func (d sessionsDict) GetCompletedStages(sessionID string) []authtypes.LoginType return make([]authtypes.LoginType, 0) } -// AddCompletedStage records that a session has completed an auth stage. -func (d *sessionsDict) AddCompletedStage(sessionID string, stage authtypes.LoginType) { - // Return if the stage is already present - for _, completedStage := range d.GetCompletedStages(sessionID) { - if completedStage == stage { - return - } - } - d.sessions[sessionID] = append(d.GetCompletedStages(sessionID), stage) -} - func newSessionsDict() *sessionsDict { return &sessionsDict{ sessions: make(map[string][]authtypes.LoginType), } } +// AddCompletedSessionStage records that a session has completed an auth stage. +func AddCompletedSessionStage(sessionID string, stage authtypes.LoginType) { + sessions.Lock() + defer sessions.Unlock() + + for _, completedStage := range sessions.sessions[sessionID] { + if completedStage == stage { + return + } + } + sessions.sessions[sessionID] = append(sessions.sessions[sessionID], stage) +} + var ( // TODO: Remove old sessions. Need to do so on a session-specific timeout. // sessions stores the completed flow stages for all sessions. Referenced using their sessionID. @@ -530,7 +538,7 @@ func handleRegistrationFlow( } // Add Recaptcha to the list of completed registration stages - sessions.AddCompletedStage(sessionID, authtypes.LoginTypeRecaptcha) + AddCompletedSessionStage(sessionID, authtypes.LoginTypeRecaptcha) case authtypes.LoginTypeSharedSecret: // Check shared secret against config @@ -543,7 +551,7 @@ func handleRegistrationFlow( } // Add SharedSecret to the list of completed registration stages - sessions.AddCompletedStage(sessionID, authtypes.LoginTypeSharedSecret) + AddCompletedSessionStage(sessionID, authtypes.LoginTypeSharedSecret) case "": // Extract the access token from the request, if there's one to extract @@ -573,7 +581,7 @@ func handleRegistrationFlow( case authtypes.LoginTypeDummy: // there is nothing to do // Add Dummy to the list of completed registration stages - sessions.AddCompletedStage(sessionID, authtypes.LoginTypeDummy) + AddCompletedSessionStage(sessionID, authtypes.LoginTypeDummy) default: return util.JSONResponse{ diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go index d36ed6957..d4b323a2d 100644 --- a/clientapi/routing/routing.go +++ b/clientapi/routing/routing.go @@ -245,6 +245,13 @@ func Setup( }), ).Methods(http.MethodGet, http.MethodPost, http.MethodOptions) + r0mux.Handle("/auth/{authType}/fallback/web", + common.MakeHTMLAPI("auth_fallback", func(w http.ResponseWriter, req *http.Request) *util.JSONResponse { + vars := mux.Vars(req) + return AuthFallback(w, req, vars["authType"], cfg) + }), + ).Methods(http.MethodGet, http.MethodPost, http.MethodOptions) + r0mux.Handle("/pushrules/", common.MakeExternalAPI("push_rules", func(req *http.Request) util.JSONResponse { // TODO: Implement push rules API diff --git a/clientapi/threepid/invites.go b/clientapi/threepid/invites.go index 251afb0d3..bfe5060a8 100644 --- a/clientapi/threepid/invites.go +++ b/clientapi/threepid/invites.go @@ -56,10 +56,10 @@ type idServerLookupResponse struct { // idServerLookupResponse represents the response described at https://matrix.org/docs/spec/client_server/r0.2.0.html#invitation-storage type idServerStoreInviteResponse struct { - PublicKey string `json:"public_key"` - Token string `json:"token"` - DisplayName string `json:"display_name"` - PublicKeys []common.PublicKey `json:"public_keys"` + PublicKey string `json:"public_key"` + Token string `json:"token"` + DisplayName string `json:"display_name"` + PublicKeys []gomatrixserverlib.PublicKey `json:"public_keys"` } var ( @@ -342,7 +342,7 @@ func emit3PIDInviteEvent( } validityURL := fmt.Sprintf("https://%s/_matrix/identity/api/v1/pubkey/isvalid", body.IDServer) - content := common.ThirdPartyInviteContent{ + content := gomatrixserverlib.ThirdPartyInviteContent{ DisplayName: res.DisplayName, KeyValidityURL: validityURL, PublicKey: res.PublicKey, diff --git a/common/config/config.go b/common/config/config.go index 9fcab8cf9..40232fb03 100644 --- a/common/config/config.go +++ b/common/config/config.go @@ -498,6 +498,11 @@ func (config *Dendrite) checkMatrix(configErrs *configErrors) { checkNotEmpty(configErrs, "matrix.server_name", string(config.Matrix.ServerName)) checkNotEmpty(configErrs, "matrix.private_key", string(config.Matrix.PrivateKeyPath)) checkNotZero(configErrs, "matrix.federation_certificates", int64(len(config.Matrix.FederationCertificatePaths))) + if config.Matrix.RecaptchaEnabled { + checkNotEmpty(configErrs, "matrix.recaptcha_public_key", string(config.Matrix.RecaptchaPublicKey)) + checkNotEmpty(configErrs, "matrix.recaptcha_private_key", string(config.Matrix.RecaptchaPrivateKey)) + checkNotEmpty(configErrs, "matrix.recaptcha_siteverify_api", string(config.Matrix.RecaptchaSiteVerifyAPI)) + } } // checkMedia verifies the parameters media.* are valid. diff --git a/common/eventcontent.go b/common/eventcontent.go index c45724fcd..c07c56276 100644 --- a/common/eventcontent.go +++ b/common/eventcontent.go @@ -14,55 +14,7 @@ package common -// CreateContent is the event content for http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-create -type CreateContent struct { - Creator string `json:"creator"` - Federate *bool `json:"m.federate,omitempty"` - RoomVersion string `json:"room_version,omitempty"` - Predecessor PreviousRoom `json:"predecessor,omitempty"` -} - -// PreviousRoom is the "Previous Room" structure defined at https://matrix.org/docs/spec/client_server/r0.5.0#m-room-create -type PreviousRoom struct { - RoomID string `json:"room_id"` - EventID string `json:"event_id"` -} - -// 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"` - 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 -type ThirdPartyInviteContent struct { - DisplayName string `json:"display_name"` - KeyValidityURL string `json:"key_validity_url"` - PublicKey string `json:"public_key"` - PublicKeys []PublicKey `json:"public_keys"` -} - -// PublicKey is the PublicKeys structure in https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-third-party-invite -type PublicKey struct { - KeyValidityURL string `json:"key_validity_url"` - PublicKey string `json:"public_key"` -} +import "github.com/matrix-org/gomatrixserverlib" // NameContent is the event content for https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-name type NameContent struct { @@ -79,51 +31,26 @@ type GuestAccessContent struct { GuestAccess string `json:"guest_access"` } -// JoinRulesContent is the event content for http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-join-rules -type JoinRulesContent struct { - JoinRule string `json:"join_rule"` -} - // HistoryVisibilityContent is the event content for http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-history-visibility type HistoryVisibilityContent struct { HistoryVisibility string `json:"history_visibility"` } -// PowerLevelContent is the event content for http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-power-levels -type PowerLevelContent struct { - EventsDefault int `json:"events_default"` - Invite int `json:"invite"` - StateDefault int `json:"state_default"` - Redact int `json:"redact"` - Ban int `json:"ban"` - UsersDefault int `json:"users_default"` - Events map[string]int `json:"events"` - Kick int `json:"kick"` - Users map[string]int `json:"users"` -} - // InitialPowerLevelsContent returns the initial values for m.room.power_levels on room creation // if they have not been specified. // http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-power-levels // https://github.com/matrix-org/synapse/blob/v0.19.2/synapse/handlers/room.py#L294 -func InitialPowerLevelsContent(roomCreator string) PowerLevelContent { - return PowerLevelContent{ - EventsDefault: 0, - Invite: 0, - StateDefault: 50, - Redact: 50, - Ban: 50, - UsersDefault: 0, - Events: map[string]int{ - "m.room.name": 50, - "m.room.power_levels": 100, - "m.room.history_visibility": 100, - "m.room.canonical_alias": 50, - "m.room.avatar": 50, - }, - Kick: 50, - Users: map[string]int{roomCreator: 100}, +func InitialPowerLevelsContent(roomCreator string) (c gomatrixserverlib.PowerLevelContent) { + c.Defaults() + c.Events = map[string]int64{ + "m.room.name": 50, + "m.room.power_levels": 100, + "m.room.history_visibility": 100, + "m.room.canonical_alias": 50, + "m.room.avatar": 50, } + c.Users = map[string]int64{roomCreator: 100} + return c } // AliasesContent is the event content for http://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-aliases diff --git a/common/httpapi.go b/common/httpapi.go index 99e15830a..bf634ff4a 100644 --- a/common/httpapi.go +++ b/common/httpapi.go @@ -10,6 +10,7 @@ import ( "github.com/matrix-org/util" opentracing "github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go/ext" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) @@ -43,6 +44,24 @@ func MakeExternalAPI(metricsName string, f func(*http.Request) util.JSONResponse return http.HandlerFunc(withSpan) } +// MakeHTMLAPI adds Span metrics to the HTML Handler function +// This is used to serve HTML alongside JSON error messages +func MakeHTMLAPI(metricsName string, f func(http.ResponseWriter, *http.Request) *util.JSONResponse) http.Handler { + withSpan := func(w http.ResponseWriter, req *http.Request) { + span := opentracing.StartSpan(metricsName) + defer span.Finish() + req = req.WithContext(opentracing.ContextWithSpan(req.Context(), span)) + if err := f(w, req); err != nil { + h := util.MakeJSONAPI(util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse { + return *err + })) + h.ServeHTTP(w, req) + } + } + + return prometheus.InstrumentHandler(metricsName, http.HandlerFunc(withSpan)) +} + // MakeInternalAPI turns a util.JSONRequestHandler function into an http.Handler. // This is used for APIs that are internal to dendrite. // If we are passed a tracing context in the request headers then we use that diff --git a/federationapi/routing/routing.go b/federationapi/routing/routing.go index ed32c8904..9f576790b 100644 --- a/federationapi/routing/routing.go +++ b/federationapi/routing/routing.go @@ -64,6 +64,7 @@ func Setup( // {keyID} argument and always return a response containing all of the keys. v2keysmux.Handle("/server/{keyID}", localKeys).Methods(http.MethodGet) v2keysmux.Handle("/server/", localKeys).Methods(http.MethodGet) + v2keysmux.Handle("/server", localKeys).Methods(http.MethodGet) v1fedmux.Handle("/send/{txnID}", common.MakeFedAPI( "federation_send", cfg.Matrix.ServerName, keys, diff --git a/federationapi/routing/threepid.go b/federationapi/routing/threepid.go index cff311cc4..7fa02be91 100644 --- a/federationapi/routing/threepid.go +++ b/federationapi/routing/threepid.go @@ -27,7 +27,6 @@ import ( "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/clientapi/producers" - "github.com/matrix-org/dendrite/common" "github.com/matrix-org/dendrite/common/config" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" @@ -38,11 +37,11 @@ import ( ) 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"` + MXID string `json:"mxid"` + RoomID string `json:"room_id"` + Sender string `json:"sender"` + Token string `json:"token"` + Signed gomatrixserverlib.MemberThirdPartyInviteSigned `json:"signed"` } type invites struct { @@ -199,11 +198,11 @@ func createInviteFrom3PIDInvite( return nil, err } - content := common.MemberContent{ + content := gomatrixserverlib.MemberContent{ AvatarURL: profile.AvatarURL, DisplayName: profile.DisplayName, Membership: gomatrixserverlib.Invite, - ThirdPartyInvite: &common.TPInvite{ + ThirdPartyInvite: &gomatrixserverlib.MemberThirdPartyInvite{ Signed: inv.Signed, }, } @@ -330,7 +329,7 @@ func sendToRemoteServer( func fillDisplayName( builder *gomatrixserverlib.EventBuilder, authEvents gomatrixserverlib.AuthEvents, ) error { - var content common.MemberContent + var content gomatrixserverlib.MemberContent if err := json.Unmarshal(builder.Content, &content); err != nil { return err } @@ -343,7 +342,7 @@ func fillDisplayName( return nil } - var thirdPartyInviteContent common.ThirdPartyInviteContent + var thirdPartyInviteContent gomatrixserverlib.ThirdPartyInviteContent if err := json.Unmarshal(thirdPartyInviteEvent.Content(), &thirdPartyInviteContent); err != nil { return err } diff --git a/go.mod b/go.mod index 8e14253ca..d51f0a33e 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/lib/pq v0.0.0-20170918175043-23da1db4f16d github.com/matrix-org/dugong v0.0.0-20171220115018-ea0a4690a0d5 github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26 - github.com/matrix-org/gomatrixserverlib v0.0.0-20190805173246-3a2199d5ecd6 + github.com/matrix-org/gomatrixserverlib v0.0.0-20190814163046-d6285a18401f github.com/matrix-org/naffka v0.0.0-20171115094957-662bfd0841d0 github.com/matrix-org/util v0.0.0-20171127121716-2e2df66af2f5 github.com/matttproud/golang_protobuf_extensions v1.0.1 diff --git a/go.sum b/go.sum index 0d59d1dd6..56781c9a6 100644 --- a/go.sum +++ b/go.sum @@ -58,6 +58,8 @@ github.com/matrix-org/gomatrixserverlib v0.0.0-20190724145009-a6df10ef35d6 h1:B8 github.com/matrix-org/gomatrixserverlib v0.0.0-20190724145009-a6df10ef35d6/go.mod h1:sf0RcKOdiwJeTti7A313xsaejNUGYDq02MQZ4JD4w/E= github.com/matrix-org/gomatrixserverlib v0.0.0-20190805173246-3a2199d5ecd6 h1:xr69Hk6QM3RIN6JSvx3RpDowBGpHpDDqhqXCeySwYow= github.com/matrix-org/gomatrixserverlib v0.0.0-20190805173246-3a2199d5ecd6/go.mod h1:sf0RcKOdiwJeTti7A313xsaejNUGYDq02MQZ4JD4w/E= +github.com/matrix-org/gomatrixserverlib v0.0.0-20190814163046-d6285a18401f h1:20CZL7ApB7xgR7sZF9yD/qpsP51Sfx0TTgUJ3vKgnZQ= +github.com/matrix-org/gomatrixserverlib v0.0.0-20190814163046-d6285a18401f/go.mod h1:sf0RcKOdiwJeTti7A313xsaejNUGYDq02MQZ4JD4w/E= github.com/matrix-org/naffka v0.0.0-20171115094957-662bfd0841d0 h1:p7WTwG+aXM86+yVrYAiCMW3ZHSmotVvuRbjtt3jC+4A= github.com/matrix-org/naffka v0.0.0-20171115094957-662bfd0841d0/go.mod h1:cXoYQIENbdWIQHt1SyCo6Bl3C3raHwJ0wgVrXHSqf+A= github.com/matrix-org/util v0.0.0-20171013132526-8b1c8ab81986 h1:TiWl4hLvezAhRPM8tPcPDFTysZ7k4T/1J4GPp/iqlZo= diff --git a/testfile b/testfile index d04ab731c..17978913e 100644 --- a/testfile +++ b/testfile @@ -143,7 +143,7 @@ Trying to get push rules with unknown rule_id fails with 404 Events come down the correct room local user can join room with version 5 User can invite local user to room with version 5 -Inbound federation can receive room-join requests +Inbound federation can receive v1 room-join requests Typing events appear in initial sync Typing events appear in incremental sync Typing events appear in gapped sync @@ -170,3 +170,4 @@ Deleted tags appear in an incremental v2 /sync Outbound federation can query profile data /event/ on joined room works /event/ does not allow access to events before the user joined +Federation key API allows unsigned requests for keys