dendrite/roomserver/canonical_alias/canonical_alias.go
2020-01-25 09:05:46 +05:30

226 lines
8.2 KiB
Go

// Copyright 2020 The Matrix.org Foundation C.I.C.
//
// 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 canonical_alias
import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
"github.com/matrix-org/dendrite/common"
"github.com/matrix-org/dendrite/common/config"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util"
)
// RoomserverCanonicalAliasAPIDatabase has the storage APIs needed to implement the alias API.
type RoomserverCanonicalAPIDatabase interface {
// Save a given canonical room alias with the room ID it refers to.
// Returns an error if there was a problem talking to the database.
SetRoomCanonicalAlias(ctx context.Context, canonical_alias string, roomID string, creatorUserID string) error
// Look up the room ID a given canonical alias refers to.
// Returns an error if there was a problem talking to the database.
GetRoomIDForCanonicalAlias(ctx context.Context, canonical_alias string) (string, error)
// Look up the canonical alias referring to a given room ID.
// Returns an error if there was a problem talking to the database.
GetCanonicalAliasForRoomID(ctx context.Context, roomID string) (string, error)
// Get the user ID of the creator of the canonical alias.
// Returns an error if there was a problem talking to the database.
GetCreatorIDForCanonicalAlias(ctx context.Context, canonical_alias string) (string, error)
// Remove a given room canonical alias.
// Returns an error if there was a problem talking to the database.
RemoveRoomCanonicalAlias(ctx context.Context, canonical_alias string) error
}
// RoomserverCanonicalAliasAPI is an implementation of alias.RoomserverCanonicalAliasAPI
type RoomserverCanonicalAliasAPI struct {
DB RoomserverCanonicalAPIDatabase
Cfg *config.Dendrite
InputAPI roomserverAPI.RoomserverInputAPI
QueryAPI roomserverAPI.RoomserverQueryAPI
AppserviceAPI appserviceAPI.AppServiceQueryAPI
}
// SetRoomCanonicalAlias implements alias.RoomserverCanonicalAliasAPI
func (r *RoomserverCanonicalAliasAPI) SetRoomAlias(
ctx context.Context,
request *roomserverAPI.SetRoomCanonicalAliasRequest,
response *roomserverAPI.SetRoomCanonicalAliasResponse,
) error {
// SPEC: Room with `m.room.canonical_alias` with empty alias field should be
// treated same as room without a canonical alias.
if request.CanonicalAlias == "" {
return r.db.RemoveCanonicalAlias(ctx, request.RoomID)
}
roomID, err := r.DB.GetRoomIDForAlias(ctx, request.CanonicalAlias)
if err != nil {
return err
}
// Check if alias exists
if len(roomID) == 0 {
response.AliasExists = false
return nil
}
response.AliasExists = true
// The alias belongs to a different room
if roomID != request.roomID {
// RFC: Is there a standard bool for wrong room?
response.DifferentRoom = true
return nil
}
response.DifferentRoom = false
// Save the new canonical alias
if err := r.DB.SetRoomCanonicalAlias(ctx, request.CanonicalAlias, request.RoomID, request.UserID); err != nil {
return err
}
return nil
}
// GetRoomIDForCanonicalAlias implements alias.RoomserverCanonicalAliasAPI
func (r *RoomserverCanonicalAliasAPI) GetRoomIDForCanonicalAlias(
ctx context.Context,
request *roomserverAPI.GetRoomIDForCanonicalAliasRequest,
response *roomserverAPI.GetRoomIDForCanonicalAliasResponse,
) error {
// Look up the room ID in the database
roomID, err := r.DB.GetRoomIDForCanonicalAlias(ctx, request.Alias)
if err != nil {
return err
}
// RFC: Should we search in application service for canonical aliases?`
if roomID == "" {
// No room 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
}
if aliasResp.AliasExists {
roomID, err = r.DB.GetRoomIDForAlias(ctx, request.Alias)
if err != nil {
return err
}
}
}
response.RoomID = roomID
return nil
}
// GetCanonicalAliasForRoomID implements alias.RoomserverCanonicalAliasAPI
func (r *RoomserverCanonicalAliasAPI) GetCanonicalAliasForRoomID(
ctx context.Context,
request *roomserverAPI.GetCanonicalAliasForRoomIDRequest,
response *roomserverAPI.GetCanonicalAliasForRoomIDResponse,
) error {
// Look up the canonical alias in the database for the given RoomID
canonicalAlias, err := r.DB.GetCanonicalAliasForRoomID(ctx, request.RoomID)
if err != nil {
return err
}
response.CanonicalAlias = canonicalAlias
return nil
}
// GetCreatorIDForCanonicalAlias implements alias.RoomserverCanonicalAliasAPI
func (r *RoomserverCanonicalAliasAPI) GetCreatorIDForCanonicalAlias(
ctx context.Context,
request *roomserverAPI.GetCreatorIDForCanonicalAliasRequest,
response *roomserverAPI.GetCreatorIDForCanonicalAliasResponse,
) error {
// Look up the aliases in the database for the given RoomID
creatorID, err := r.DB.GetCreatorIDForCanonicalAlias(ctx, request.CanonicalAlias)
if err != nil {
return err
}
response.UserID = creatorID
return nil
}
// SetupHTTP adds the RoomserverCanonicalAliasAPI handlers to the http.ServeMux.
func (r *RoomserverCanonicalAliasAPI) SetupHTTP(servMux *http.ServeMux) {
servMux.Handle(
roomserverAPI.RoomserverSetRoomCanonicalAliasPath,
common.MakeInternalAPI("setRoomCanonicalAlias", func(req *http.Request) util.JSONResponse {
var request roomserverAPI.SetRoomCanonicalAliasRequest
var response roomserverAPI.SetRoomCanonicalAliasResponse
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.ErrorResponse(err)
}
if err := r.SetRoomCanonicalAlias(req.Context(), &request, &response); err != nil {
return util.ErrorResponse(err)
}
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
}),
)
servMux.Handle(
roomserverAPI.RoomserverGetRoomIDForCanonicalAliasPath,
common.MakeInternalAPI("GetRoomIDForCanonicalAlias", func(req *http.Request) util.JSONResponse {
var request roomserverAPI.GetRoomIDForCanonicalAliasRequest
var response roomserverAPI.GetRoomIDForCanonicalAliasResponse
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.ErrorResponse(err)
}
if err := r.GetRoomIDForCanonicalAlias(req.Context(), &request, &response); err != nil {
return util.ErrorResponse(err)
}
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
}),
)
servMux.Handle(
roomserverAPI.RoomserverGetCreatorIDForCanonicalAliasPath,
common.MakeInternalAPI("GetCreatorIDForCanonicalAlias", func(req *http.Request) util.JSONResponse {
var request roomserverAPI.GetCreatorIDForCanonicalAliasRequest
var response roomserverAPI.GetCreatorIDForCanonicalAliasResponse
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.ErrorResponse(err)
}
if err := r.GetCreatorIDForCanonicalAlias(req.Context(), &request, &response); err != nil {
return util.ErrorResponse(err)
}
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
}),
)
servMux.Handle(
roomserverAPI.RoomserverGetCanonicalAliasForRoomIDPath,
common.MakeInternalAPI("getCanonicalAliasForRoomID", func(req *http.Request) util.JSONResponse {
var request roomserverAPI.GetCanonicalAliasForRoomIDRequest
var response roomserverAPI.GetCanonicalAliasForRoomIDResponse
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
return util.ErrorResponse(err)
}
if err := r.GetCanonicalAliasForRoomID(req.Context(), &request, &response); err != nil {
return util.ErrorResponse(err)
}
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
}),
)
}