Implement GET /rooms/{roomAlias} (#494)

* Query whether a room alias exists on app services

Signed-off-by: Andrew Morgan <andrewm@matrix.org>

* URL encode room alias before sending to AS

* Add /room/ to path

* Query AS /alias/ API at a lower level

* Don't verify self-signed AS certificates

* Don't skip cert validation on appservices, fix logging

* Separate req.WithContext

* Linting

* Do not warn when an AS room alias does not exist
main
Andrew Morgan 2018-08-08 08:17:09 -07:00 committed by GitHub
parent e05a31f4c2
commit 609646c19b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 247 additions and 105 deletions

View File

@ -18,16 +18,41 @@
package api package api
import ( import (
"context"
"net/http" "net/http"
commonHTTP "github.com/matrix-org/dendrite/common/http"
opentracing "github.com/opentracing/opentracing-go"
) )
// RoomAliasExistsRequest is a request to an application service
// about whether a room alias exists
type RoomAliasExistsRequest struct {
// Alias we want to lookup
Alias string `json:"alias"`
}
// RoomAliasExistsResponse is a response from an application service
// about whether a room alias exists
type RoomAliasExistsResponse struct {
AliasExists bool `json:"exists"`
}
// AppServiceQueryAPI is used to query user and room alias data from application // AppServiceQueryAPI is used to query user and room alias data from application
// services // services
type AppServiceQueryAPI interface { type AppServiceQueryAPI interface {
// TODO: Check whether a room alias exists within any application service namespaces // Check whether a room alias exists within any application service namespaces
RoomAliasExists(
ctx context.Context,
req *RoomAliasExistsRequest,
response *RoomAliasExistsResponse,
) error
// TODO: QueryUserIDExists // TODO: QueryUserIDExists
} }
// AppServiceRoomAliasExistsPath is the HTTP path for the RoomAliasExists API
const AppServiceRoomAliasExistsPath = "/api/appservice/RoomAliasExists"
// httpAppServiceQueryAPI contains the URL to an appservice query API and a // httpAppServiceQueryAPI contains the URL to an appservice query API and a
// reference to a httpClient used to reach it // reference to a httpClient used to reach it
type httpAppServiceQueryAPI struct { type httpAppServiceQueryAPI struct {
@ -47,3 +72,16 @@ func NewAppServiceQueryAPIHTTP(
} }
return &httpAppServiceQueryAPI{appserviceURL, httpClient} return &httpAppServiceQueryAPI{appserviceURL, httpClient}
} }
// RoomAliasExists implements AppServiceQueryAPI
func (h *httpAppServiceQueryAPI) RoomAliasExists(
ctx context.Context,
request *RoomAliasExistsRequest,
response *RoomAliasExistsResponse,
) error {
span, ctx := opentracing.StartSpanFromContext(ctx, "appserviceRoomAliasExists")
defer span.Finish()
apiURL := h.appserviceURL + AppServiceRoomAliasExistsPath
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
}

View File

@ -74,14 +74,12 @@ func SetupAppServiceAPIComponent(
} }
} }
// Create a HTTP client that this component will use for all outbound and // Create appserivce query API with an HTTP client that will be used for all
// inbound requests (inbound only for the internal API) // outbound and inbound requests (inbound only for the internal API)
httpClient := &http.Client{
Timeout: time.Second * 30,
}
appserviceQueryAPI := query.AppServiceQueryAPI{ appserviceQueryAPI := query.AppServiceQueryAPI{
HTTPClient: httpClient, HTTPClient: &http.Client{
Timeout: time.Second * 30,
},
Cfg: base.Cfg, Cfg: base.Cfg,
} }

View File

