Add canonical support

This commit is contained in:
Till Faelligen 2022-03-01 13:27:14 +01:00
parent 58bf91a585
commit b544169cf9
5 changed files with 136 additions and 4 deletions

View file

@ -58,6 +58,11 @@ func BadJSON(msg string) *MatrixError {
return &MatrixError{"M_BAD_JSON", msg} return &MatrixError{"M_BAD_JSON", msg}
} }
// BadAlias is an error when the client supplies a bad alias.
func BadAlias(msg string) *MatrixError {
return &MatrixError{"M_BAD_ALIAS", msg}
}
// NotJSON is an error when the client supplies something that is not JSON // NotJSON is an error when the client supplies something that is not JSON
// to a JSON endpoint. // to a JSON endpoint.
func NotJSON(msg string) *MatrixError { func NotJSON(msg string) *MatrixError {

View file

@ -16,6 +16,8 @@ package routing
import ( import (
"context" "context"
"encoding/json"
"fmt"
"net/http" "net/http"
"sync" "sync"
"time" "time"
@ -120,6 +122,40 @@ func SendEvent(
} }
timeToGenerateEvent := time.Since(startedGeneratingEvent) timeToGenerateEvent := time.Since(startedGeneratingEvent)
// validate that the aliases exists
if eventType == gomatrixserverlib.MRoomCanonicalAlias {
aliasReq := api.AliasEvent{}
if err = json.Unmarshal(e.Content(), &aliasReq); err != nil {
return util.ErrorResponse(fmt.Errorf("unable to parse alias event: %w", err))
}
if !aliasReq.Valid() {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: jsonerror.InvalidParam("Request contains invalid aliases."),
}
}
aliasRes := &api.GetAliasesForRoomIDResponse{}
if err = rsAPI.GetAliasesForRoomID(req.Context(), &api.GetAliasesForRoomIDRequest{RoomID: roomID}, aliasRes); err != nil {
return jsonerror.InternalServerError()
}
var found int
requestAliases := append(aliasReq.AltAliases, aliasReq.Alias)
for _, alias := range aliasRes.Aliases {
for _, altAlias := range requestAliases {
if altAlias == alias {
found++
}
}
}
// check that we found at least the same amount of existing aliases as are in the request
if aliasReq.Alias != "" && found < len(requestAliases) {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: jsonerror.BadAlias("No matching alias found."),
}
}
}
var txnAndSessionID *api.TransactionID var txnAndSessionID *api.TransactionID
if txnID != nil { if txnID != nil {
txnAndSessionID = &api.TransactionID{ txnAndSessionID = &api.TransactionID{

View file

@ -14,6 +14,8 @@
package api package api
import "regexp"
// SetRoomAliasRequest is a request to SetRoomAlias // SetRoomAliasRequest is a request to SetRoomAlias
type SetRoomAliasRequest struct { type SetRoomAliasRequest struct {
// ID of the user setting the alias // ID of the user setting the alias
@ -84,3 +86,27 @@ type RemoveRoomAliasResponse struct {
// Did we remove it? // Did we remove it?
Removed bool `json:"removed"` Removed bool `json:"removed"`
} }
type AliasEvent struct {
Alias string `json:"alias"`
AltAliases []string `json:"alt_aliases"`
}
var validateAliasRegex = regexp.MustCompile("^#.*:.+$")
func (a AliasEvent) Valid() bool {
// alias is set to be removed
if a.Alias == "" {
return true
}
if !validateAliasRegex.MatchString(a.Alias) {
return false
}
for _, alias := range a.AltAliases {
if !validateAliasRegex.MatchString(alias) {
return false
}
}
return true
}

View file

@ -16,12 +16,15 @@ package internal
import ( import (
"context" "context"
"database/sql"
"fmt" "fmt"
"time"
"github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/gomatrixserverlib"
asAPI "github.com/matrix-org/dendrite/appservice/api" asAPI "github.com/matrix-org/dendrite/appservice/api"
"github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/gomatrixserverlib"
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"
) )
// RoomserverInternalAPIDatabase has the storage APIs needed to implement the alias API. // RoomserverInternalAPIDatabase has the storage APIs needed to implement the alias API.
@ -183,6 +186,65 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias(
} }
} }
ev, err := r.DB.GetStateEvent(ctx, roomID, gomatrixserverlib.MRoomCanonicalAlias, "")
if err != nil && err != sql.ErrNoRows {
return err
}
stateAlias := gjson.GetBytes(ev.Content(), "alias").Str
// the alias to remove is currently set as the canonical alias, remove it
if stateAlias == request.Alias {
res, err := sjson.DeleteBytes(ev.Content(), "alias")
if err != nil {
return err
}
stateRes := &api.QueryLatestEventsAndStateResponse{}
if err = r.QueryLatestEventsAndState(ctx, &api.QueryLatestEventsAndStateRequest{RoomID: roomID}, stateRes); err != nil {
return err
}
stateEventIDs := make([]string, len(stateRes.StateEvents))
for i, ev := range stateRes.StateEvents {
stateEventIDs[i] = ev.EventID()
}
sender := request.UserID
if request.UserID != ev.Sender() {
sender = ev.Sender()
}
builder := &gomatrixserverlib.EventBuilder{
Sender: sender,
RoomID: ev.RoomID(),
Type: ev.Type(),
StateKey: ev.StateKey(),
PrevEvents: []string{ev.EventID()},
AuthEvents: stateEventIDs,
Content: res,
}
newEvent, err := builder.Build(time.Now(), r.ServerName, r.Cfg.Matrix.KeyID, r.Cfg.Matrix.PrivateKey, ev.RoomVersion)
if err != nil {
return err
}
inputEvent := api.InputRoomEvent{
Kind: api.KindNew,
Event: newEvent.Headered(ev.RoomVersion),
Origin: r.ServerName,
StateEventIDs: stateEventIDs,
HasState: true,
SendAsServer: string(r.ServerName),
}
respInput := &api.InputRoomEventsResponse{}
r.InputRoomEvents(ctx, &api.InputRoomEventsRequest{InputRoomEvents: []api.InputRoomEvent{inputEvent}}, respInput)
if respInput.NotAllowed || respInput.ErrMsg != "" {
return fmt.Errorf(respInput.ErrMsg)
}
}
// Remove the alias from the database // Remove the alias from the database
if err := r.DB.RemoveRoomAlias(ctx, request.Alias); err != nil { if err := r.DB.RemoveRoomAlias(ctx, request.Alias); err != nil {
return err return err

View file

@ -604,4 +604,7 @@ Remote banned user is kicked and may not rejoin until unbanned
registration remembers parameters registration remembers parameters
registration accepts non-ascii passwords registration accepts non-ascii passwords
registration with inhibit_login inhibits login registration with inhibit_login inhibits login
Canonical alias can be set
Canonical alias can include alt_aliases
Can delete canonical alias
Multiple calls to /sync should not cause 500 errors