2017-05-25 10:08:28 -05:00
|
|
|
// 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.
|
|
|
|
|
2017-10-11 12:16:53 -05:00
|
|
|
package routing
|
2017-05-25 10:08:28 -05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2017-07-07 08:11:32 -05:00
|
|
|
"net/http"
|
|
|
|
"strings"
|
2018-08-22 07:40:25 -05:00
|
|
|
"time"
|
2017-07-07 08:11:32 -05:00
|
|
|
|
2017-05-25 10:08:28 -05:00
|
|
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
2017-07-25 10:10:59 -05:00
|
|
|
"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
|
2017-05-25 10:08:28 -05:00
|
|
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
|
|
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
|
|
|
"github.com/matrix-org/dendrite/clientapi/producers"
|
2017-10-25 08:44:33 -05:00
|
|
|
"github.com/matrix-org/dendrite/common"
|
2017-06-19 09:21:04 -05:00
|
|
|
"github.com/matrix-org/dendrite/common/config"
|
2020-04-29 09:29:39 -05:00
|
|
|
federationSenderAPI "github.com/matrix-org/dendrite/federationsender/api"
|
2018-07-17 09:36:04 -05:00
|
|
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
2017-05-25 10:08:28 -05:00
|
|
|
"github.com/matrix-org/gomatrix"
|
|
|
|
"github.com/matrix-org/gomatrixserverlib"
|
|
|
|
"github.com/matrix-org/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
// JoinRoomByIDOrAlias implements the "/join/{roomIDOrAlias}" API.
|
|
|
|
// https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-join-roomidoralias
|
|
|
|
func JoinRoomByIDOrAlias(
|
|
|
|
req *http.Request,
|
|
|
|
device *authtypes.Device,
|
|
|
|
roomIDOrAlias string,
|
2020-02-11 05:18:12 -06:00
|
|
|
cfg *config.Dendrite,
|
2017-05-25 10:08:28 -05:00
|
|
|
federation *gomatrixserverlib.FederationClient,
|
|
|
|
producer *producers.RoomserverProducer,
|
2020-05-01 04:48:17 -05:00
|
|
|
rsAPI roomserverAPI.RoomserverInternalAPI,
|
2020-04-29 09:29:39 -05:00
|
|
|
fsAPI federationSenderAPI.FederationSenderInternalAPI,
|
2017-05-25 10:08:28 -05:00
|
|
|
keyRing gomatrixserverlib.KeyRing,
|
2020-02-13 11:27:33 -06:00
|
|
|
accountDB accounts.Database,
|
2017-05-25 10:08:28 -05:00
|
|
|
) util.JSONResponse {
|
|
|
|
var content map[string]interface{} // must be a JSON object
|
|
|
|
if resErr := httputil.UnmarshalJSONRequest(req, &content); resErr != nil {
|
|
|
|
return *resErr
|
|
|
|
}
|
|
|
|
|
2018-08-22 07:40:25 -05:00
|
|
|
evTime, err := httputil.ParseTSParam(req)
|
|
|
|
if err != nil {
|
|
|
|
return util.JSONResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
JSON: jsonerror.InvalidArgumentValue(err.Error()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-25 10:10:59 -05:00
|
|
|
localpart, _, err := gomatrixserverlib.SplitID('@', device.UserID)
|
|
|
|
if err != nil {
|
2020-03-02 10:20:44 -06:00
|
|
|
util.GetLogger(req.Context()).WithError(err).Error("gomatrixserverlib.SplitID failed")
|
|
|
|
return jsonerror.InternalServerError()
|
2017-07-25 10:10:59 -05:00
|
|
|
}
|
|
|
|
|
2017-09-18 08:15:27 -05:00
|
|
|
profile, err := accountDB.GetProfileByLocalpart(req.Context(), localpart)
|
2017-07-25 10:10:59 -05:00
|
|
|
if err != nil {
|
2020-03-02 10:20:44 -06:00
|
|
|
util.GetLogger(req.Context()).WithError(err).Error("accountDB.GetProfileByLocalpart failed")
|
|
|
|
return jsonerror.InternalServerError()
|
2017-07-25 10:10:59 -05:00
|
|
|
}
|
|
|
|
|
2019-08-06 09:07:36 -05:00
|
|
|
content["membership"] = gomatrixserverlib.Join
|
2017-07-25 10:10:59 -05:00
|
|
|
content["displayname"] = profile.DisplayName
|
|
|
|
content["avatar_url"] = profile.AvatarURL
|
2017-05-25 10:08:28 -05:00
|
|
|
|
2018-08-22 07:40:25 -05:00
|
|
|
r := joinRoomReq{
|
2020-04-29 09:29:39 -05:00
|
|
|
req, evTime, content, device.UserID, cfg, federation, producer,
|
2020-05-01 04:48:17 -05:00
|
|
|
rsAPI, fsAPI, keyRing,
|
2018-08-22 07:40:25 -05:00
|
|
|
}
|
2017-05-25 10:08:28 -05:00
|
|
|
|
|
|
|
if strings.HasPrefix(roomIDOrAlias, "!") {
|
2017-09-21 11:00:48 -05:00
|
|
|
return r.joinRoomByID(roomIDOrAlias)
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
|
|
|
if strings.HasPrefix(roomIDOrAlias, "#") {
|
|
|
|
return r.joinRoomByAlias(roomIDOrAlias)
|
|
|
|
}
|
|
|
|
return util.JSONResponse{
|
2018-03-13 10:55:45 -05:00
|
|
|
Code: http.StatusBadRequest,
|
2019-07-03 10:38:50 -05:00
|
|
|
JSON: jsonerror.BadJSON(
|
|
|
|
fmt.Sprintf("Invalid first character '%s' for room ID or alias",
|
|
|
|
string([]rune(roomIDOrAlias)[0])), // Wrapping with []rune makes this call UTF-8 safe
|
|
|
|
),
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type joinRoomReq struct {
|
|
|
|
req *http.Request
|
2018-08-22 07:40:25 -05:00
|
|
|
evTime time.Time
|
2017-05-25 10:08:28 -05:00
|
|
|
content map[string]interface{}
|
|
|
|
userID string
|
2020-02-11 05:18:12 -06:00
|
|
|
cfg *config.Dendrite
|
2017-05-25 10:08:28 -05:00
|
|
|
federation *gomatrixserverlib.FederationClient
|
|
|
|
producer *producers.RoomserverProducer
|
2020-05-01 04:48:17 -05:00
|
|
|
rsAPI roomserverAPI.RoomserverInternalAPI
|
2020-04-29 09:29:39 -05:00
|
|
|
fsAPI federationSenderAPI.FederationSenderInternalAPI
|
2017-05-25 10:08:28 -05:00
|
|
|
keyRing gomatrixserverlib.KeyRing
|
|
|
|
}
|
|
|
|
|
|
|
|
// joinRoomByID joins a room by room ID
|
2017-09-21 11:00:48 -05:00
|
|
|
func (r joinRoomReq) joinRoomByID(roomID string) util.JSONResponse {
|
2017-05-25 10:08:28 -05:00
|
|
|
// A client should only join a room by room ID when it has an invite
|
|
|
|
// to the room. If the server is already in the room then we can
|
|
|
|
// lookup the invite and process the request as a normal state event.
|
|
|
|
// If the server is not in the room the we will need to look up the
|
|
|
|
// remote server the invite came from in order to request a join event
|
|
|
|
// from that server.
|
2018-07-17 09:36:04 -05:00
|
|
|
queryReq := roomserverAPI.QueryInvitesForUserRequest{
|
2017-09-21 11:00:48 -05:00
|
|
|
RoomID: roomID, TargetUserID: r.userID,
|
|
|
|
}
|
2018-07-17 09:36:04 -05:00
|
|
|
var queryRes roomserverAPI.QueryInvitesForUserResponse
|
2020-05-01 04:48:17 -05:00
|
|
|
if err := r.rsAPI.QueryInvitesForUser(r.req.Context(), &queryReq, &queryRes); err != nil {
|
2020-03-02 10:20:44 -06:00
|
|
|
util.GetLogger(r.req.Context()).WithError(err).Error("r.queryAPI.QueryInvitesForUser failed")
|
|
|
|
return jsonerror.InternalServerError()
|
2017-09-21 11:00:48 -05:00
|
|
|
}
|
2019-01-15 12:20:46 -06:00
|
|
|
|
2017-09-21 11:00:48 -05:00
|
|
|
servers := []gomatrixserverlib.ServerName{}
|
2019-01-15 12:20:46 -06:00
|
|
|
seenInInviterIDs := map[gomatrixserverlib.ServerName]bool{}
|
2017-09-21 11:00:48 -05:00
|
|
|
for _, userID := range queryRes.InviteSenderUserIDs {
|
|
|
|
_, domain, err := gomatrixserverlib.SplitID('@', userID)
|
|
|
|
if err != nil {
|
2020-03-02 10:20:44 -06:00
|
|
|
util.GetLogger(r.req.Context()).WithError(err).Error("gomatrixserverlib.SplitID failed")
|
|
|
|
return jsonerror.InternalServerError()
|
2017-09-21 11:00:48 -05:00
|
|
|
}
|
2019-01-15 12:20:46 -06:00
|
|
|
if !seenInInviterIDs[domain] {
|
2017-09-21 11:00:48 -05:00
|
|
|
servers = append(servers, domain)
|
2019-01-15 12:20:46 -06:00
|
|
|
seenInInviterIDs[domain] = true
|
2017-09-21 11:00:48 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-15 12:20:46 -06:00
|
|
|
// Also add the domain extracted from the roomID as a last resort to join
|
|
|
|
// in case the client is erroneously trying to join by ID without an invite
|
|
|
|
// or all previous attempts at domains extracted from the inviter IDs fail
|
|
|
|
// Note: It's no guarantee we'll succeed because a room isn't bound to the domain in its ID
|
|
|
|
_, domain, err := gomatrixserverlib.SplitID('!', roomID)
|
|
|
|
if err != nil {
|
2020-03-02 10:20:44 -06:00
|
|
|
util.GetLogger(r.req.Context()).WithError(err).Error("gomatrixserverlib.SplitID failed")
|
|
|
|
return jsonerror.InternalServerError()
|
2019-01-15 12:20:46 -06:00
|
|
|
}
|
|
|
|
if domain != r.cfg.Matrix.ServerName && !seenInInviterIDs[domain] {
|
|
|
|
servers = append(servers, domain)
|
|
|
|
}
|
|
|
|
|
2017-09-21 11:00:48 -05:00
|
|
|
return r.joinRoomUsingServers(roomID, servers)
|
|
|
|
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// joinRoomByAlias joins a room using a room alias.
|
|
|
|
func (r joinRoomReq) joinRoomByAlias(roomAlias string) util.JSONResponse {
|
2017-07-07 08:11:32 -05:00
|
|
|
_, domain, err := gomatrixserverlib.SplitID('#', roomAlias)
|
2017-05-25 10:08:28 -05:00
|
|
|
if err != nil {
|
|
|
|
return util.JSONResponse{
|
2018-03-13 10:55:45 -05:00
|
|
|
Code: http.StatusBadRequest,
|
2017-05-25 10:08:28 -05:00
|
|
|
JSON: jsonerror.BadJSON("Room alias must be in the form '#localpart:domain'"),
|
|
|
|
}
|
|
|
|
}
|
2017-06-19 09:21:04 -05:00
|
|
|
if domain == r.cfg.Matrix.ServerName {
|
2018-07-17 09:36:04 -05:00
|
|
|
queryReq := roomserverAPI.GetRoomIDForAliasRequest{Alias: roomAlias}
|
|
|
|
var queryRes roomserverAPI.GetRoomIDForAliasResponse
|
2020-05-01 04:48:17 -05:00
|
|
|
if err = r.rsAPI.GetRoomIDForAlias(r.req.Context(), &queryReq, &queryRes); err != nil {
|
2020-03-02 10:20:44 -06:00
|
|
|
util.GetLogger(r.req.Context()).WithError(err).Error("r.aliasAPI.GetRoomIDForAlias failed")
|
|
|
|
return jsonerror.InternalServerError()
|
2017-07-28 09:29:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(queryRes.RoomID) > 0 {
|
|
|
|
return r.joinRoomUsingServers(queryRes.RoomID, []gomatrixserverlib.ServerName{r.cfg.Matrix.ServerName})
|
|
|
|
}
|
|
|
|
// If the response doesn't contain a non-empty string, return an error
|
|
|
|
return util.JSONResponse{
|
2018-03-13 10:55:45 -05:00
|
|
|
Code: http.StatusNotFound,
|
2017-07-28 09:29:12 -05:00
|
|
|
JSON: jsonerror.NotFound("Room alias " + roomAlias + " not found."),
|
|
|
|
}
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
2017-07-28 09:29:12 -05:00
|
|
|
// If the room isn't local, use federation to join
|
|
|
|
return r.joinRoomByRemoteAlias(domain, roomAlias)
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r joinRoomReq) joinRoomByRemoteAlias(
|
|
|
|
domain gomatrixserverlib.ServerName, roomAlias string,
|
|
|
|
) util.JSONResponse {
|
2017-09-13 05:03:41 -05:00
|
|
|
resp, err := r.federation.LookupRoomAlias(r.req.Context(), domain, roomAlias)
|
2017-05-25 10:08:28 -05:00
|
|
|
if err != nil {
|
|
|
|
switch x := err.(type) {
|
|
|
|
case gomatrix.HTTPError:
|
2018-03-13 10:55:45 -05:00
|
|
|
if x.Code == http.StatusNotFound {
|
2017-05-25 10:08:28 -05:00
|
|
|
return util.JSONResponse{
|
2018-03-13 10:55:45 -05:00
|
|
|
Code: http.StatusNotFound,
|
2017-05-25 10:08:28 -05:00
|
|
|
JSON: jsonerror.NotFound("Room alias not found"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-02 10:20:44 -06:00
|
|
|
util.GetLogger(r.req.Context()).WithError(err).Error("r.federation.LookupRoomAlias failed")
|
|
|
|
return jsonerror.InternalServerError()
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return r.joinRoomUsingServers(resp.RoomID, resp.Servers)
|
|
|
|
}
|
|
|
|
|
2017-09-20 04:59:19 -05:00
|
|
|
func (r joinRoomReq) writeToBuilder(eb *gomatrixserverlib.EventBuilder, roomID string) error {
|
2017-05-25 10:08:28 -05:00
|
|
|
eb.Type = "m.room.member"
|
2017-09-20 04:59:19 -05:00
|
|
|
|
|
|
|
err := eb.SetContent(r.content)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = eb.SetUnsigned(struct{}{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-05-25 10:08:28 -05:00
|
|
|
eb.Sender = r.userID
|
|
|
|
eb.StateKey = &r.userID
|
|
|
|
eb.RoomID = roomID
|
|
|
|
eb.Redacts = ""
|
2017-09-20 04:59:19 -05:00
|
|
|
|
|
|
|
return nil
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r joinRoomReq) joinRoomUsingServers(
|
|
|
|
roomID string, servers []gomatrixserverlib.ServerName,
|
|
|
|
) util.JSONResponse {
|
|
|
|
var eb gomatrixserverlib.EventBuilder
|
2017-09-20 04:59:19 -05:00
|
|
|
err := r.writeToBuilder(&eb, roomID)
|
|
|
|
if err != nil {
|
2020-03-02 10:20:44 -06:00
|
|
|
util.GetLogger(r.req.Context()).WithError(err).Error("r.writeToBuilder failed")
|
|
|
|
return jsonerror.InternalServerError()
|
2017-09-20 04:59:19 -05:00
|
|
|
}
|
2017-05-25 10:08:28 -05:00
|
|
|
|
2020-03-27 11:28:22 -05:00
|
|
|
queryRes := roomserverAPI.QueryLatestEventsAndStateResponse{}
|
2020-05-01 04:48:17 -05:00
|
|
|
event, err := common.BuildEvent(r.req.Context(), &eb, r.cfg, r.evTime, r.rsAPI, &queryRes)
|
2017-09-13 07:37:50 -05:00
|
|
|
if err == nil {
|
Federation for v3/v4 rooms (#954)
* Update gomatrixserverlib
* Default to room version 4
* Update gomatrixserverlib
* Limit prev_events and auth_events
* Fix auth_events, prev_events
* Fix linter issues
* Update gomatrixserverlib
* Fix getState
* Update sytest-whitelist
* Squashed commit of the following:
commit 067b87506357c996fd6ddb11271db9469ad4ce80
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Fri Apr 3 14:29:06 2020 +0100
Invites v2 endpoint (#952)
* Start converting v1 invite endpoint to v2
* Update gomatrixserverlib
* Early federationsender code for sending invites
* Sending invites sorta happens now
* Populate invite request with stripped state
* Remodel a bit, don't reflect received invites
* Handle invite_room_state
* Handle room versions a bit better
* Update gomatrixserverlib
* Tweak order in destinationQueue.next
* Revert check in processMessage
* Tweak federation sender destination queue code a bit
* Add comments
commit 955244c09298d0e6c870377dad3af2ffa1f5e578
Author: Ben B <benne@klimlive.de>
Date: Fri Apr 3 12:40:50 2020 +0200
use custom http client instead of the http DefaultClient (#823)
This commit replaces the default client from the http lib with a custom one.
The previously used default client doesn't come with a timeout. This could cause
unwanted locks.
That solution chosen here creates a http client in the base component dendrite
with a constant timeout of 30 seconds. If it should be necessary to overwrite
this, we could include the timeout in the dendrite configuration.
Here it would be a good idea to extend the type "Address" by a timeout and
create an http client for each service.
Closes #820
Signed-off-by: Benedikt Bongartz <benne@klimlive.de>
Co-authored-by: Kegsay <kegan@matrix.org>
* Update sytest-whitelist, sytest-blacklist
* Update go.mod/go.sum
* Add some error wrapping for debug
* Add a NOTSPEC to common/events.go
* Perform state resolution at send_join
* Set default room version to v2 again
* Tweak GetCapabilities
* Add comments to ResolveConflictsAdhoc
* Update sytest-blacklist
* go mod tidy
* Update sytest-whitelist, sytest-blacklist
* Update versions
* Updates from review comments
* Update sytest-blacklist, sytest-whitelist
* Check room versions compatible at make_join, add some comments, update gomatrixserverlib, other tweaks
* Set default room version back to v2
* Update gomatrixserverlib, sytest-whitelist
2020-04-09 09:46:06 -05:00
|
|
|
// If we have successfully built an event at this point then we can
|
|
|
|
// assert that the room is a local room, as BuildEvent was able to
|
|
|
|
// add prev_events etc successfully.
|
2020-03-27 11:28:22 -05:00
|
|
|
if _, err = r.producer.SendEvents(
|
|
|
|
r.req.Context(),
|
|
|
|
[]gomatrixserverlib.HeaderedEvent{
|
|
|
|
(*event).Headered(queryRes.RoomVersion),
|
|
|
|
},
|
|
|
|
r.cfg.Matrix.ServerName,
|
|
|
|
nil,
|
|
|
|
); err != nil {
|
2020-03-02 10:20:44 -06:00
|
|
|
util.GetLogger(r.req.Context()).WithError(err).Error("r.producer.SendEvents failed")
|
|
|
|
return jsonerror.InternalServerError()
|
2017-07-28 09:29:12 -05:00
|
|
|
}
|
|
|
|
return util.JSONResponse{
|
2018-03-13 10:55:45 -05:00
|
|
|
Code: http.StatusOK,
|
2017-07-28 09:29:12 -05:00
|
|
|
JSON: struct {
|
|
|
|
RoomID string `json:"room_id"`
|
|
|
|
}{roomID},
|
|
|
|
}
|
2017-09-13 07:37:50 -05:00
|
|
|
}
|
Federation for v3/v4 rooms (#954)
* Update gomatrixserverlib
* Default to room version 4
* Update gomatrixserverlib
* Limit prev_events and auth_events
* Fix auth_events, prev_events
* Fix linter issues
* Update gomatrixserverlib
* Fix getState
* Update sytest-whitelist
* Squashed commit of the following:
commit 067b87506357c996fd6ddb11271db9469ad4ce80
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Fri Apr 3 14:29:06 2020 +0100
Invites v2 endpoint (#952)
* Start converting v1 invite endpoint to v2
* Update gomatrixserverlib
* Early federationsender code for sending invites
* Sending invites sorta happens now
* Populate invite request with stripped state
* Remodel a bit, don't reflect received invites
* Handle invite_room_state
* Handle room versions a bit better
* Update gomatrixserverlib
* Tweak order in destinationQueue.next
* Revert check in processMessage
* Tweak federation sender destination queue code a bit
* Add comments
commit 955244c09298d0e6c870377dad3af2ffa1f5e578
Author: Ben B <benne@klimlive.de>
Date: Fri Apr 3 12:40:50 2020 +0200
use custom http client instead of the http DefaultClient (#823)
This commit replaces the default client from the http lib with a custom one.
The previously used default client doesn't come with a timeout. This could cause
unwanted locks.
That solution chosen here creates a http client in the base component dendrite
with a constant timeout of 30 seconds. If it should be necessary to overwrite
this, we could include the timeout in the dendrite configuration.
Here it would be a good idea to extend the type "Address" by a timeout and
create an http client for each service.
Closes #820
Signed-off-by: Benedikt Bongartz <benne@klimlive.de>
Co-authored-by: Kegsay <kegan@matrix.org>
* Update sytest-whitelist, sytest-blacklist
* Update go.mod/go.sum
* Add some error wrapping for debug
* Add a NOTSPEC to common/events.go
* Perform state resolution at send_join
* Set default room version to v2 again
* Tweak GetCapabilities
* Add comments to ResolveConflictsAdhoc
* Update sytest-blacklist
* go mod tidy
* Update sytest-whitelist, sytest-blacklist
* Update versions
* Updates from review comments
* Update sytest-blacklist, sytest-whitelist
* Check room versions compatible at make_join, add some comments, update gomatrixserverlib, other tweaks
* Set default room version back to v2
* Update gomatrixserverlib, sytest-whitelist
2020-04-09 09:46:06 -05:00
|
|
|
|
|
|
|
// Otherwise, if we've reached here, then we haven't been able to populate
|
|
|
|
// prev_events etc for the room, therefore the room is probably federated.
|
|
|
|
|
2020-04-03 08:29:06 -05:00
|
|
|
// TODO: This needs to be re-thought, as in the case of an invite, the room
|
|
|
|
// will exist in the database in roomserver_rooms but won't have any state
|
|
|
|
// events, therefore this below check fails.
|
2017-10-25 08:44:33 -05:00
|
|
|
if err != common.ErrRoomNoExists {
|
2020-03-02 10:20:44 -06:00
|
|
|
util.GetLogger(r.req.Context()).WithError(err).Error("common.BuildEvent failed")
|
|
|
|
return jsonerror.InternalServerError()
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(servers) == 0 {
|
|
|
|
return util.JSONResponse{
|
2018-03-13 10:55:45 -05:00
|
|
|
Code: http.StatusNotFound,
|
2017-05-25 10:08:28 -05:00
|
|
|
JSON: jsonerror.NotFound("No candidate servers found for room"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var lastErr error
|
|
|
|
for _, server := range servers {
|
|
|
|
var response *util.JSONResponse
|
|
|
|
response, lastErr = r.joinRoomUsingServer(roomID, server)
|
|
|
|
if lastErr != nil {
|
|
|
|
// There was a problem talking to one of the servers.
|
|
|
|
util.GetLogger(r.req.Context()).WithError(lastErr).WithField("server", server).Warn("Failed to join room using server")
|
|
|
|
// Try the next server.
|
2020-04-20 11:42:34 -05:00
|
|
|
if r.req.Context().Err() != nil {
|
|
|
|
// The request context has expired so don't bother trying any
|
|
|
|
// more servers - they will immediately fail due to the expired
|
|
|
|
// context.
|
|
|
|
break
|
|
|
|
} else {
|
|
|
|
// The request context hasn't expired yet so try the next server.
|
|
|
|
continue
|
|
|
|
}
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
|
|
|
return *response
|
|
|
|
}
|
|
|
|
|
|
|
|
// Every server we tried to join through resulted in an error.
|
|
|
|
// We return the error from the last server.
|
|
|
|
|
|
|
|
// TODO: Generate the correct HTTP status code for all different
|
|
|
|
// kinds of errors that could have happened.
|
|
|
|
// The possible errors include:
|
|
|
|
// 1) We can't connect to the remote servers.
|
|
|
|
// 2) None of the servers we could connect to think we are allowed
|
|
|
|
// to join the room.
|
|
|
|
// 3) The remote server returned something invalid.
|
|
|
|
// 4) We couldn't fetch the public keys needed to verify the
|
|
|
|
// signatures on the state events.
|
|
|
|
// 5) ...
|
2020-03-02 10:20:44 -06:00
|
|
|
util.GetLogger(r.req.Context()).WithError(lastErr).Error("failed to join through any server")
|
|
|
|
return jsonerror.InternalServerError()
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// joinRoomUsingServer tries to join a remote room using a given matrix server.
|
|
|
|
// If there was a failure communicating with the server or the response from the
|
|
|
|
// server was invalid this returns an error.
|
|
|
|
// Otherwise this returns a JSONResponse.
|
|
|
|
func (r joinRoomReq) joinRoomUsingServer(roomID string, server gomatrixserverlib.ServerName) (*util.JSONResponse, error) {
|
2020-04-29 09:29:39 -05:00
|
|
|
fedJoinReq := federationSenderAPI.PerformJoinRequest{
|
|
|
|
RoomID: roomID,
|
|
|
|
UserID: r.userID,
|
|
|
|
ServerName: server,
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
2020-04-29 09:29:39 -05:00
|
|
|
fedJoinRes := federationSenderAPI.PerformJoinResponse{}
|
|
|
|
if err := r.fsAPI.PerformJoin(r.req.Context(), &fedJoinReq, &fedJoinRes); err != nil {
|
2020-04-20 11:42:34 -05:00
|
|
|
return nil, err
|
2017-05-25 10:08:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return &util.JSONResponse{
|
2018-03-13 10:55:45 -05:00
|
|
|
Code: http.StatusOK,
|
2017-05-25 10:08:28 -05:00
|
|
|
// TODO: Put the response struct somewhere common.
|
|
|
|
JSON: struct {
|
|
|
|
RoomID string `json:"room_id"`
|
|
|
|
}{roomID},
|
|
|
|
}, nil
|
|
|
|
}
|