@ -185,6 +185,7 @@ func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Cont
return false return false
} }
// Check Room ID and Sender of the event
if appservice.IsInterestedInUserID(event.Sender()) || if appservice.IsInterestedInUserID(event.Sender()) ||
appservice.IsInterestedInRoomID(event.RoomID()) { appservice.IsInterestedInRoomID(event.RoomID()) {
return true return true

View File

@ -17,18 +17,118 @@
package query package query
import ( import (
"context"
"encoding/json"
"net/http" "net/http"
"net/url"
"time"
"github.com/matrix-org/dendrite/appservice/api"
"github.com/matrix-org/dendrite/common"
"github.com/matrix-org/dendrite/common/config" "github.com/matrix-org/dendrite/common/config"
"github.com/matrix-org/util"
opentracing "github.com/opentracing/opentracing-go"
log "github.com/sirupsen/logrus"
) )
const roomAliasExistsPath = "/rooms/"
// AppServiceQueryAPI is an implementation of api.AppServiceQueryAPI // AppServiceQueryAPI is an implementation of api.AppServiceQueryAPI
type AppServiceQueryAPI struct { type AppServiceQueryAPI struct {
HTTPClient *http.Client HTTPClient *http.Client
Cfg *config.Dendrite Cfg *config.Dendrite
} }
// RoomAliasExists performs a request to '/room/{roomAlias}' on all known
// handling application services until one admits to owning the room
func (a *AppServiceQueryAPI) RoomAliasExists(
ctx context.Context,
request *api.RoomAliasExistsRequest,
response *api.RoomAliasExistsResponse,
) error {
span, ctx := opentracing.StartSpanFromContext(ctx, "ApplicationServiceRoomAlias")
defer span.Finish()
// Create an HTTP client if one does not already exist
if a.HTTPClient == nil {
a.HTTPClient = makeHTTPClient()
}
// Determine which application service should handle this request
for _, appservice := range a.Cfg.Derived.ApplicationServices {
if appservice.URL != "" && appservice.IsInterestedInRoomAlias(request.Alias) {
// The full path to the rooms API, includes hs token
URL, err := url.Parse(appservice.URL + roomAliasExistsPath)
URL.Path += request.Alias
apiURL := URL.String() + "?access_token=" + appservice.HSToken
// Send a request to each application service. If one responds that it has
// created the room, immediately return.
req, err := http.NewRequest(http.MethodGet, apiURL, nil)
if err != nil {
return err
}
req = req.WithContext(ctx)
resp, err := a.HTTPClient.Do(req)
if resp != nil {
defer func() {
err = resp.Body.Close()
if err != nil {
log.WithFields(log.Fields{
"appservice_id": appservice.ID,
"status_code": resp.StatusCode,
}).WithError(err).Error("Unable to close application service response body")
}
}()
}
if err != nil {
log.WithError(err).Errorf("Issue querying room alias on application service %s", appservice.ID)
return err
}
switch resp.StatusCode {
case http.StatusOK:
// OK received from appservice. Room exists
response.AliasExists = true
return nil
case http.StatusNotFound:
// Room does not exist
default:
// Application service reported an error. Warn
log.WithFields(log.Fields{
"appservice_id": appservice.ID,
"status_code": resp.StatusCode,
}).Warn("Application service responded with non-OK status code")
}
}
}
response.AliasExists = false
return nil
}
// makeHTTPClient creates an HTTP client with certain options that will be used for all query requests to application services
func makeHTTPClient() *http.Client {
return &http.Client{
Timeout: time.Second * 30,
}
}
// SetupHTTP adds the AppServiceQueryPAI handlers to the http.ServeMux. This // SetupHTTP adds the AppServiceQueryPAI handlers to the http.ServeMux. This
// handles and muxes incoming api requests the to internal AppServiceQueryAPI. // handles and muxes incoming api requests the to internal AppServiceQueryAPI.
func (a *AppServiceQueryAPI) SetupHTTP(servMux *http.ServeMux) { func (a *AppServiceQueryAPI) SetupHTTP(servMux *http.ServeMux) {
servMux.Handle(
api.AppServiceRoomAliasExistsPath,
common.MakeInternalAPI("appserviceRoomAliasExists", func(req *http.Request) util.JSONResponse {
var request api.RoomAliasExistsRequest
var response api.RoomAliasExistsResponse
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.ErrorResponse(err)
}
if err := a.RoomAliasExists(req.Context(), &request, &response); err != nil {
return util.ErrorResponse(err)
}
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
}),
)
} }

View File

@ -17,7 +17,6 @@ package workers
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/tls"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math" "math"
@ -68,12 +67,6 @@ func worker(db *storage.Database, ws types.ApplicationServiceWorkerState) {
// Create a HTTP client for sending requests to app services // Create a HTTP client for sending requests to app services
client := &http.Client{ client := &http.Client{
Timeout: transactionTimeout, Timeout: transactionTimeout,
// TODO: Verify certificates
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true, // nolint: gas
},
},
} }
// Initial check for any leftover events to send from last time // Initial check for any leftover events to send from last time

