mirror of
https://github.com/hoernschen/dendrite.git
synced 2024-12-27 07:28:27 +00:00
Query whether a room alias exists on app services
Signed-off-by: Andrew Morgan <andrewm@matrix.org>
This commit is contained in:
parent
c87fb4d894
commit
e7ba18d4bd
20 changed files with 506 additions and 170 deletions
|
@ -113,7 +113,7 @@ listen:
|
||||||
media_api: "localhost:7774"
|
media_api: "localhost:7774"
|
||||||
public_rooms_api: "localhost:7775"
|
public_rooms_api: "localhost:7775"
|
||||||
federation_sender: "localhost:7776"
|
federation_sender: "localhost:7776"
|
||||||
appservice: "localhost:7777"
|
appservice_api: "localhost:7777"
|
||||||
|
|
||||||
# The configuration for tracing the dendrite components.
|
# The configuration for tracing the dendrite components.
|
||||||
tracing:
|
tracing:
|
||||||
|
|
95
src/github.com/matrix-org/dendrite/appservice/api/query.go
Normal file
95
src/github.com/matrix-org/dendrite/appservice/api/query.go
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
// Copyright 2018 New Vector 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 api contains methods used by dendrite components in multi-process
|
||||||
|
// mode to send requests to the appservice component, typically in order to ask
|
||||||
|
// an application service for some information.
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoomAliasExistsRequestAccessToken is a request to an application service
|
||||||
|
// about whether a room alias exists. Includes an access token
|
||||||
|
type RoomAliasExistsRequestAccessToken struct {
|
||||||
|
// Alias we want to lookup
|
||||||
|
Alias string `json:"alias"`
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// services
|
||||||
|
type AppServiceQueryAPI interface {
|
||||||
|
// Check whether a room alias exists within any application service namespaces
|
||||||
|
RoomAliasExists(
|
||||||
|
ctx context.Context,
|
||||||
|
req *RoomAliasExistsRequest,
|
||||||
|
response *RoomAliasExistsResponse,
|
||||||
|
) error
|
||||||
|
// 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
|
||||||
|
// reference to a httpClient used to reach it
|
||||||
|
type httpAppServiceQueryAPI struct {
|
||||||
|
appserviceURL string
|
||||||
|
httpClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAppServiceQueryAPIHTTP creates a AppServiceQueryAPI implemented by talking
|
||||||
|
// to a HTTP POST API.
|
||||||
|
// If httpClient is nil then it uses http.DefaultClient
|
||||||
|
func NewAppServiceQueryAPIHTTP(
|
||||||
|
appserviceURL string,
|
||||||
|
httpClient *http.Client,
|
||||||
|
) AppServiceQueryAPI {
|
||||||
|
if httpClient == nil {
|
||||||
|
httpClient = http.DefaultClient
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
|
@ -15,9 +15,13 @@
|
||||||
package appservice
|
package appservice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
"github.com/matrix-org/dendrite/appservice/consumers"
|
"github.com/matrix-org/dendrite/appservice/consumers"
|
||||||
|
"github.com/matrix-org/dendrite/appservice/query"
|
||||||
"github.com/matrix-org/dendrite/appservice/routing"
|
"github.com/matrix-org/dendrite/appservice/routing"
|
||||||
"github.com/matrix-org/dendrite/appservice/storage"
|
"github.com/matrix-org/dendrite/appservice/storage"
|
||||||
"github.com/matrix-org/dendrite/appservice/types"
|
"github.com/matrix-org/dendrite/appservice/types"
|
||||||
|
@ -25,7 +29,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
|
"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
|
||||||
"github.com/matrix-org/dendrite/common/basecomponent"
|
"github.com/matrix-org/dendrite/common/basecomponent"
|
||||||
"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/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -36,10 +40,10 @@ func SetupAppServiceAPIComponent(
|
||||||
base *basecomponent.BaseDendrite,
|
base *basecomponent.BaseDendrite,
|
||||||
accountsDB *accounts.Database,
|
accountsDB *accounts.Database,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *gomatrixserverlib.FederationClient,
|
||||||
aliasAPI api.RoomserverAliasAPI,
|
roomserverAliasAPI roomserverAPI.RoomserverAliasAPI,
|
||||||
queryAPI api.RoomserverQueryAPI,
|
roomserverQueryAPI roomserverAPI.RoomserverQueryAPI,
|
||||||
transactionsCache *transactions.Cache,
|
transactionsCache *transactions.Cache,
|
||||||
) {
|
) appserviceAPI.AppServiceQueryAPI {
|
||||||
// Create a connection to the appservice postgres DB
|
// Create a connection to the appservice postgres DB
|
||||||
appserviceDB, err := storage.NewDatabase(string(base.Cfg.Database.AppService))
|
appserviceDB, err := storage.NewDatabase(string(base.Cfg.Database.AppService))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -59,9 +63,22 @@ func SetupAppServiceAPIComponent(
|
||||||
workerStates[i] = ws
|
workerStates[i] = ws
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a HTTP client that this component will use for all outbound and
|
||||||
|
// inbound requests (inbound only for the internal API)
|
||||||
|
httpClient := &http.Client{
|
||||||
|
Timeout: time.Second * 30,
|
||||||
|
}
|
||||||
|
|
||||||
|
appserviceQueryAPI := query.AppServiceQueryAPI{
|
||||||
|
HTTPClient: httpClient,
|
||||||
|
Cfg: base.Cfg,
|
||||||
|
}
|
||||||
|
|
||||||
|
appserviceQueryAPI.SetupHTTP(http.DefaultServeMux)
|
||||||
|
|
||||||
consumer := consumers.NewOutputRoomEventConsumer(
|
consumer := consumers.NewOutputRoomEventConsumer(
|
||||||
base.Cfg, base.KafkaConsumer, accountsDB, appserviceDB,
|
base.Cfg, base.KafkaConsumer, accountsDB, appserviceDB,
|
||||||
queryAPI, aliasAPI, workerStates,
|
roomserverQueryAPI, roomserverAliasAPI, workerStates,
|
||||||
)
|
)
|
||||||
if err := consumer.Start(); err != nil {
|
if err := consumer.Start(); err != nil {
|
||||||
logrus.WithError(err).Panicf("failed to start app service roomserver consumer")
|
logrus.WithError(err).Panicf("failed to start app service roomserver consumer")
|
||||||
|
@ -74,7 +91,9 @@ func SetupAppServiceAPIComponent(
|
||||||
|
|
||||||
// Set up HTTP Endpoints
|
// Set up HTTP Endpoints
|
||||||
routing.Setup(
|
routing.Setup(
|
||||||
base.APIMux, *base.Cfg, queryAPI, aliasAPI, accountsDB,
|
base.APIMux, *base.Cfg, roomserverQueryAPI, roomserverAliasAPI,
|
||||||
federation, transactionsCache,
|
accountsDB, federation, transactionsCache,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return &appserviceQueryAPI
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,24 +179,10 @@ func (s *OutputRoomEventConsumer) filterRoomserverEvents(
|
||||||
// appserviceIsInterestedInEvent returns a boolean depending on whether a given
|
// appserviceIsInterestedInEvent returns a boolean depending on whether a given
|
||||||
// event falls within one of a given application service's namespaces.
|
// event falls within one of a given application service's namespaces.
|
||||||
func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Context, event gomatrixserverlib.Event, appservice config.ApplicationService) bool {
|
func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Context, event gomatrixserverlib.Event, appservice config.ApplicationService) bool {
|
||||||
// No reason to queue events if they'll never be sent to the application
|
// Check room_id and sender of the event
|
||||||
// service
|
if appservice.IsInterestedInUserID(event.Sender()) ||
|
||||||
if appservice.URL == "" {
|
appservice.IsInterestedInRoomID(event.RoomID()) {
|
||||||
return false
|
return true
|
||||||
}
|
|
||||||
|
|
||||||
// Check sender of the event
|
|
||||||
for _, userNamespace := range appservice.NamespaceMap["users"] {
|
|
||||||
if userNamespace.RegexpObject.MatchString(event.Sender()) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check room id of the event
|
|
||||||
for _, roomNamespace := range appservice.NamespaceMap["rooms"] {
|
|
||||||
if roomNamespace.RegexpObject.MatchString(event.RoomID()) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check all known room aliases of the room the event came from
|
// Check all known room aliases of the room the event came from
|
||||||
|
@ -204,10 +190,8 @@ func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Cont
|
||||||
var queryRes api.GetAliasesForRoomIDResponse
|
var queryRes api.GetAliasesForRoomIDResponse
|
||||||
if err := s.alias.GetAliasesForRoomID(ctx, &queryReq, &queryRes); err == nil {
|
if err := s.alias.GetAliasesForRoomID(ctx, &queryReq, &queryRes); err == nil {
|
||||||
for _, alias := range queryRes.Aliases {
|
for _, alias := range queryRes.Aliases {
|
||||||
for _, aliasNamespace := range appservice.NamespaceMap["aliases"] {
|
if appservice.IsInterestedInRoomAlias(alias) {
|
||||||
if aliasNamespace.RegexpObject.MatchString(alias) {
|
return true
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
114
src/github.com/matrix-org/dendrite/appservice/query/query.go
Normal file
114
src/github.com/matrix-org/dendrite/appservice/query/query.go
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
// Copyright 2018 New Vector 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 query handles requests from other internal dendrite components when
|
||||||
|
// they interact with the AppServiceQueryAPI.
|
||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/appservice/api"
|
||||||
|
"github.com/matrix-org/dendrite/common"
|
||||||
|
"github.com/matrix-org/dendrite/common/config"
|
||||||
|
"github.com/matrix-org/util"
|
||||||
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const remoteAppServiceRoomAliasExistsPath = "/rooms/"
|
||||||
|
|
||||||
|
// AppServiceQueryAPI is an implementation of api.AppServiceQueryAPI
|
||||||
|
type AppServiceQueryAPI struct {
|
||||||
|
HTTPClient *http.Client
|
||||||
|
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()
|
||||||
|
|
||||||
|
// 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
|
||||||
|
apiURL := appservice.URL +
|
||||||
|
remoteAppServiceRoomAliasExistsPath + request.Alias + "?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
|
||||||
|
}
|
||||||
|
resp, err := a.HTTPClient.Do(req.WithContext(ctx))
|
||||||
|
if resp != nil {
|
||||||
|
defer func() {
|
||||||
|
err = resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"appservice_id": appservice.ID,
|
||||||
|
"status_code": resp.StatusCode,
|
||||||
|
}).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
|
||||||
|
}
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
// StatusOK received from appservice. Room exists
|
||||||
|
response.AliasExists = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log non OK
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupHTTP adds the AppServiceQueryPAI handlers to the http.ServeMux. This
|
||||||
|
// handles and muxes incoming api requests the to internal AppServiceQueryAPI.
|
||||||
|
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}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
|
@ -65,7 +65,7 @@ func worker(db *storage.Database, ws types.ApplicationServiceWorkerState) {
|
||||||
}).Info("starting application service")
|
}).Info("starting application service")
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
// Grab the 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
|
// TODO: Verify certificates
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
package clientapi
|
package clientapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
|
"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
|
"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
|
||||||
"github.com/matrix-org/dendrite/clientapi/consumers"
|
"github.com/matrix-org/dendrite/clientapi/consumers"
|
||||||
|
@ -22,7 +23,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/clientapi/routing"
|
"github.com/matrix-org/dendrite/clientapi/routing"
|
||||||
"github.com/matrix-org/dendrite/common/basecomponent"
|
"github.com/matrix-org/dendrite/common/basecomponent"
|
||||||
"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/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -35,9 +36,10 @@ func SetupClientAPIComponent(
|
||||||
accountsDB *accounts.Database,
|
accountsDB *accounts.Database,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *gomatrixserverlib.FederationClient,
|
||||||
keyRing *gomatrixserverlib.KeyRing,
|
keyRing *gomatrixserverlib.KeyRing,
|
||||||
aliasAPI api.RoomserverAliasAPI,
|
aliasAPI roomserverAPI.RoomserverAliasAPI,
|
||||||
inputAPI api.RoomserverInputAPI,
|
inputAPI roomserverAPI.RoomserverInputAPI,
|
||||||
queryAPI api.RoomserverQueryAPI,
|
queryAPI roomserverAPI.RoomserverQueryAPI,
|
||||||
|
asAPI appserviceAPI.AppServiceQueryAPI,
|
||||||
transactionsCache *transactions.Cache,
|
transactionsCache *transactions.Cache,
|
||||||
) {
|
) {
|
||||||
roomserverProducer := producers.NewRoomserverProducer(inputAPI)
|
roomserverProducer := producers.NewRoomserverProducer(inputAPI)
|
||||||
|
@ -60,10 +62,8 @@ func SetupClientAPIComponent(
|
||||||
}
|
}
|
||||||
|
|
||||||
routing.Setup(
|
routing.Setup(
|
||||||
base.APIMux, *base.Cfg, roomserverProducer,
|
base.APIMux, *base.Cfg, roomserverProducer, queryAPI, asAPI, aliasAPI,
|
||||||
queryAPI, aliasAPI, accountsDB, deviceDB,
|
accountsDB, deviceDB, federation, *keyRing, userUpdateProducer,
|
||||||
federation, *keyRing,
|
syncProducer, transactionsCache,
|
||||||
userUpdateProducer, syncProducer,
|
|
||||||
transactionsCache,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,25 +15,29 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DirectoryRoom looks up a room alias
|
// DirectoryRoom looks up a room alias
|
||||||
|
// nolint: gocyclo
|
||||||
func DirectoryRoom(
|
func DirectoryRoom(
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
roomAlias string,
|
roomAlias string,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *gomatrixserverlib.FederationClient,
|
||||||
cfg *config.Dendrite,
|
cfg *config.Dendrite,
|
||||||
aliasAPI api.RoomserverAliasAPI,
|
rsAPI roomserverAPI.RoomserverAliasAPI,
|
||||||
|
asAPI appserviceAPI.AppServiceQueryAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
_, domain, err := gomatrixserverlib.SplitID('#', roomAlias)
|
_, domain, err := gomatrixserverlib.SplitID('#', roomAlias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -43,52 +47,91 @@ func DirectoryRoom(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp gomatrixserverlib.RespDirectory
|
|
||||||
|
|
||||||
if domain == cfg.Matrix.ServerName {
|
if domain == cfg.Matrix.ServerName {
|
||||||
queryReq := api.GetRoomIDForAliasRequest{Alias: roomAlias}
|
queryResp, err := getRoomIDForAlias(req, rsAPI, roomAlias)
|
||||||
var queryRes api.GetRoomIDForAliasResponse
|
if err != nil {
|
||||||
if err = aliasAPI.GetRoomIDForAlias(req.Context(), &queryReq, &queryRes); err != nil {
|
|
||||||
return httputil.LogThenError(req, err)
|
return httputil.LogThenError(req, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(queryRes.RoomID) > 0 {
|
// List any roomIDs found associated with this alias
|
||||||
// TODO: List servers that are aware of this room alias
|
if len(queryResp.RoomID) > 0 {
|
||||||
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: queryResp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No rooms found locally, try our application services by making a call to
|
||||||
|
// the appservice component
|
||||||
|
aliasReq := appserviceAPI.RoomAliasExistsRequest{Alias: roomAlias}
|
||||||
|
var aliasResp appserviceAPI.RoomAliasExistsResponse
|
||||||
|
err = asAPI.RoomAliasExists(req.Context(), &aliasReq, &aliasResp)
|
||||||
|
if err != nil {
|
||||||
|
return httputil.LogThenError(req, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if aliasResp.AliasExists {
|
||||||
|
// Query the roomserver API again. We should have the room now
|
||||||
|
queryResp, err = getRoomIDForAlias(req, rsAPI, roomAlias)
|
||||||
|
if err != nil {
|
||||||
|
return httputil.LogThenError(req, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List any roomIDs found associated with this alias
|
||||||
|
if len(queryResp.RoomID) > 0 {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: queryResp,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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{
|
// TODO: Return 502 if the remote server errored.
|
||||||
Code: http.StatusNotFound,
|
// TODO: Return 504 if the remote server timed out.
|
||||||
JSON: jsonerror.NotFound("Room alias not found"),
|
return httputil.LogThenError(req, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(resp.RoomID) > 0 {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: resp,
|
||||||
}
|
}
|
||||||
// TODO: Return 502 if the remote server errored.
|
|
||||||
// TODO: Return 504 if the remote server timed out.
|
|
||||||
return httputil.LogThenError(req, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusNotFound,
|
||||||
JSON: resp,
|
JSON: jsonerror.NotFound(
|
||||||
|
fmt.Sprintf("Room alias %s not found", roomAlias),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getRoomIDForAlias queries the roomserver API and returns a Directory Response
|
||||||
|
// on a successful query
|
||||||
|
func getRoomIDForAlias(
|
||||||
|
req *http.Request,
|
||||||
|
rsAPI roomserverAPI.RoomserverAliasAPI,
|
||||||
|
roomAlias string,
|
||||||
|
) (resp gomatrixserverlib.RespDirectory, err error) {
|
||||||
|
// Query the roomserver API to check if the alias exists locally
|
||||||
|
queryReq := roomserverAPI.GetRoomIDForAliasRequest{Alias: roomAlias}
|
||||||
|
var queryRes roomserverAPI.GetRoomIDForAliasResponse
|
||||||
|
if err = rsAPI.GetRoomIDForAlias(req.Context(), &queryReq, &queryRes); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return gomatrixserverlib.RespDirectory{
|
||||||
|
RoomID: queryRes.RoomID,
|
||||||
|
Servers: []gomatrixserverlib.ServerName{},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
func SetLocalAlias(
|
func SetLocalAlias(
|
||||||
|
@ -96,7 +139,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 +181,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 +210,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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -318,8 +318,8 @@ func UserIDIsWithinApplicationServiceNamespace(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through all known application service's namespaces and see if any match
|
// Loop through all known application service's namespaces and see if any match
|
||||||
for _, knownAppservice := range cfg.Derived.ApplicationServices {
|
for _, knownAppService := range cfg.Derived.ApplicationServices {
|
||||||
for _, namespace := range knownAppservice.NamespaceMap["users"] {
|
for _, namespace := range knownAppService.NamespaceMap["users"] {
|
||||||
// AS namespaces are checked for validity in config
|
// AS namespaces are checked for validity in config
|
||||||
if namespace.RegexpObject.MatchString(userID) {
|
if namespace.RegexpObject.MatchString(userID) {
|
||||||
return true
|
return true
|
||||||
|
@ -338,16 +338,13 @@ func UsernameMatchesMultipleExclusiveNamespaces(
|
||||||
// Check namespaces and see if more than one match
|
// Check namespaces and see if more than one match
|
||||||
matchCount := 0
|
matchCount := 0
|
||||||
for _, appservice := range cfg.Derived.ApplicationServices {
|
for _, appservice := range cfg.Derived.ApplicationServices {
|
||||||
for _, namespaceSlice := range appservice.NamespaceMap {
|
if appservice.IsInterestedInUserID(username) {
|
||||||
for _, namespace := range namespaceSlice {
|
if matchCount++; matchCount > 1 {
|
||||||
// Check if we have a match on this username
|
return true
|
||||||
if namespace.RegexpObject.MatchString(username) {
|
|
||||||
matchCount++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return matchCount > 1
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateApplicationService checks if a provided application service token
|
// validateApplicationService checks if a provided application service token
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
|
"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
|
"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
|
||||||
|
@ -28,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"
|
||||||
)
|
)
|
||||||
|
@ -41,8 +42,8 @@ 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, queryAPI roomserverAPI.RoomserverQueryAPI,
|
||||||
aliasAPI api.RoomserverAliasAPI,
|
appserviceAPI appserviceAPI.AppServiceQueryAPI, aliasAPI roomserverAPI.RoomserverAliasAPI,
|
||||||
accountDB *accounts.Database,
|
accountDB *accounts.Database,
|
||||||
deviceDB *devices.Database,
|
deviceDB *devices.Database,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *gomatrixserverlib.FederationClient,
|
||||||
|
@ -138,9 +139,9 @@ 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", deviceDB, 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, appserviceAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,12 @@ func main() {
|
||||||
keyRing := keydb.CreateKeyRing(federation.Client, keyDB)
|
keyRing := keydb.CreateKeyRing(federation.Client, keyDB)
|
||||||
|
|
||||||
alias, input, query := base.CreateHTTPRoomserverAPIs()
|
alias, input, query := base.CreateHTTPRoomserverAPIs()
|
||||||
|
asQuery := base.CreateHTTPAppServiceAPIs()
|
||||||
cache := transactions.New()
|
cache := transactions.New()
|
||||||
|
|
||||||
clientapi.SetupClientAPIComponent(
|
clientapi.SetupClientAPIComponent(
|
||||||
base, deviceDB, accountDB, federation, &keyRing,
|
base, deviceDB, accountDB, federation, &keyRing,
|
||||||
alias, input, query, cache,
|
alias, input, query, asQuery, cache,
|
||||||
)
|
)
|
||||||
|
|
||||||
base.SetupAndServeHTTP(string(base.Cfg.Listen.ClientAPI))
|
base.SetupAndServeHTTP(string(base.Cfg.Listen.ClientAPI))
|
||||||
|
|
|
@ -55,10 +55,13 @@ func main() {
|
||||||
keyRing := keydb.CreateKeyRing(federation.Client, keyDB)
|
keyRing := keydb.CreateKeyRing(federation.Client, keyDB)
|
||||||
|
|
||||||
alias, input, query := roomserver.SetupRoomServerComponent(base)
|
alias, input, query := roomserver.SetupRoomServerComponent(base)
|
||||||
|
asQuery := appservice.SetupAppServiceAPIComponent(
|
||||||
|
base, accountDB, federation, alias, query, transactions.New(),
|
||||||
|
)
|
||||||
|
|
||||||
clientapi.SetupClientAPIComponent(
|
clientapi.SetupClientAPIComponent(
|
||||||
base, deviceDB, accountDB,
|
base, deviceDB, accountDB,
|
||||||
federation, &keyRing, alias, input, query,
|
federation, &keyRing, alias, input, query, asQuery,
|
||||||
transactions.New(),
|
transactions.New(),
|
||||||
)
|
)
|
||||||
federationapi.SetupFederationAPIComponent(base, accountDB, deviceDB, federation, &keyRing, alias, input, query)
|
federationapi.SetupFederationAPIComponent(base, accountDB, deviceDB, federation, &keyRing, alias, input, query)
|
||||||
|
@ -66,7 +69,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, federation, alias, query, transactions.New())
|
|
||||||
|
|
||||||
httpHandler := common.WrapHandlerInCORS(base.APIMux)
|
httpHandler := common.WrapHandlerInCORS(base.APIMux)
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,9 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
sarama "gopkg.in/Shopify/sarama.v1"
|
sarama "gopkg.in/Shopify/sarama.v1"
|
||||||
|
|
||||||
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
"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/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -80,12 +81,22 @@ func (b *BaseDendrite) Close() error {
|
||||||
return b.tracerCloser.Close()
|
return b.tracerCloser.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateHTTPRoomserverAPIs returns the AliasAPI, InputAPI and QueryAPI to hit
|
// CreateHTTPAppServiceAPIs returns the QueryAPI for hitting the appservice
|
||||||
|
// component over HTTP.
|
||||||
|
func (b *BaseDendrite) CreateHTTPAppServiceAPIs() appserviceAPI.AppServiceQueryAPI {
|
||||||
|
return appserviceAPI.NewAppServiceQueryAPIHTTP(b.Cfg.AppServiceURL(), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateHTTPRoomserverAPIs returns the AliasAPI, InputAPI and QueryAPI for hitting
|
||||||
// the roomserver over HTTP.
|
// the roomserver over HTTP.
|
||||||
func (b *BaseDendrite) CreateHTTPRoomserverAPIs() (api.RoomserverAliasAPI, api.RoomserverInputAPI, api.RoomserverQueryAPI) {
|
func (b *BaseDendrite) CreateHTTPRoomserverAPIs() (
|
||||||
alias := api.NewRoomserverAliasAPIHTTP(b.Cfg.RoomServerURL(), nil)
|
roomserverAPI.RoomserverAliasAPI,
|
||||||
input := api.NewRoomserverInputAPIHTTP(b.Cfg.RoomServerURL(), nil)
|
roomserverAPI.RoomserverInputAPI,
|
||||||
query := api.NewRoomserverQueryAPIHTTP(b.Cfg.RoomServerURL(), nil)
|
roomserverAPI.RoomserverQueryAPI,
|
||||||
|
) {
|
||||||
|
alias := roomserverAPI.NewRoomserverAliasAPIHTTP(b.Cfg.RoomServerURL(), nil)
|
||||||
|
input := roomserverAPI.NewRoomserverInputAPIHTTP(b.Cfg.RoomServerURL(), nil)
|
||||||
|
query := roomserverAPI.NewRoomserverQueryAPIHTTP(b.Cfg.RoomServerURL(), nil)
|
||||||
return alias, input, query
|
return alias, input, query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,9 +66,57 @@ type ApplicationService struct {
|
||||||
Protocols []string `yaml:"protocols"`
|
Protocols []string `yaml:"protocols"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadAppservices iterates through all application service config files
|
// IsInterestedInRoomID returns a bool on whether an application service's
|
||||||
|
// namespace includes the given room ID
|
||||||
|
func (a *ApplicationService) IsInterestedInRoomID(
|
||||||
|
roomID string,
|
||||||
|
) bool {
|
||||||
|
if namespaceSlice, ok := a.NamespaceMap["users"]; ok {
|
||||||
|
for _, namespace := range namespaceSlice {
|
||||||
|
if namespace.RegexpObject.MatchString(roomID) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInterestedInUserID returns a bool on whether an application service's
|
||||||
|
// namespace includes the given user ID
|
||||||
|
func (a *ApplicationService) IsInterestedInUserID(
|
||||||
|
userID string,
|
||||||
|
) bool {
|
||||||
|
if namespaceSlice, ok := a.NamespaceMap["users"]; ok {
|
||||||
|
for _, namespace := range namespaceSlice {
|
||||||
|
if namespace.RegexpObject.MatchString(userID) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInterestedInRoomAlias returns a bool on whether an application service's
|
||||||
|
// namespace includes the given room alias
|
||||||
|
func (a *ApplicationService) IsInterestedInRoomAlias(
|
||||||
|
roomAlias string,
|
||||||
|
) bool {
|
||||||
|
if namespaceSlice, ok := a.NamespaceMap["aliases"]; ok {
|
||||||
|
for _, namespace := range namespaceSlice {
|
||||||
|
if namespace.RegexpObject.MatchString(roomAlias) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadAppServices iterates through all application service config files
|
||||||
// and loads their data into the config object for later access.
|
// and loads their data into the config object for later access.
|
||||||
func loadAppservices(config *Dendrite) error {
|
func loadAppServices(config *Dendrite) error {
|
||||||
for _, configPath := range config.ApplicationServices.ConfigFiles {
|
for _, configPath := range config.ApplicationServices.ConfigFiles {
|
||||||
// Create a new application service with default options
|
// Create a new application service with default options
|
||||||
appservice := ApplicationService{
|
appservice := ApplicationService{
|
||||||
|
|
|
@ -198,6 +198,7 @@ type Dendrite struct {
|
||||||
MediaAPI Address `yaml:"media_api"`
|
MediaAPI Address `yaml:"media_api"`
|
||||||
ClientAPI Address `yaml:"client_api"`
|
ClientAPI Address `yaml:"client_api"`
|
||||||
FederationAPI Address `yaml:"federation_api"`
|
FederationAPI Address `yaml:"federation_api"`
|
||||||
|
AppServiceAPI Address `yaml:"appservice_api"`
|
||||||
SyncAPI Address `yaml:"sync_api"`
|
SyncAPI Address `yaml:"sync_api"`
|
||||||
RoomServer Address `yaml:"room_server"`
|
RoomServer Address `yaml:"room_server"`
|
||||||
FederationSender Address `yaml:"federation_sender"`
|
FederationSender Address `yaml:"federation_sender"`
|
||||||
|
@ -408,7 +409,7 @@ func (config *Dendrite) derive() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load application service configuration files
|
// Load application service configuration files
|
||||||
if err := loadAppservices(config); err != nil {
|
if err := loadAppServices(config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,6 +641,15 @@ func fingerprintPEM(data []byte) *gomatrixserverlib.TLSFingerprint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AppServiceURL returns a HTTP URL for where the appservice component is listening.
|
||||||
|
func (config *Dendrite) AppServiceURL() string {
|
||||||
|
// Hard code the roomserver to talk HTTP for now.
|
||||||
|
// If we support HTTPS we need to think of a practical way to do certificate validation.
|
||||||
|
// People setting up servers shouldn't need to get a certificate valid for the public
|
||||||
|
// internet for an internal API.
|
||||||
|
return "http://" + string(config.Listen.AppServiceAPI)
|
||||||
|
}
|
||||||
|
|
||||||
// RoomServerURL returns an HTTP URL for where the roomserver is listening.
|
// RoomServerURL returns an HTTP URL for where the roomserver is listening.
|
||||||
func (config *Dendrite) RoomServerURL() string {
|
func (config *Dendrite) RoomServerURL() string {
|
||||||
// Hard code the roomserver to talk HTTP for now.
|
// Hard code the roomserver to talk HTTP for now.
|
||||||
|
|
57
src/github.com/matrix-org/dendrite/common/http/http.go
Normal file
57
src/github.com/matrix-org/dendrite/common/http/http.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
|
"github.com/opentracing/opentracing-go/ext"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PostJSON performs a POST request with JSON on an internal HTTP API
|
||||||
|
func PostJSON(
|
||||||
|
ctx context.Context, span opentracing.Span, httpClient *http.Client,
|
||||||
|
apiURL string, request, response interface{},
|
||||||
|
) error {
|
||||||
|
jsonBytes, err := json.Marshal(request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, apiURL, bytes.NewReader(jsonBytes))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the span as being an RPC client.
|
||||||
|
ext.SpanKindRPCClient.Set(span)
|
||||||
|
carrier := opentracing.HTTPHeadersCarrier(req.Header)
|
||||||
|
tracer := opentracing.GlobalTracer()
|
||||||
|
|
||||||
|
if err = tracer.Inject(span.Context(), opentracing.HTTPHeaders, carrier); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
res, err := httpClient.Do(req.WithContext(ctx))
|
||||||
|
if res != nil {
|
||||||
|
defer (func() { err = res.Body.Close() })()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if res.StatusCode != http.StatusOK {
|
||||||
|
var errorBody struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
if err = json.NewDecoder(res.Body).Decode(&errorBody); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fmt.Errorf("api: %d: %s", res.StatusCode, errorBody.Message)
|
||||||
|
}
|
||||||
|
return json.NewDecoder(res.Body).Decode(response)
|
||||||
|
}
|
|
@ -44,7 +44,7 @@ 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
|
||||||
|
@ -52,7 +52,7 @@ type RoomserverAliasAPI struct {
|
||||||
QueryAPI api.RoomserverQueryAPI
|
QueryAPI api.RoomserverQueryAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 *api.SetRoomAliasRequest,
|
||||||
|
@ -82,7 +82,7 @@ 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 *api.GetRoomIDForAliasRequest,
|
||||||
|
@ -98,7 +98,7 @@ func (r *RoomserverAliasAPI) GetRoomIDForAlias(
|
||||||
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 *api.GetAliasesForRoomIDRequest,
|
||||||
|
@ -114,7 +114,7 @@ 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 *api.RemoveRoomAliasRequest,
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
commonHTTP "github.com/matrix-org/dendrite/common/http"
|
||||||
opentracing "github.com/opentracing/opentracing-go"
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -139,7 +140,7 @@ func (h *httpRoomserverAliasAPI) SetRoomAlias(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverSetRoomAliasPath
|
apiURL := h.roomserverURL + RoomserverSetRoomAliasPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRoomIDForAlias implements RoomserverAliasAPI
|
// GetRoomIDForAlias implements RoomserverAliasAPI
|
||||||
|
@ -152,7 +153,7 @@ func (h *httpRoomserverAliasAPI) GetRoomIDForAlias(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverGetRoomIDForAliasPath
|
apiURL := h.roomserverURL + RoomserverGetRoomIDForAliasPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAliasesForRoomID implements RoomserverAliasAPI
|
// GetAliasesForRoomID implements RoomserverAliasAPI
|
||||||
|
@ -165,7 +166,7 @@ func (h *httpRoomserverAliasAPI) GetAliasesForRoomID(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverGetAliasesForRoomIDPath
|
apiURL := h.roomserverURL + RoomserverGetAliasesForRoomIDPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveRoomAlias implements RoomserverAliasAPI
|
// RemoveRoomAlias implements RoomserverAliasAPI
|
||||||
|
@ -178,5 +179,5 @@ func (h *httpRoomserverAliasAPI) RemoveRoomAlias(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverRemoveRoomAliasPath
|
apiURL := h.roomserverURL + RoomserverRemoveRoomAliasPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
commonHTTP "github.com/matrix-org/dendrite/common/http"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
opentracing "github.com/opentracing/opentracing-go"
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
)
|
)
|
||||||
|
@ -134,5 +135,5 @@ func (h *httpRoomserverInputAPI) InputRoomEvents(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverInputRoomEventsPath
|
apiURL := h.roomserverURL + RoomserverInputRoomEventsPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,16 +15,12 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
opentracing "github.com/opentracing/opentracing-go"
|
commonHTTP "github.com/matrix-org/dendrite/common/http"
|
||||||
"github.com/opentracing/opentracing-go/ext"
|
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// QueryLatestEventsAndStateRequest is a request to QueryLatestEventsAndState
|
// QueryLatestEventsAndStateRequest is a request to QueryLatestEventsAndState
|
||||||
|
@ -308,7 +304,7 @@ func (h *httpRoomserverQueryAPI) QueryLatestEventsAndState(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverQueryLatestEventsAndStatePath
|
apiURL := h.roomserverURL + RoomserverQueryLatestEventsAndStatePath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryStateAfterEvents implements RoomserverQueryAPI
|
// QueryStateAfterEvents implements RoomserverQueryAPI
|
||||||
|
@ -321,7 +317,7 @@ func (h *httpRoomserverQueryAPI) QueryStateAfterEvents(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverQueryStateAfterEventsPath
|
apiURL := h.roomserverURL + RoomserverQueryStateAfterEventsPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryEventsByID implements RoomserverQueryAPI
|
// QueryEventsByID implements RoomserverQueryAPI
|
||||||
|
@ -334,7 +330,7 @@ func (h *httpRoomserverQueryAPI) QueryEventsByID(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverQueryEventsByIDPath
|
apiURL := h.roomserverURL + RoomserverQueryEventsByIDPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryMembershipsForRoom implements RoomserverQueryAPI
|
// QueryMembershipsForRoom implements RoomserverQueryAPI
|
||||||
|
@ -347,7 +343,7 @@ func (h *httpRoomserverQueryAPI) QueryMembershipsForRoom(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverQueryMembershipsForRoomPath
|
apiURL := h.roomserverURL + RoomserverQueryMembershipsForRoomPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryInvitesForUser implements RoomserverQueryAPI
|
// QueryInvitesForUser implements RoomserverQueryAPI
|
||||||
|
@ -360,7 +356,7 @@ func (h *httpRoomserverQueryAPI) QueryInvitesForUser(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverQueryInvitesForUserPath
|
apiURL := h.roomserverURL + RoomserverQueryInvitesForUserPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryServerAllowedToSeeEvent implements RoomserverQueryAPI
|
// QueryServerAllowedToSeeEvent implements RoomserverQueryAPI
|
||||||
|
@ -373,7 +369,7 @@ func (h *httpRoomserverQueryAPI) QueryServerAllowedToSeeEvent(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverQueryServerAllowedToSeeEventPath
|
apiURL := h.roomserverURL + RoomserverQueryServerAllowedToSeeEventPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryMissingEvents implements RoomServerQueryAPI
|
// QueryMissingEvents implements RoomServerQueryAPI
|
||||||
|
@ -386,7 +382,7 @@ func (h *httpRoomserverQueryAPI) QueryMissingEvents(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverQueryMissingEventsPath
|
apiURL := h.roomserverURL + RoomserverQueryMissingEventsPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryStateAndAuthChain implements RoomserverQueryAPI
|
// QueryStateAndAuthChain implements RoomserverQueryAPI
|
||||||
|
@ -399,49 +395,5 @@ func (h *httpRoomserverQueryAPI) QueryStateAndAuthChain(
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
|
|
||||||
apiURL := h.roomserverURL + RoomserverQueryStateAndAuthChainPath
|
apiURL := h.roomserverURL + RoomserverQueryStateAndAuthChainPath
|
||||||
return postJSON(ctx, span, h.httpClient, apiURL, request, response)
|
return commonHTTP.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||||
}
|
|
||||||
|
|
||||||
func postJSON(
|
|
||||||
ctx context.Context, span opentracing.Span, httpClient *http.Client,
|
|
||||||
apiURL string, request, response interface{},
|
|
||||||
) error {
|
|
||||||
jsonBytes, err := json.Marshal(request)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodPost, apiURL, bytes.NewReader(jsonBytes))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark the span as being an RPC client.
|
|
||||||
ext.SpanKindRPCClient.Set(span)
|
|
||||||
carrier := opentracing.HTTPHeadersCarrier(req.Header)
|
|
||||||
tracer := opentracing.GlobalTracer()
|
|
||||||
|
|
||||||
if err = tracer.Inject(span.Context(), opentracing.HTTPHeaders, carrier); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
res, err := httpClient.Do(req.WithContext(ctx))
|
|
||||||
if res != nil {
|
|
||||||
defer (func() { err = res.Body.Close() })()
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if res.StatusCode != http.StatusOK {
|
|
||||||
var errorBody struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
if err = json.NewDecoder(res.Body).Decode(&errorBody); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return fmt.Errorf("api: %d: %s", res.StatusCode, errorBody.Message)
|
|
||||||
}
|
|
||||||
return json.NewDecoder(res.Body).Decode(response)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue