Federation fixes for virtual hosting

This commit is contained in:
Neil Alexander 2022-11-15 15:05:23 +00:00
parent f4ee397734
commit 6650712a1c
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
73 changed files with 736 additions and 420 deletions

View file

@ -139,7 +139,12 @@ func (r *Admin) PerformAdminEvacuateRoom(
return nil
}
event, err := eventutil.BuildEvent(ctx, fledglingEvent, r.Cfg.Matrix, time.Now(), &eventsNeeded, latestRes)
identity, err := r.Cfg.Matrix.SigningIdentityFor(senderDomain)
if err != nil {
continue
}
event, err := eventutil.BuildEvent(ctx, fledglingEvent, r.Cfg.Matrix, identity, time.Now(), &eventsNeeded, latestRes)
if err != nil {
res.Error = &api.PerformError{
Code: api.PerformErrorBadRequest,
@ -242,6 +247,15 @@ func (r *Admin) PerformAdminDownloadState(
req *api.PerformAdminDownloadStateRequest,
res *api.PerformAdminDownloadStateResponse,
) error {
_, senderDomain, err := r.Cfg.Matrix.SplitLocalID('@', req.UserID)
if err != nil {
res.Error = &api.PerformError{
Code: api.PerformErrorBadRequest,
Msg: fmt.Sprintf("r.Cfg.Matrix.SplitLocalID: %s", err),
}
return nil
}
roomInfo, err := r.DB.RoomInfo(ctx, req.RoomID)
if err != nil {
res.Error = &api.PerformError{
@ -273,7 +287,7 @@ func (r *Admin) PerformAdminDownloadState(
for _, fwdExtremity := range fwdExtremities {
var state gomatrixserverlib.RespState
state, err = r.Inputer.FSAPI.LookupState(ctx, req.ServerName, req.RoomID, fwdExtremity.EventID, roomInfo.RoomVersion)
state, err = r.Inputer.FSAPI.LookupState(ctx, r.Inputer.ServerName, req.ServerName, req.RoomID, fwdExtremity.EventID, roomInfo.RoomVersion)
if err != nil {
res.Error = &api.PerformError{
Code: api.PerformErrorBadRequest,
@ -331,7 +345,12 @@ func (r *Admin) PerformAdminDownloadState(
Depth: depth,
}
ev, err := eventutil.BuildEvent(ctx, builder, r.Cfg.Matrix, time.Now(), &eventsNeeded, queryRes)
identity, err := r.Cfg.Matrix.SigningIdentityFor(senderDomain)
if err != nil {
return err
}
ev, err := eventutil.BuildEvent(ctx, builder, r.Cfg.Matrix, identity, time.Now(), &eventsNeeded, queryRes)
if err != nil {
res.Error = &api.PerformError{
Code: api.PerformErrorBadRequest,

View file

@ -37,10 +37,10 @@ import (
const maxBackfillServers = 5
type Backfiller struct {
ServerName gomatrixserverlib.ServerName
DB storage.Database
FSAPI federationAPI.RoomserverFederationAPI
KeyRing gomatrixserverlib.JSONVerifier
IsLocalServerName func(gomatrixserverlib.ServerName) bool
DB storage.Database
FSAPI federationAPI.RoomserverFederationAPI
KeyRing gomatrixserverlib.JSONVerifier
// The servers which should be preferred above other servers when backfilling
PreferServers []gomatrixserverlib.ServerName
@ -55,7 +55,7 @@ func (r *Backfiller) PerformBackfill(
// if we are requesting the backfill then we need to do a federation hit
// TODO: we could be more sensible and fetch as many events we already have then request the rest
// which is what the syncapi does already.
if request.ServerName == r.ServerName {
if r.IsLocalServerName(request.ServerName) {
return r.backfillViaFederation(ctx, request, response)
}
// someone else is requesting the backfill, try to service their request.
@ -112,16 +112,18 @@ func (r *Backfiller) backfillViaFederation(ctx context.Context, req *api.Perform
if info == nil || info.IsStub() {
return fmt.Errorf("backfillViaFederation: missing room info for room %s", req.RoomID)
}
requester := newBackfillRequester(r.DB, r.FSAPI, r.ServerName, req.BackwardsExtremities, r.PreferServers)
requester := newBackfillRequester(r.DB, r.FSAPI, req.VirtualHost, r.IsLocalServerName, req.BackwardsExtremities, r.PreferServers)
// Request 100 items regardless of what the query asks for.
// We don't want to go much higher than this.
// We can't honour exactly the limit as some sytests rely on requesting more for tests to pass
// (so we don't need to hit /state_ids which the test has no listener for)
// Specifically the test "Outbound federation can backfill events"
events, err := gomatrixserverlib.RequestBackfill(
ctx, requester,
r.KeyRing, req.RoomID, info.RoomVersion, req.PrevEventIDs(), 100)
ctx, req.VirtualHost, requester,
r.KeyRing, req.RoomID, info.RoomVersion, req.PrevEventIDs(), 100,
)
if err != nil {
logrus.WithError(err).Errorf("gomatrixserverlib.RequestBackfill failed")
return err
}
logrus.WithField("room_id", req.RoomID).Infof("backfilled %d events", len(events))
@ -144,7 +146,7 @@ func (r *Backfiller) backfillViaFederation(ctx context.Context, req *api.Perform
var entries []types.StateEntry
if entries, err = r.DB.StateEntriesForEventIDs(ctx, stateIDs, true); err != nil {
// attempt to fetch the missing events
r.fetchAndStoreMissingEvents(ctx, info.RoomVersion, requester, stateIDs)
r.fetchAndStoreMissingEvents(ctx, info.RoomVersion, requester, stateIDs, req.VirtualHost)
// try again
entries, err = r.DB.StateEntriesForEventIDs(ctx, stateIDs, true)
if err != nil {
@ -173,7 +175,7 @@ func (r *Backfiller) backfillViaFederation(ctx context.Context, req *api.Perform
// fetchAndStoreMissingEvents does a best-effort fetch and store of missing events specified in stateIDs. Returns no error as it is just
// best effort.
func (r *Backfiller) fetchAndStoreMissingEvents(ctx context.Context, roomVer gomatrixserverlib.RoomVersion,
backfillRequester *backfillRequester, stateIDs []string) {
backfillRequester *backfillRequester, stateIDs []string, virtualHost gomatrixserverlib.ServerName) {
servers := backfillRequester.servers
@ -198,7 +200,7 @@ func (r *Backfiller) fetchAndStoreMissingEvents(ctx context.Context, roomVer gom
continue // already found
}
logger := util.GetLogger(ctx).WithField("server", srv).WithField("event_id", id)
res, err := r.FSAPI.GetEvent(ctx, srv, id)
res, err := r.FSAPI.GetEvent(ctx, virtualHost, srv, id)
if err != nil {
logger.WithError(err).Warn("failed to get event from server")
continue
@ -241,11 +243,12 @@ func (r *Backfiller) fetchAndStoreMissingEvents(ctx context.Context, roomVer gom
// backfillRequester implements gomatrixserverlib.BackfillRequester
type backfillRequester struct {
db storage.Database
fsAPI federationAPI.RoomserverFederationAPI
thisServer gomatrixserverlib.ServerName
preferServer map[gomatrixserverlib.ServerName]bool
bwExtrems map[string][]string
db storage.Database
fsAPI federationAPI.RoomserverFederationAPI
virtualHost gomatrixserverlib.ServerName
isLocalServerName func(gomatrixserverlib.ServerName) bool
preferServer map[gomatrixserverlib.ServerName]bool
bwExtrems map[string][]string
// per-request state
servers []gomatrixserverlib.ServerName
@ -255,7 +258,9 @@ type backfillRequester struct {
}
func newBackfillRequester(
db storage.Database, fsAPI federationAPI.RoomserverFederationAPI, thisServer gomatrixserverlib.ServerName,
db storage.Database, fsAPI federationAPI.RoomserverFederationAPI,
virtualHost gomatrixserverlib.ServerName,
isLocalServerName func(gomatrixserverlib.ServerName) bool,
bwExtrems map[string][]string, preferServers []gomatrixserverlib.ServerName,
) *backfillRequester {
preferServer := make(map[gomatrixserverlib.ServerName]bool)
@ -265,7 +270,8 @@ func newBackfillRequester(
return &backfillRequester{
db: db,
fsAPI: fsAPI,
thisServer: thisServer,
virtualHost: virtualHost,
isLocalServerName: isLocalServerName,
eventIDToBeforeStateIDs: make(map[string][]string),
eventIDMap: make(map[string]*gomatrixserverlib.Event),
bwExtrems: bwExtrems,
@ -450,7 +456,7 @@ FindSuccessor:
}
// possibly return all joined servers depending on history visiblity
memberEventsFromVis, visibility, err := joinEventsFromHistoryVisibility(ctx, b.db, roomID, stateEntries, b.thisServer)
memberEventsFromVis, visibility, err := joinEventsFromHistoryVisibility(ctx, b.db, roomID, stateEntries, b.virtualHost)
b.historyVisiblity = visibility
if err != nil {
logrus.WithError(err).Error("ServersAtEvent: failed calculate servers from history visibility rules")
@ -477,7 +483,7 @@ FindSuccessor:
}
var servers []gomatrixserverlib.ServerName
for server := range serverSet {
if server == b.thisServer {
if b.isLocalServerName(server) {
continue
}
if b.preferServer[server] { // insert at the front
@ -496,10 +502,10 @@ FindSuccessor:
// Backfill performs a backfill request to the given server.
// https://matrix.org/docs/spec/server_server/latest#get-matrix-federation-v1-backfill-roomid
func (b *backfillRequester) Backfill(ctx context.Context, server gomatrixserverlib.ServerName, roomID string,
func (b *backfillRequester) Backfill(ctx context.Context, origin, server gomatrixserverlib.ServerName, roomID string,
limit int, fromEventIDs []string) (gomatrixserverlib.Transaction, error) {
tx, err := b.fsAPI.Backfill(ctx, server, roomID, limit, fromEventIDs)
tx, err := b.fsAPI.Backfill(ctx, origin, server, roomID, limit, fromEventIDs)
return tx, err
}

View file

@ -39,11 +39,10 @@ import (
)
type Joiner struct {
ServerName gomatrixserverlib.ServerName
Cfg *config.RoomServer
FSAPI fsAPI.RoomserverFederationAPI
RSAPI rsAPI.RoomserverInternalAPI
DB storage.Database
Cfg *config.RoomServer
FSAPI fsAPI.RoomserverFederationAPI
RSAPI rsAPI.RoomserverInternalAPI
DB storage.Database
Inputer *input.Inputer
Queryer *query.Queryer
@ -197,7 +196,7 @@ func (r *Joiner) performJoinRoomByID(
// Prepare the template for the join event.
userID := req.UserID
_, userDomain, err := gomatrixserverlib.SplitID('@', userID)
_, userDomain, err := r.Cfg.Matrix.SplitLocalID('@', userID)
if err != nil {
return "", "", &rsAPI.PerformError{
Code: rsAPI.PerformErrorBadRequest,
@ -283,7 +282,7 @@ func (r *Joiner) performJoinRoomByID(
// locally on the homeserver.
// TODO: Check what happens if the room exists on the server
// but everyone has since left. I suspect it does the wrong thing.
event, buildRes, err := buildEvent(ctx, r.DB, r.Cfg.Matrix, &eb)
event, buildRes, err := buildEvent(ctx, r.DB, r.Cfg.Matrix, userDomain, &eb)
switch err {
case nil:
@ -410,7 +409,9 @@ func (r *Joiner) populateAuthorisedViaUserForRestrictedJoin(
}
func buildEvent(
ctx context.Context, db storage.Database, cfg *config.Global, builder *gomatrixserverlib.EventBuilder,
ctx context.Context, db storage.Database, cfg *config.Global,
senderDomain gomatrixserverlib.ServerName,
builder *gomatrixserverlib.EventBuilder,
) (*gomatrixserverlib.HeaderedEvent, *rsAPI.QueryLatestEventsAndStateResponse, error) {
eventsNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(builder)
if err != nil {
@ -438,7 +439,12 @@ func buildEvent(
}
}
ev, err := eventutil.BuildEvent(ctx, builder, cfg, time.Now(), &eventsNeeded, &queryRes)
identity, err := cfg.SigningIdentityFor(senderDomain)
if err != nil {
return nil, nil, err
}
ev, err := eventutil.BuildEvent(ctx, builder, cfg, identity, time.Now(), &eventsNeeded, &queryRes)
if err != nil {
return nil, nil, err
}

View file

@ -162,21 +162,21 @@ func (r *Leaver) performLeaveRoomByID(
return nil, fmt.Errorf("eb.SetUnsigned: %w", err)
}
// Get the sender domain.
_, senderDomain, serr := r.Cfg.Matrix.SplitLocalID('@', eb.Sender)
if serr != nil {
return nil, fmt.Errorf("sender %q is invalid", eb.Sender)
}
// We know that the user is in the room at this point so let's build
// a leave event.
// TODO: Check what happens if the room exists on the server
// but everyone has since left. I suspect it does the wrong thing.
event, buildRes, err := buildEvent(ctx, r.DB, r.Cfg.Matrix, &eb)
event, buildRes, err := buildEvent(ctx, r.DB, r.Cfg.Matrix, senderDomain, &eb)
if err != nil {
return nil, fmt.Errorf("eventutil.BuildEvent: %w", err)
}
// Get the sender domain.
_, senderDomain, serr := gomatrixserverlib.SplitID('@', event.Sender())
if serr != nil {
return nil, fmt.Errorf("sender %q is invalid", event.Sender())
}
// Give our leave event to the roomserver input stream. The
// roomserver will process the membership change and notify
// downstream automatically.

View file

@ -60,7 +60,7 @@ func (r *Upgrader) performRoomUpgrade(
) (string, *api.PerformError) {
roomID := req.RoomID
userID := req.UserID
_, userDomain, err := gomatrixserverlib.SplitID('@', userID)
_, userDomain, err := r.Cfg.Matrix.SplitLocalID('@', userID)
if err != nil {
return "", &api.PerformError{
Code: api.PerformErrorNotAllowed,
@ -558,7 +558,7 @@ func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, user
SendAsServer: api.DoNotSendToOtherServers,
})
}
if err = api.SendInputRoomEvents(ctx, r.URSAPI, inputs, false); err != nil {
if err = api.SendInputRoomEvents(ctx, r.URSAPI, userDomain, inputs, false); err != nil {
return &api.PerformError{
Msg: fmt.Sprintf("Failed to send new room %q to roomserver: %s", newRoomID, err),
}
@ -595,8 +595,21 @@ func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, user
Msg: fmt.Sprintf("Failed to set new %q event content: %s", builder.Type, err),
}
}
// Get the sender domain.
_, senderDomain, serr := r.Cfg.Matrix.SplitLocalID('@', builder.Sender)
if serr != nil {
return nil, &api.PerformError{
Msg: fmt.Sprintf("Failed to split user ID %q: %s", builder.Sender, err),
}
}
identity, err := r.Cfg.Matrix.SigningIdentityFor(senderDomain)
if err != nil {
return nil, &api.PerformError{
Msg: fmt.Sprintf("Failed to get signing identity for %q: %s", senderDomain, err),
}
}
var queryRes api.QueryLatestEventsAndStateResponse
headeredEvent, err := eventutil.QueryAndBuildEvent(ctx, &builder, r.Cfg.Matrix, evTime, r.URSAPI, &queryRes)
headeredEvent, err := eventutil.QueryAndBuildEvent(ctx, &builder, r.Cfg.Matrix, identity, evTime, r.URSAPI, &queryRes)
if err == eventutil.ErrRoomNoExists {
return nil, &api.PerformError{
Code: api.PerformErrorNoRoom,
@ -686,7 +699,7 @@ func (r *Upgrader) sendHeaderedEvent(
Origin: serverName,
SendAsServer: sendAsServer,
})
if err := api.SendInputRoomEvents(ctx, r.URSAPI, inputs, false); err != nil {
if err := api.SendInputRoomEvents(ctx, r.URSAPI, serverName, inputs, false); err != nil {
return &api.PerformError{
Msg: fmt.Sprintf("Failed to send new %q event to roomserver: %s", headeredEvent.Type(), err),
}