View File

@ -15,13 +15,14 @@
package routing package routing
import ( import (
"fmt"
"net/http" "net/http"
"github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/httputil"
"github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/clientapi/jsonerror"
"github.com/matrix-org/dendrite/common/config" "github.com/matrix-org/dendrite/common/config"
"github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrix"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
@ -33,7 +34,7 @@ func DirectoryRoom(
roomAlias string, roomAlias string,
federation *gomatrixserverlib.FederationClient, federation *gomatrixserverlib.FederationClient,
cfg *config.Dendrite, cfg *config.Dendrite,
aliasAPI api.RoomserverAliasAPI, rsAPI roomserverAPI.RoomserverAliasAPI,
) util.JSONResponse { ) util.JSONResponse {
_, domain, err := gomatrixserverlib.SplitID('#', roomAlias) _, domain, err := gomatrixserverlib.SplitID('#', roomAlias)
if err != nil { if err != nil {
@ -43,51 +44,48 @@ func DirectoryRoom(
} }
} }
var resp gomatrixserverlib.RespDirectory
if domain == cfg.Matrix.ServerName { if domain == cfg.Matrix.ServerName {
queryReq := api.GetRoomIDForAliasRequest{Alias: roomAlias} // Query the roomserver API to check if the alias exists locally
var queryRes api.GetRoomIDForAliasResponse queryReq := roomserverAPI.GetRoomIDForAliasRequest{Alias: roomAlias}
if err = aliasAPI.GetRoomIDForAlias(req.Context(), &queryReq, &queryRes); err != nil { var queryRes roomserverAPI.GetRoomIDForAliasResponse
if err = rsAPI.GetRoomIDForAlias(req.Context(), &queryReq, &queryRes); err != nil {
return httputil.LogThenError(req, err) return httputil.LogThenError(req, err)
} }
// List any roomIDs found associated with this alias
if len(queryRes.RoomID) > 0 { if len(queryRes.RoomID) > 0 {
// TODO: List servers that are aware of this room alias
resp = gomatrixserverlib.RespDirectory{
RoomID: queryRes.RoomID,
Servers: []gomatrixserverlib.ServerName{},
}
} else {
// If the response doesn't contain a non-empty string, return an error
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusNotFound, Code: http.StatusOK,
JSON: jsonerror.NotFound("Room alias " + roomAlias + " not found."), JSON: queryRes,
} }
} }
} else { } else {
resp, err = federation.LookupRoomAlias(req.Context(), domain, roomAlias) // Query the federation for this room alias
resp, err := federation.LookupRoomAlias(req.Context(), domain, roomAlias)
if err != nil { if err != nil {
switch x := err.(type) { switch err.(type) {
case gomatrix.HTTPError: case gomatrix.HTTPError:
if x.Code == http.StatusNotFound { default:
return util.JSONResponse{
Code: http.StatusNotFound,
JSON: jsonerror.NotFound("Room alias not found"),
}
}
}
// TODO: Return 502 if the remote server errored. // TODO: Return 502 if the remote server errored.
// TODO: Return 504 if the remote server timed out. // TODO: Return 504 if the remote server timed out.
return httputil.LogThenError(req, err) return httputil.LogThenError(req, err)
} }
} }
if len(resp.RoomID) > 0 {
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusOK, Code: http.StatusOK,
JSON: resp, JSON: resp,
} }
} }
}
return util.JSONResponse{
Code: http.StatusNotFound,
JSON: jsonerror.NotFound(
fmt.Sprintf("Room alias %s not found", roomAlias),
),
}
}
// SetLocalAlias implements PUT /directory/room/{roomAlias} // SetLocalAlias implements PUT /directory/room/{roomAlias}
// TODO: Check if the user has the power level to set an alias // TODO: Check if the user has the power level to set an alias
@ -96,7 +94,7 @@ func SetLocalAlias(
device *authtypes.Device, device *authtypes.Device,
alias string, alias string,
cfg *config.Dendrite, cfg *config.Dendrite,
aliasAPI api.RoomserverAliasAPI, aliasAPI roomserverAPI.RoomserverAliasAPI,
) util.JSONResponse { ) util.JSONResponse {
_, domain, err := gomatrixserverlib.SplitID('#', alias) _, domain, err := gomatrixserverlib.SplitID('#', alias)
if err != nil { if err != nil {
@ -138,12 +136,12 @@ func SetLocalAlias(
return *resErr return *resErr
} }
queryReq := api.SetRoomAliasRequest{ queryReq := roomserverAPI.SetRoomAliasRequest{
UserID: device.UserID, UserID: device.UserID,
RoomID: r.RoomID, RoomID: r.RoomID,
Alias: alias, Alias: alias,
} }
var queryRes api.SetRoomAliasResponse var queryRes roomserverAPI.SetRoomAliasResponse
if err := aliasAPI.SetRoomAlias(req.Context(), &queryReq, &queryRes); err != nil { if err := aliasAPI.SetRoomAlias(req.Context(), &queryReq, &queryRes); err != nil {
return httputil.LogThenError(req, err) return httputil.LogThenError(req, err)
} }
@ -167,13 +165,13 @@ func RemoveLocalAlias(
req *http.Request, req *http.Request,
device *authtypes.Device, device *authtypes.Device,
alias string, alias string,
aliasAPI api.RoomserverAliasAPI, aliasAPI roomserverAPI.RoomserverAliasAPI,
) util.JSONResponse { ) util.JSONResponse {
queryReq := api.RemoveRoomAliasRequest{ queryReq := roomserverAPI.RemoveRoomAliasRequest{
Alias: alias, Alias: alias,
UserID: device.UserID, UserID: device.UserID,
} }
var queryRes api.RemoveRoomAliasResponse var queryRes roomserverAPI.RemoveRoomAliasResponse
if err := aliasAPI.RemoveRoomAlias(req.Context(), &queryReq, &queryRes); err != nil { if err := aliasAPI.RemoveRoomAlias(req.Context(), &queryReq, &queryRes); err != nil {
return httputil.LogThenError(req, err) return httputil.LogThenError(req, err)
} }

View File

@ -29,7 +29,7 @@ import (
"github.com/matrix-org/dendrite/common" "github.com/matrix-org/dendrite/common"
"github.com/matrix-org/dendrite/common/config" "github.com/matrix-org/dendrite/common/config"
"github.com/matrix-org/dendrite/common/transactions" "github.com/matrix-org/dendrite/common/transactions"
"github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
) )
@ -42,8 +42,9 @@ const pathPrefixUnstable = "/_matrix/client/unstable"
// to clients which need to make outbound HTTP requests. // to clients which need to make outbound HTTP requests.
func Setup( func Setup(
apiMux *mux.Router, cfg config.Dendrite, apiMux *mux.Router, cfg config.Dendrite,
producer *producers.RoomserverProducer, queryAPI api.RoomserverQueryAPI, producer *producers.RoomserverProducer,
aliasAPI api.RoomserverAliasAPI, queryAPI roomserverAPI.RoomserverQueryAPI,
aliasAPI roomserverAPI.RoomserverAliasAPI,
accountDB *accounts.Database, accountDB *accounts.Database,
deviceDB *devices.Database, deviceDB *devices.Database,
federation *gomatrixserverlib.FederationClient, federation *gomatrixserverlib.FederationClient,
@ -142,7 +143,7 @@ func Setup(
})).Methods(http.MethodGet, http.MethodOptions) })).Methods(http.MethodGet, http.MethodOptions)
r0mux.Handle("/directory/room/{roomAlias}", r0mux.Handle("/directory/room/{roomAlias}",
common.MakeAuthAPI("directory_room", authData, func(req *http.Request, device *authtypes.Device) util.JSONResponse { common.MakeExternalAPI("directory_room", func(req *http.Request) util.JSONResponse {
vars := mux.Vars(req) vars := mux.Vars(req)
return DirectoryRoom(req, vars["roomAlias"], federation, &cfg, aliasAPI) return DirectoryRoom(req, vars["roomAlias"], federation, &cfg, aliasAPI)
}), }),

View File

@ -19,6 +19,8 @@ import (
"github.com/matrix-org/dendrite/common/basecomponent" "github.com/matrix-org/dendrite/common/basecomponent"
"github.com/matrix-org/dendrite/common/keydb" "github.com/matrix-org/dendrite/common/keydb"
"github.com/matrix-org/dendrite/common/transactions" "github.com/matrix-org/dendrite/common/transactions"
"github.com/matrix-org/dendrite/typingserver"
"github.com/matrix-org/dendrite/typingserver/cache"
) )
func main() { func main() {
@ -34,12 +36,11 @@ func main() {
keyRing := keydb.CreateKeyRing(federation.Client, keyDB) keyRing := keydb.CreateKeyRing(federation.Client, keyDB)
alias, input, query := base.CreateHTTPRoomserverAPIs() alias, input, query := base.CreateHTTPRoomserverAPIs()
typingInputAPI := base.CreateHTTPTypingServerAPIs() typingInputAPI := typingserver.SetupTypingServerComponent(base, cache.NewTypingCache())
cache := transactions.New()
clientapi.SetupClientAPIComponent( clientapi.SetupClientAPIComponent(
base, deviceDB, accountDB, federation, &keyRing, base, deviceDB, accountDB, federation, &keyRing,
alias, input, query, typingInputAPI, cache, alias, input, query, typingInputAPI, transactions.New(),
) )
base.SetupAndServeHTTP(string(base.Cfg.Listen.ClientAPI)) base.SetupAndServeHTTP(string(base.Cfg.Listen.ClientAPI))

View File

@ -18,7 +18,6 @@ import (
"flag" "flag"
"net/http" "net/http"
"github.com/matrix-org/dendrite/appservice"
"github.com/matrix-org/dendrite/clientapi" "github.com/matrix-org/dendrite/clientapi"
"github.com/matrix-org/dendrite/common" "github.com/matrix-org/dendrite/common"
"github.com/matrix-org/dendrite/common/basecomponent" "github.com/matrix-org/dendrite/common/basecomponent"
@ -68,7 +67,6 @@ func main() {
mediaapi.SetupMediaAPIComponent(base, deviceDB) mediaapi.SetupMediaAPIComponent(base, deviceDB)
publicroomsapi.SetupPublicRoomsAPIComponent(base, deviceDB) publicroomsapi.SetupPublicRoomsAPIComponent(base, deviceDB)
syncapi.SetupSyncAPIComponent(base, deviceDB, accountDB, query) syncapi.SetupSyncAPIComponent(base, deviceDB, accountDB, query)
appservice.SetupAppServiceAPIComponent(base, accountDB, deviceDB, federation, alias, query, transactions.New())
httpHandler := common.WrapHandlerInCORS(base.APIMux) httpHandler := common.WrapHandlerInCORS(base.APIMux)

View File

@ -21,7 +21,7 @@ import (
"github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/httputil"
"github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/clientapi/jsonerror"
"github.com/matrix-org/dendrite/common/config" "github.com/matrix-org/dendrite/common/config"
"github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrix"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
@ -32,7 +32,7 @@ func RoomAliasToID(
httpReq *http.Request, httpReq *http.Request,
federation *gomatrixserverlib.FederationClient, federation *gomatrixserverlib.FederationClient,
cfg config.Dendrite, cfg config.Dendrite,
aliasAPI api.RoomserverAliasAPI, aliasAPI roomserverAPI.RoomserverAliasAPI,
) util.JSONResponse { ) util.JSONResponse {
roomAlias := httpReq.FormValue("room_alias") roomAlias := httpReq.FormValue("room_alias")
if roomAlias == "" { if roomAlias == "" {
@ -52,8 +52,8 @@ func RoomAliasToID(
var resp gomatrixserverlib.RespDirectory var resp gomatrixserverlib.RespDirectory
if domain == cfg.Matrix.ServerName { if domain == cfg.Matrix.ServerName {
queryReq := api.GetRoomIDForAliasRequest{Alias: roomAlias} queryReq := roomserverAPI.GetRoomIDForAliasRequest{Alias: roomAlias}
var queryRes api.GetRoomIDForAliasResponse var queryRes roomserverAPI.GetRoomIDForAliasResponse
if err = aliasAPI.GetRoomIDForAlias(httpReq.Context(), &queryReq, &queryRes); err != nil { if err = aliasAPI.GetRoomIDForAlias(httpReq.Context(), &queryReq, &queryRes); err != nil {
return httputil.LogThenError(httpReq, err) return httputil.LogThenError(httpReq, err)
} }

View File

@ -23,7 +23,7 @@ import (
"github.com/matrix-org/dendrite/clientapi/producers" "github.com/matrix-org/dendrite/clientapi/producers"
"github.com/matrix-org/dendrite/common" "github.com/matrix-org/dendrite/common"
"github.com/matrix-org/dendrite/common/config" "github.com/matrix-org/dendrite/common/config"
"github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
) )
@ -37,8 +37,8 @@ const (
func Setup( func Setup(
apiMux *mux.Router, apiMux *mux.Router,
cfg config.Dendrite, cfg config.Dendrite,
query api.RoomserverQueryAPI, query roomserverAPI.RoomserverQueryAPI,
aliasAPI api.RoomserverAliasAPI, aliasAPI roomserverAPI.RoomserverAliasAPI,
producer *producers.RoomserverProducer, producer *producers.RoomserverProducer,
keys gomatrixserverlib.KeyRing, keys gomatrixserverlib.KeyRing,
federation *gomatrixserverlib.FederationClient, federation *gomatrixserverlib.FederationClient,

View File

@ -21,9 +21,10 @@ import (
"net/http" "net/http"
"time" "time"
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
"github.com/matrix-org/dendrite/common" "github.com/matrix-org/dendrite/common"
"github.com/matrix-org/dendrite/common/config" "github.com/matrix-org/dendrite/common/config"
"github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
) )
@ -44,19 +45,20 @@ type RoomserverAliasAPIDatabase interface {
RemoveRoomAlias(ctx context.Context, alias string) error RemoveRoomAlias(ctx context.Context, alias string) error
} }
// RoomserverAliasAPI is an implementation of api.RoomserverAliasAPI // RoomserverAliasAPI is an implementation of alias.RoomserverAliasAPI
type RoomserverAliasAPI struct { type RoomserverAliasAPI struct {
DB RoomserverAliasAPIDatabase DB RoomserverAliasAPIDatabase
Cfg *config.Dendrite Cfg *config.Dendrite
InputAPI api.RoomserverInputAPI InputAPI roomserverAPI.RoomserverInputAPI
QueryAPI api.RoomserverQueryAPI QueryAPI roomserverAPI.RoomserverQueryAPI
AppserviceAPI appserviceAPI.AppServiceQueryAPI
} }
// SetRoomAlias implements api.RoomserverAliasAPI // SetRoomAlias implements alias.RoomserverAliasAPI
func (r *RoomserverAliasAPI) SetRoomAlias( func (r *RoomserverAliasAPI) SetRoomAlias(
ctx context.Context, ctx context.Context,
request *api.SetRoomAliasRequest, request *roomserverAPI.SetRoomAliasRequest,
response *api.SetRoomAliasResponse, response *roomserverAPI.SetRoomAliasResponse,
) error { ) error {
// Check if the alias isn't already referring to a room // Check if the alias isn't already referring to a room
roomID, err := r.DB.GetRoomIDForAlias(ctx, request.Alias) roomID, err := r.DB.GetRoomIDForAlias(ctx, request.Alias)
@ -82,11 +84,11 @@ func (r *RoomserverAliasAPI) SetRoomAlias(
return r.sendUpdatedAliasesEvent(context.TODO(), request.UserID, request.RoomID) return r.sendUpdatedAliasesEvent(context.TODO(), request.UserID, request.RoomID)
} }
// GetRoomIDForAlias implements api.RoomserverAliasAPI // GetRoomIDForAlias implements alias.RoomserverAliasAPI
func (r *RoomserverAliasAPI) GetRoomIDForAlias( func (r *RoomserverAliasAPI) GetRoomIDForAlias(
ctx context.Context, ctx context.Context,
request *api.GetRoomIDForAliasRequest, request *roomserverAPI.GetRoomIDForAliasRequest,
response *api.GetRoomIDForAliasResponse, response *roomserverAPI.GetRoomIDForAliasResponse,
) error { ) error {
// Look up the room ID in the database // Look up the room ID in the database
roomID, err := r.DB.GetRoomIDForAlias(ctx, request.Alias) roomID, err := r.DB.GetRoomIDForAlias(ctx, request.Alias)
@ -94,15 +96,23 @@ func (r *RoomserverAliasAPI) GetRoomIDForAlias(
return err return err
} }
// No rooms found locally, try our application services by making a call to
// the appservice component
aliasReq := appserviceAPI.RoomAliasExistsRequest{Alias: request.Alias}
var aliasResp appserviceAPI.RoomAliasExistsResponse
if err = r.AppserviceAPI.RoomAliasExists(ctx, &aliasReq, &aliasResp); err != nil {
return err
}
response.RoomID = roomID response.RoomID = roomID
return nil return nil
} }
// GetAliasesForRoomID implements api.RoomserverAliasAPI // GetAliasesForRoomID implements alias.RoomserverAliasAPI
func (r *RoomserverAliasAPI) GetAliasesForRoomID( func (r *RoomserverAliasAPI) GetAliasesForRoomID(
ctx context.Context, ctx context.Context,
request *api.GetAliasesForRoomIDRequest, request *roomserverAPI.GetAliasesForRoomIDRequest,
response *api.GetAliasesForRoomIDResponse, response *roomserverAPI.GetAliasesForRoomIDResponse,
) error { ) error {
// Look up the aliases in the database for the given RoomID // Look up the aliases in the database for the given RoomID
aliases, err := r.DB.GetAliasesForRoomID(ctx, request.RoomID) aliases, err := r.DB.GetAliasesForRoomID(ctx, request.RoomID)
@ -114,11 +124,11 @@ func (r *RoomserverAliasAPI) GetAliasesForRoomID(
return nil return nil
} }
// RemoveRoomAlias implements api.RoomserverAliasAPI // RemoveRoomAlias implements alias.RoomserverAliasAPI
func (r *RoomserverAliasAPI) RemoveRoomAlias( func (r *RoomserverAliasAPI) RemoveRoomAlias(
ctx context.Context, ctx context.Context,
request *api.RemoveRoomAliasRequest, request *roomserverAPI.RemoveRoomAliasRequest,
response *api.RemoveRoomAliasResponse, response *roomserverAPI.RemoveRoomAliasResponse,
) error { ) error {
// Look up the room ID in the database // Look up the room ID in the database
roomID, err := r.DB.GetRoomIDForAlias(ctx, request.Alias) roomID, err := r.DB.GetRoomIDForAlias(ctx, request.Alias)
@ -177,11 +187,11 @@ func (r *RoomserverAliasAPI) sendUpdatedAliasesEvent(
if err != nil { if err != nil {
return err return err
} }
req := api.QueryLatestEventsAndStateRequest{ req := roomserverAPI.QueryLatestEventsAndStateRequest{
RoomID: roomID, RoomID: roomID,
StateToFetch: eventsNeeded.Tuples(), StateToFetch: eventsNeeded.Tuples(),
} }
var res api.QueryLatestEventsAndStateResponse var res roomserverAPI.QueryLatestEventsAndStateResponse
if err = r.QueryAPI.QueryLatestEventsAndState(ctx, &req, &res); err != nil { if err = r.QueryAPI.QueryLatestEventsAndState(ctx, &req, &res); err != nil {
return err return err
} }
@ -213,16 +223,16 @@ func (r *RoomserverAliasAPI) sendUpdatedAliasesEvent(
} }
// Create the request // Create the request
ire := api.InputRoomEvent{ ire := roomserverAPI.InputRoomEvent{
Kind: api.KindNew, Kind: roomserverAPI.KindNew,
Event: event, Event: event,
AuthEventIDs: event.AuthEventIDs(), AuthEventIDs: event.AuthEventIDs(),
SendAsServer: serverName, SendAsServer: serverName,
} }
inputReq := api.InputRoomEventsRequest{ inputReq := roomserverAPI.InputRoomEventsRequest{
InputRoomEvents: []api.InputRoomEvent{ire}, InputRoomEvents: []roomserverAPI.InputRoomEvent{ire},
} }
var inputRes api.InputRoomEventsResponse var inputRes roomserverAPI.InputRoomEventsResponse
// Send the request // Send the request
return r.InputAPI.InputRoomEvents(ctx, &inputReq, &inputRes) return r.InputAPI.InputRoomEvents(ctx, &inputReq, &inputRes)
@ -231,10 +241,10 @@ func (r *RoomserverAliasAPI) sendUpdatedAliasesEvent(
// SetupHTTP adds the RoomserverAliasAPI handlers to the http.ServeMux. // SetupHTTP adds the RoomserverAliasAPI handlers to the http.ServeMux.
func (r *RoomserverAliasAPI) SetupHTTP(servMux *http.ServeMux) { func (r *RoomserverAliasAPI) SetupHTTP(servMux *http.ServeMux) {
servMux.Handle( servMux.Handle(
api.RoomserverSetRoomAliasPath, roomserverAPI.RoomserverSetRoomAliasPath,
common.MakeInternalAPI("setRoomAlias", func(req *http.Request) util.JSONResponse { common.MakeInternalAPI("setRoomAlias", func(req *http.Request) util.JSONResponse {
var request api.SetRoomAliasRequest var request roomserverAPI.SetRoomAliasRequest
var response api.SetRoomAliasResponse var response roomserverAPI.SetRoomAliasResponse
if err := json.NewDecoder(req.Body).Decode(&request); err != nil { if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.ErrorResponse(err) return util.ErrorResponse(err)
} }
@ -245,10 +255,10 @@ func (r *RoomserverAliasAPI) SetupHTTP(servMux *http.ServeMux) {
}), }),
) )
servMux.Handle( servMux.Handle(
api.RoomserverGetRoomIDForAliasPath, roomserverAPI.RoomserverGetRoomIDForAliasPath,
common.MakeInternalAPI("GetRoomIDForAlias", func(req *http.Request) util.JSONResponse { common.MakeInternalAPI("GetRoomIDForAlias", func(req *http.Request) util.JSONResponse {
var request api.GetRoomIDForAliasRequest var request roomserverAPI.GetRoomIDForAliasRequest
var response api.GetRoomIDForAliasResponse var response roomserverAPI.GetRoomIDForAliasResponse
if err := json.NewDecoder(req.Body).Decode(&request); err != nil { if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.ErrorResponse(err) return util.ErrorResponse(err)
} }
@ -259,10 +269,10 @@ func (r *RoomserverAliasAPI) SetupHTTP(servMux *http.ServeMux) {
}), }),
) )
servMux.Handle( servMux.Handle(
api.RoomserverRemoveRoomAliasPath, roomserverAPI.RoomserverRemoveRoomAliasPath,
common.MakeInternalAPI("removeRoomAlias", func(req *http.Request) util.JSONResponse { common.MakeInternalAPI("removeRoomAlias", func(req *http.Request) util.JSONResponse {
var request api.RemoveRoomAliasRequest var request roomserverAPI.RemoveRoomAliasRequest
var response api.RemoveRoomAliasResponse var response roomserverAPI.RemoveRoomAliasResponse
if err := json.NewDecoder(req.Body).Decode(&request); err != nil { if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.ErrorResponse(err) return util.ErrorResponse(err)
} }

View File

@ -19,6 +19,7 @@ import (
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
asQuery "github.com/matrix-org/dendrite/appservice/query"
"github.com/matrix-org/dendrite/common/basecomponent" "github.com/matrix-org/dendrite/common/basecomponent"
"github.com/matrix-org/dendrite/roomserver/alias" "github.com/matrix-org/dendrite/roomserver/alias"
"github.com/matrix-org/dendrite/roomserver/input" "github.com/matrix-org/dendrite/roomserver/input"
@ -51,11 +52,14 @@ func SetupRoomServerComponent(
queryAPI.SetupHTTP(http.DefaultServeMux) queryAPI.SetupHTTP(http.DefaultServeMux)
asAPI := asQuery.AppServiceQueryAPI{Cfg: base.Cfg}
aliasAPI := alias.RoomserverAliasAPI{ aliasAPI := alias.RoomserverAliasAPI{
DB: roomserverDB, DB: roomserverDB,
Cfg: base.Cfg, Cfg: base.Cfg,
InputAPI: &inputAPI, InputAPI: &inputAPI,
QueryAPI: &queryAPI, QueryAPI: &queryAPI,
AppserviceAPI: &asAPI,
} }
aliasAPI.SetupHTTP(http.DefaultServeMux) aliasAPI.SetupHTTP(http.DefaultServeMux)