[pseudoIDs] Fixes for room alias tests (#3159)

Some (deceptively) simple fixes for some bugs that caused room alias
tests to fail (sytext `tests/30rooms/05aliases.pl`). Each commit has
details about what it fixes.

Sytest results:

- Sytest before (79d4a0e):
https://gist.github.com/swedgwood/972ac4ef93edd130d3db0930703d6c82
- Sytest after (4b09bed):
https://gist.github.com/swedgwood/504b00ac4ee892acb757b7fac55fa28a

Room aliases go from `8/15` to `15/15`, but looks like these fixes also
managed to fix about `4` other tests, which is a nice bonus :)

Signed-off-by: `Sam Wedgwood <sam@wedgwood.dev>`
This commit is contained in:
Sam Wedgwood 2023-07-31 14:39:41 +01:00 committed by GitHub
parent 3f727485d6
commit af13fa1c75
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 160 additions and 138 deletions

View file

@ -35,27 +35,27 @@ import (
// SetRoomAlias implements alias.RoomserverInternalAPI
func (r *RoomserverInternalAPI) SetRoomAlias(
ctx context.Context,
request *api.SetRoomAliasRequest,
response *api.SetRoomAliasResponse,
) error {
senderID spec.SenderID,
roomID spec.RoomID,
alias string,
) (aliasAlreadyUsed bool, err error) {
// Check if the alias isn't already referring to a room
roomID, err := r.DB.GetRoomIDForAlias(ctx, request.Alias)
existingRoomID, err := r.DB.GetRoomIDForAlias(ctx, alias)
if err != nil {
return err
return false, err
}
if len(roomID) > 0 {
if len(existingRoomID) > 0 {
// If the alias already exists, stop the process
response.AliasExists = true
return nil
return true, nil
}
response.AliasExists = false
// Save the new alias
if err := r.DB.SetRoomAlias(ctx, request.Alias, request.RoomID, request.UserID); err != nil {
return err
if err := r.DB.SetRoomAlias(ctx, alias, roomID.String(), string(senderID)); err != nil {
return false, err
}
return nil
return false, nil
}
// GetRoomIDForAlias implements alias.RoomserverInternalAPI
@ -116,90 +116,79 @@ func (r *RoomserverInternalAPI) GetAliasesForRoomID(
// nolint:gocyclo
// RemoveRoomAlias implements alias.RoomserverInternalAPI
// nolint: gocyclo
func (r *RoomserverInternalAPI) RemoveRoomAlias(
ctx context.Context,
request *api.RemoveRoomAliasRequest,
response *api.RemoveRoomAliasResponse,
) error {
roomID, err := r.DB.GetRoomIDForAlias(ctx, request.Alias)
func (r *RoomserverInternalAPI) RemoveRoomAlias(ctx context.Context, senderID spec.SenderID, alias string) (aliasFound bool, aliasRemoved bool, err error) {
roomID, err := r.DB.GetRoomIDForAlias(ctx, alias)
if err != nil {
return fmt.Errorf("r.DB.GetRoomIDForAlias: %w", err)
return false, false, fmt.Errorf("r.DB.GetRoomIDForAlias: %w", err)
}
if roomID == "" {
response.Found = false
response.Removed = false
return nil
return false, false, nil
}
validRoomID, err := spec.NewRoomID(roomID)
if err != nil {
return err
return true, false, err
}
sender, err := r.QueryUserIDForSender(ctx, *validRoomID, request.SenderID)
sender, err := r.QueryUserIDForSender(ctx, *validRoomID, senderID)
if err != nil || sender == nil {
return fmt.Errorf("r.QueryUserIDForSender: %w", err)
return true, false, fmt.Errorf("r.QueryUserIDForSender: %w", err)
}
virtualHost := sender.Domain()
response.Found = true
creatorID, err := r.DB.GetCreatorIDForAlias(ctx, request.Alias)
creatorID, err := r.DB.GetCreatorIDForAlias(ctx, alias)
if err != nil {
return fmt.Errorf("r.DB.GetCreatorIDForAlias: %w", err)
return true, false, fmt.Errorf("r.DB.GetCreatorIDForAlias: %w", err)
}
if spec.SenderID(creatorID) != request.SenderID {
if spec.SenderID(creatorID) != senderID {
var plEvent *types.HeaderedEvent
var pls *gomatrixserverlib.PowerLevelContent
plEvent, err = r.DB.GetStateEvent(ctx, roomID, spec.MRoomPowerLevels, "")
if err != nil {
return fmt.Errorf("r.DB.GetStateEvent: %w", err)
return true, false, fmt.Errorf("r.DB.GetStateEvent: %w", err)
}
pls, err = plEvent.PowerLevels()
if err != nil {
return fmt.Errorf("plEvent.PowerLevels: %w", err)
return true, false, fmt.Errorf("plEvent.PowerLevels: %w", err)
}
if pls.UserLevel(request.SenderID) < pls.EventLevel(spec.MRoomCanonicalAlias, true) {
response.Removed = false
return nil
if pls.UserLevel(senderID) < pls.EventLevel(spec.MRoomCanonicalAlias, true) {
return true, false, nil
}
}
ev, err := r.DB.GetStateEvent(ctx, roomID, spec.MRoomCanonicalAlias, "")
if err != nil && err != sql.ErrNoRows {
return err
return true, false, err
} else if ev != nil {
stateAlias := gjson.GetBytes(ev.Content(), "alias").Str
// the alias to remove is currently set as the canonical alias, remove it
if stateAlias == request.Alias {
if stateAlias == alias {
res, err := sjson.DeleteBytes(ev.Content(), "alias")
if err != nil {
return err
return true, false, err
}
senderID := request.SenderID
if request.SenderID != ev.SenderID() {
senderID = ev.SenderID()
}
sender, err := r.QueryUserIDForSender(ctx, *validRoomID, senderID)
if err != nil || sender == nil {
return err
canonicalSenderID := ev.SenderID()
canonicalSender, err := r.QueryUserIDForSender(ctx, *validRoomID, canonicalSenderID)
if err != nil || canonicalSender == nil {
return true, false, err
}
validRoomID, err := spec.NewRoomID(roomID)
if err != nil {
return err
return true, false, err
}
identity, err := r.SigningIdentityFor(ctx, *validRoomID, *sender)
identity, err := r.SigningIdentityFor(ctx, *validRoomID, *canonicalSender)
if err != nil {
return err
return true, false, err
}
proto := &gomatrixserverlib.ProtoEvent{
SenderID: string(senderID),
SenderID: string(canonicalSenderID),
RoomID: ev.RoomID(),
Type: ev.Type(),
StateKey: ev.StateKey(),
@ -208,34 +197,33 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias(
eventsNeeded, err := gomatrixserverlib.StateNeededForProtoEvent(proto)
if err != nil {
return fmt.Errorf("gomatrixserverlib.StateNeededForEventBuilder: %w", err)
return true, false, fmt.Errorf("gomatrixserverlib.StateNeededForEventBuilder: %w", err)
}
if len(eventsNeeded.Tuples()) == 0 {
return errors.New("expecting state tuples for event builder, got none")
return true, false, errors.New("expecting state tuples for event builder, got none")
}
stateRes := &api.QueryLatestEventsAndStateResponse{}
if err = helpers.QueryLatestEventsAndState(ctx, r.DB, r, &api.QueryLatestEventsAndStateRequest{RoomID: roomID, StateToFetch: eventsNeeded.Tuples()}, stateRes); err != nil {
return err
return true, false, err
}
newEvent, err := eventutil.BuildEvent(ctx, proto, &identity, time.Now(), &eventsNeeded, stateRes)
if err != nil {
return err
return true, false, err
}
err = api.SendEvents(ctx, r, api.KindNew, []*types.HeaderedEvent{newEvent}, virtualHost, r.ServerName, r.ServerName, nil, false)
if err != nil {
return err
return true, false, err
}
}
}
// Remove the alias from the database
if err := r.DB.RemoveRoomAlias(ctx, request.Alias); err != nil {
return err
if err := r.DB.RemoveRoomAlias(ctx, alias); err != nil {
return true, false, err
}
response.Removed = true
return nil
return true, true, nil
}

View file

@ -433,23 +433,16 @@ func (c *Creator) PerformCreateRoom(ctx context.Context, userID spec.UserID, roo
// from creating the room but still failing due to the alias having already
// been taken.
if roomAlias != "" {
aliasReq := api.SetRoomAliasRequest{
Alias: roomAlias,
RoomID: roomID.String(),
UserID: userID.String(),
}
var aliasResp api.SetRoomAliasResponse
err = c.RSAPI.SetRoomAlias(ctx, &aliasReq, &aliasResp)
if err != nil {
util.GetLogger(ctx).WithError(err).Error("aliasAPI.SetRoomAlias failed")
aliasAlreadyExists, aliasErr := c.RSAPI.SetRoomAlias(ctx, senderID, roomID, roomAlias)
if aliasErr != nil {
util.GetLogger(ctx).WithError(aliasErr).Error("aliasAPI.SetRoomAlias failed")
return "", &util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}
}
if aliasResp.AliasExists {
if aliasAlreadyExists {
return "", &util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.RoomInUse("Room alias already exists."),

View file

@ -116,7 +116,7 @@ func (r *Upgrader) performRoomUpgrade(
}
// 4. Move local aliases to the new room
if pErr = moveLocalAliases(ctx, roomID, newRoomID, senderID, userID, r.URSAPI); pErr != nil {
if pErr = moveLocalAliases(ctx, roomID, newRoomID, senderID, r.URSAPI); pErr != nil {
return "", pErr
}
@ -171,7 +171,7 @@ func (r *Upgrader) restrictOldRoomPowerLevels(ctx context.Context, evTime time.T
}
func moveLocalAliases(ctx context.Context,
roomID, newRoomID string, senderID spec.SenderID, userID spec.UserID,
roomID, newRoomID string, senderID spec.SenderID,
URSAPI api.RoomserverInternalAPI,
) (err error) {
@ -181,17 +181,27 @@ func moveLocalAliases(ctx context.Context,
return fmt.Errorf("Failed to get old room aliases: %w", err)
}
// TODO: this should be spec.RoomID further up the call stack
parsedNewRoomID, err := spec.NewRoomID(newRoomID)
if err != nil {
return err
}
for _, alias := range aliasRes.Aliases {
removeAliasReq := api.RemoveRoomAliasRequest{SenderID: senderID, Alias: alias}
removeAliasRes := api.RemoveRoomAliasResponse{}
if err = URSAPI.RemoveRoomAlias(ctx, &removeAliasReq, &removeAliasRes); err != nil {
aliasFound, aliasRemoved, err := URSAPI.RemoveRoomAlias(ctx, senderID, alias)
if err != nil {
return fmt.Errorf("Failed to remove old room alias: %w", err)
} else if !aliasFound {
return fmt.Errorf("Failed to remove old room alias: alias not found, possible race")
} else if !aliasRemoved {
return fmt.Errorf("Failed to remove old alias")
}
setAliasReq := api.SetRoomAliasRequest{UserID: userID.String(), Alias: alias, RoomID: newRoomID}
setAliasRes := api.SetRoomAliasResponse{}
if err = URSAPI.SetRoomAlias(ctx, &setAliasReq, &setAliasRes); err != nil {
aliasAlreadyExists, err := URSAPI.SetRoomAlias(ctx, senderID, *parsedNewRoomID, alias)
if err != nil {
return fmt.Errorf("Failed to set new room alias: %w", err)
} else if aliasAlreadyExists {
return fmt.Errorf("Failed to set new room alias: alias exists when it should have just been removed")
}
}
return nil