Add directory lookups of aliases

This commit is contained in:
Neil Alexander 2020-05-01 17:25:45 +01:00
parent 1d3ddaeb5f
commit eda4efcf13
4 changed files with 88 additions and 12 deletions

View file

@ -8,6 +8,12 @@ import (
// FederationSenderInternalAPI is used to query information from the federation sender. // FederationSenderInternalAPI is used to query information from the federation sender.
type FederationSenderInternalAPI interface { type FederationSenderInternalAPI interface {
// PerformDirectoryLookup looks up a remote room ID from a room alias.
PerformDirectoryLookup(
ctx context.Context,
request *PerformDirectoryLookupRequest,
response *PerformDirectoryLookupResponse,
) error
// Query the joined hosts and the membership events accounting for their participation in a room. // Query the joined hosts and the membership events accounting for their participation in a room.
// Note that if a server has multiple users in the room, it will have multiple entries in the returned slice. // Note that if a server has multiple users in the room, it will have multiple entries in the returned slice.
// See `QueryJoinedHostServerNamesInRoom` for a de-duplicated version. // See `QueryJoinedHostServerNamesInRoom` for a de-duplicated version.

View file

@ -9,6 +9,9 @@ import (
) )
const ( const (
// FederationSenderPerformJoinRequestPath is the HTTP path for the PerformJoinRequest API.
FederationSenderPerformDirectoryLookupRequestPath = "/api/federationsender/performDirectoryLookup"
// FederationSenderPerformJoinRequestPath is the HTTP path for the PerformJoinRequest API. // FederationSenderPerformJoinRequestPath is the HTTP path for the PerformJoinRequest API.
FederationSenderPerformJoinRequestPath = "/api/federationsender/performJoinRequest" FederationSenderPerformJoinRequestPath = "/api/federationsender/performJoinRequest"
@ -16,6 +19,29 @@ const (
FederationSenderPerformLeaveRequestPath = "/api/federationsender/performLeaveRequest" FederationSenderPerformLeaveRequestPath = "/api/federationsender/performLeaveRequest"
) )
type PerformDirectoryLookupRequest struct {
RoomAlias string `json:"room_alias"`
ServerName gomatrixserverlib.ServerName `json:"server_name"`
}
type PerformDirectoryLookupResponse struct {
RoomID string `json:"room_id"`
ServerNames []gomatrixserverlib.ServerName `json:"server_names"`
}
// Handle an instruction to make_join & send_join with a remote server.
func (h *httpFederationSenderInternalAPI) PerformDirectoryLookup(
ctx context.Context,
request *PerformDirectoryLookupRequest,
response *PerformDirectoryLookupResponse,
) error {
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformDirectoryLookup")
defer span.Finish()
apiURL := h.federationSenderURL + FederationSenderPerformDirectoryLookupRequestPath
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
}
type PerformJoinRequest struct { type PerformJoinRequest struct {
RoomID string `json:"room_id"` RoomID string `json:"room_id"`
UserID string `json:"user_id"` UserID string `json:"user_id"`

View file

@ -11,6 +11,25 @@ import (
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
// PerformLeaveRequest implements api.FederationSenderInternalAPI
func (r *FederationSenderInternalAPI) PerformDirectoryLookup(
ctx context.Context,
request *api.PerformDirectoryLookupRequest,
response *api.PerformDirectoryLookupResponse,
) (err error) {
dir, err := r.federation.LookupRoomAlias(
ctx,
request.ServerName,
request.RoomAlias,
)
if err != nil {
return err
}
response.RoomID = dir.RoomID
response.ServerNames = dir.Servers
return nil
}
// PerformJoinRequest implements api.FederationSenderInternalAPI // PerformJoinRequest implements api.FederationSenderInternalAPI
func (r *FederationSenderInternalAPI) PerformJoin( func (r *FederationSenderInternalAPI) PerformJoin(
ctx context.Context, ctx context.Context,

View file

@ -21,10 +21,10 @@ func (r *RoomserverInternalAPI) PerformJoin(
) error { ) error {
_, domain, err := gomatrixserverlib.SplitID('@', req.UserID) _, domain, err := gomatrixserverlib.SplitID('@', req.UserID)
if err != nil { if err != nil {
return fmt.Errorf("supplied user ID %q in incorrect format", req.UserID) return fmt.Errorf("Supplied user ID %q in incorrect format", req.UserID)
} }
if domain != r.Cfg.Matrix.ServerName { if domain != r.Cfg.Matrix.ServerName {
return fmt.Errorf("user ID %q does not belong to this homeserver", req.UserID) return fmt.Errorf("User %q does not belong to this homeserver", req.UserID)
} }
if strings.HasPrefix(req.RoomIDOrAlias, "!") { if strings.HasPrefix(req.RoomIDOrAlias, "!") {
return r.performJoinRoomByID(ctx, req, res) return r.performJoinRoomByID(ctx, req, res)
@ -32,7 +32,7 @@ func (r *RoomserverInternalAPI) PerformJoin(
if strings.HasPrefix(req.RoomIDOrAlias, "#") { if strings.HasPrefix(req.RoomIDOrAlias, "#") {
return r.performJoinRoomByAlias(ctx, req, res) return r.performJoinRoomByAlias(ctx, req, res)
} }
return fmt.Errorf("unexpected sigil on room %q", req.RoomIDOrAlias) return fmt.Errorf("Room ID or alias %q is invalid", req.RoomIDOrAlias)
} }
func (r *RoomserverInternalAPI) performJoinRoomByAlias( func (r *RoomserverInternalAPI) performJoinRoomByAlias(
@ -43,14 +43,39 @@ func (r *RoomserverInternalAPI) performJoinRoomByAlias(
// Get the domain part of the room alias. // Get the domain part of the room alias.
_, domain, err := gomatrixserverlib.SplitID('#', req.RoomIDOrAlias) _, domain, err := gomatrixserverlib.SplitID('#', req.RoomIDOrAlias)
if err != nil { if err != nil {
return fmt.Errorf("supplied room alias %q in incorrect format", req.RoomIDOrAlias) return fmt.Errorf("Alias %q is not in the correct format", req.RoomIDOrAlias)
} }
req.ServerNames = append(req.ServerNames, domain) req.ServerNames = append(req.ServerNames, domain)
// Look up if we know this room alias. // Check if this alias matches our own server configuration. If it
roomID, err := r.DB.GetRoomIDForAlias(ctx, req.RoomIDOrAlias) // doesn't then we'll need to try a federated join.
var roomID string
if domain != r.Cfg.Matrix.ServerName {
// The alias isn't owned by us, so we will eed to try joining using
// a remote server.
dirReq := fsAPI.PerformDirectoryLookupRequest{
RoomAlias: req.RoomIDOrAlias, // the room alias to lookup
ServerName: domain, // the server to ask
}
dirRes := fsAPI.PerformDirectoryLookupResponse{}
err = r.fsAPI.PerformDirectoryLookup(ctx, &dirReq, &dirRes)
if err != nil { if err != nil {
return err logrus.WithError(err).Errorf("error looking up alias %q", req.RoomIDOrAlias)
return fmt.Errorf("Looking up alias %q over federation failed: %w", req.RoomIDOrAlias, err)
}
roomID = dirRes.RoomID
req.ServerNames = append(req.ServerNames, dirRes.ServerNames...)
} else {
// Otherwise, look up if we know this room alias locally.
roomID, err = r.DB.GetRoomIDForAlias(ctx, req.RoomIDOrAlias)
if err != nil {
return fmt.Errorf("Lookup room alias %q failed: %w", req.RoomIDOrAlias, err)
}
}
// If the room ID is empty then we failed to look up the alias.
if roomID == "" {
return fmt.Errorf("Alias %q not found", req.RoomIDOrAlias)
} }
// If we do, then pluck out the room ID and continue the join. // If we do, then pluck out the room ID and continue the join.
@ -68,7 +93,7 @@ func (r *RoomserverInternalAPI) performJoinRoomByID(
// Get the domain part of the room ID. // Get the domain part of the room ID.
_, domain, err := gomatrixserverlib.SplitID('!', req.RoomIDOrAlias) _, domain, err := gomatrixserverlib.SplitID('!', req.RoomIDOrAlias)
if err != nil { if err != nil {
return fmt.Errorf("supplied room ID %q in incorrect format", req.RoomIDOrAlias) return fmt.Errorf("Room ID %q is invalid", req.RoomIDOrAlias)
} }
req.ServerNames = append(req.ServerNames, domain) req.ServerNames = append(req.ServerNames, domain)
@ -135,7 +160,7 @@ func (r *RoomserverInternalAPI) performJoinRoomByID(
// room. If it is then there's nothing more to do - the room just // room. If it is then there's nothing more to do - the room just
// hasn't been created yet. // hasn't been created yet.
if domain == r.Cfg.Matrix.ServerName { if domain == r.Cfg.Matrix.ServerName {
return fmt.Errorf("room ID %q does not exist", req.RoomIDOrAlias) return fmt.Errorf("Room ID %q does not exist", req.RoomIDOrAlias)
} }
// Try joining by all of the supplied server names. // Try joining by all of the supplied server names.
@ -164,13 +189,13 @@ func (r *RoomserverInternalAPI) performJoinRoomByID(
// servers then return an error saying such. // servers then return an error saying such.
if !joined { if !joined {
return fmt.Errorf( return fmt.Errorf(
"failed to join %q using %d server(s)", "Failed to join %q using %d server(s)",
req.RoomIDOrAlias, len(req.ServerNames), req.RoomIDOrAlias, len(req.ServerNames),
) )
} }
default: default:
return fmt.Errorf("error joining room %q: %w", req.RoomIDOrAlias, err) return fmt.Errorf("Error joining room %q: %w", req.RoomIDOrAlias, err)
} }
return nil return nil