Merge branch 'hs/as-transaction-send-if-in-room' into hs/fix-appsevice-alias-queries-part-2

This commit is contained in:
Will Hunt 2021-03-03 16:16:43 +00:00
commit f1f4255e9c
7 changed files with 65 additions and 22 deletions

View file

@ -85,9 +85,6 @@ func (s *OutputRoomEventConsumer) onMessage(msg *sarama.ConsumerMessage) error {
} }
if output.Type != api.OutputTypeNewRoomEvent { if output.Type != api.OutputTypeNewRoomEvent {
log.WithField("type", output.Type).Debug(
"roomserver output log: ignoring unknown output type",
)
return nil return nil
} }
@ -114,6 +111,7 @@ func (s *OutputRoomEventConsumer) filterRoomserverEvents(
// Queue this event to be sent off to the application service // Queue this event to be sent off to the application service
if err := s.asDB.StoreEvent(ctx, ws.AppService.ID, event); err != nil { if err := s.asDB.StoreEvent(ctx, ws.AppService.ID, event); err != nil {
log.WithError(err).Warn("failed to insert incoming event into appservices database") log.WithError(err).Warn("failed to insert incoming event into appservices database")
return err
} else { } else {
// Tell our worker to send out new messages by updating remaining message // Tell our worker to send out new messages by updating remaining message
// count and waking them up with a broadcast // count and waking them up with a broadcast
@ -126,25 +124,29 @@ func (s *OutputRoomEventConsumer) filterRoomserverEvents(
return nil return nil
} }
// appserviceHasMembershipInRoom returns a boolean depending on whether a given // appserviceJoinedAtEvent returns a boolean depending on whether a given
// appservice has membership at the time a given event was created. // appservice has membership at the time a given event was created.
func (s *OutputRoomEventConsumer) appserviceHasMembershipForEvent(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, appservice config.ApplicationService) bool { func (s *OutputRoomEventConsumer) appserviceJoinedAtEvent(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, appservice config.ApplicationService) bool {
// Check if any of the members in the room match the appservice // TODO: This is only checking the current room state, not the state at
membershipReq := api.QueryStateAfterEventsRequest{ // the event in question. Pretty sure this is what Synapse does too, but
PrevEventIDs: []string{event.EventID()}, // until we have a lighter way of checking the state before the event that
// doesn't involve state res, then this is probably OK.
membershipReq := &api.QueryMembershipsForRoomRequest{
RoomID: event.RoomID(), RoomID: event.RoomID(),
JoinedOnly: true,
} }
var membershipRes api.QueryStateAfterEventsResponse membershipRes := &api.QueryMembershipsForRoomResponse{}
// XXX: This could potentially race if the state for the event is not known yet // XXX: This could potentially race if the state for the event is not known yet
// e.g. the event came over federation but we do not have the full state persisted. // e.g. the event came over federation but we do not have the full state persisted.
if err := s.rsAPI.QueryStateAfterEvents(ctx, &membershipReq, &membershipRes); err == nil { if err := s.rsAPI.QueryMembershipsForRoom(ctx, membershipReq, membershipRes); err == nil {
for _, ev := range membershipRes.StateEvents { for _, ev := range membershipRes.JoinEvents {
if ev.Type() == gomatrixserverlib.MRoomMember { var membership gomatrixserverlib.MemberContent
var membership, _ = ev.Membership() if err = json.Unmarshal(ev.Content, &membership); err != nil || ev.StateKey == nil {
if membership == gomatrixserverlib.Join && appservice.IsInterestedInUserID(*ev.StateKey()) { continue
return true
} }
if appservice.IsInterestedInUserID(*ev.StateKey) {
return true
} }
} }
} else { } else {
@ -194,5 +196,5 @@ func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Cont
} }
// Check if any of the members in the room match the appservice // Check if any of the members in the room match the appservice
return s.appserviceHasMembershipForEvent(ctx, event, appservice) return s.appserviceJoinedAtEvent(ctx, event, appservice)
} }

View file

@ -62,7 +62,7 @@ func SetupTransactionWorkers(
func worker(db storage.Database, ws types.ApplicationServiceWorkerState) { func worker(db storage.Database, ws types.ApplicationServiceWorkerState) {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"appservice": ws.AppService.ID, "appservice": ws.AppService.ID,
}).Info("starting application service") }).Info("Starting application service")
ctx := context.Background() ctx := context.Background()
// Create a HTTP client for sending requests to app services // Create a HTTP client for sending requests to app services

View file

@ -103,8 +103,22 @@ func GetEvent(
} }
} }
var appService *config.ApplicationService
if device.AppserviceID != "" {
for _, as := range cfg.Derived.ApplicationServices {
if as.ID == device.AppserviceID {
appService = &as
break
}
}
}
for _, stateEvent := range stateResp.StateEvents { for _, stateEvent := range stateResp.StateEvents {
if !stateEvent.StateKeyEquals(device.UserID) { if appService != nil {
if !appService.IsInterestedInUserID(*stateEvent.StateKey()) {
continue
}
} else if !stateEvent.StateKeyEquals(device.UserID) {
continue continue
} }
membership, err := stateEvent.Membership() membership, err := stateEvent.Membership()

View file

@ -151,7 +151,9 @@ type QueryMembershipsForRoomRequest struct {
JoinedOnly bool `json:"joined_only"` JoinedOnly bool `json:"joined_only"`
// ID of the room to fetch memberships from // ID of the room to fetch memberships from
RoomID string `json:"room_id"` RoomID string `json:"room_id"`
// ID of the user sending the request // Optional - ID of the user sending the request, for checking if the
// user is allowed to see the memberships. If not specified then all
// room memberships will be returned.
Sender string `json:"sender"` Sender string `json:"sender"`
} }

View file

@ -242,6 +242,27 @@ func (r *Queryer) QueryMembershipsForRoom(
return err return err
} }
// If no sender is specified then we will just return the entire
// set of memberships for the room, regardless of whether a specific
// user is allowed to see them or not.
if request.Sender == "" {
var events []types.Event
var eventNIDs []types.EventNID
eventNIDs, err = r.DB.GetMembershipEventNIDsForRoom(ctx, info.RoomNID, request.JoinedOnly, false)
if err != nil {
return fmt.Errorf("r.DB.GetMembershipEventNIDsForRoom: %w", err)
}
events, err = r.DB.Events(ctx, eventNIDs)
if err != nil {
return fmt.Errorf("r.DB.Events: %w", err)
}
for _, event := range events {
clientEvent := gomatrixserverlib.ToClientEvent(event.Event, gomatrixserverlib.FormatAll)
response.JoinEvents = append(response.JoinEvents, clientEvent)
}
return nil
}
membershipEventNID, stillInRoom, isRoomforgotten, err := r.DB.GetMembership(ctx, info.RoomNID, request.Sender) membershipEventNID, stillInRoom, isRoomforgotten, err := r.DB.GetMembership(ctx, info.RoomNID, request.Sender)
if err != nil { if err != nil {
return err return err

View file

@ -241,6 +241,9 @@ type Device struct {
LastSeenTS int64 LastSeenTS int64
LastSeenIP string LastSeenIP string
UserAgent string UserAgent string
// If the device is for an appservice user,
// this is the appservice ID.
AppserviceID string
} }
// Account represents a Matrix account on this home server. // Account represents a Matrix account on this home server.

View file

@ -382,6 +382,7 @@ func (a *UserInternalAPI) queryAppServiceToken(ctx context.Context, token, appSe
ID: types.AppServiceDeviceID, ID: types.AppServiceDeviceID,
// AS dummy device has AS's token. // AS dummy device has AS's token.
AccessToken: token, AccessToken: token,
AppserviceID: appService.ID,
} }
localpart, err := userutil.ParseUsernameParam(appServiceUserID, &a.ServerName) localpart, err := userutil.ParseUsernameParam(appServiceUserID, &a.ServerName)