Skip to content

Commit

Permalink
Fix issue with sentinels being incorrect on m.room.member events
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
  • Loading branch information
t3chguy committed Jan 8, 2025
1 parent 5b85ae4 commit df213e5
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 27 deletions.
22 changes: 1 addition & 21 deletions src/models/event-timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,27 +68,7 @@ export class EventTimeline {
* @param toStartOfTimeline - if true the event's forwardLooking flag is set false
*/
public static setEventMetadata(event: MatrixEvent, stateContext: RoomState, toStartOfTimeline: boolean): void {
// When we try to generate a sentinel member before we have that member
// in the members object, we still generate a sentinel but it doesn't
// have a membership event, so test to see if events.member is set. We
// check this to avoid overriding non-sentinel members by sentinel ones
// when adding the event to a filtered timeline
if (!event.sender?.events?.member) {
event.sender = stateContext.getSentinelMember(event.getSender()!);
}
if (!event.target?.events?.member && event.getType() === EventType.RoomMember) {
event.target = stateContext.getSentinelMember(event.getStateKey()!);
}

if (event.isState()) {
// room state has no concept of 'old' or 'current', but we want the
// room state to regress back to previous values if toStartOfTimeline
// is set, which means inspecting prev_content if it exists. This
// is done by toggling the forwardLooking flag.
if (toStartOfTimeline) {
event.forwardLooking = false;
}
}
event.setMetadata(stateContext, toStartOfTimeline);
}

private readonly roomId: string | null;
Expand Down
64 changes: 58 additions & 6 deletions src/models/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { Room } from "./room.ts";
import { EventTimeline } from "./event-timeline.ts";
import { Membership } from "../@types/membership.ts";
import { DecryptionFailureCode } from "../crypto-api/index.ts";
import { RoomState } from "./room-state.ts";

export { EventStatus } from "./event-status.ts";

Expand Down Expand Up @@ -232,6 +233,7 @@ export enum MatrixEventEvent {
Status = "Event.status",
Replaced = "Event.replaced",
RelationsCreated = "Event.relationsCreated",
SentinelUpdated = "Event.sentinelUpdated",
}

export type MatrixEventEmittedEvents = MatrixEventEvent | ThreadEvent.Update;
Expand All @@ -244,6 +246,7 @@ export type MatrixEventHandlerMap = {
[MatrixEventEvent.Status]: (event: MatrixEvent, status: EventStatus | null) => void;
[MatrixEventEvent.Replaced]: (event: MatrixEvent) => void;
[MatrixEventEvent.RelationsCreated]: (relationType: string, eventType: string) => void;
[MatrixEventEvent.SentinelUpdated]: () => void;
} & Pick<ThreadEventHandlerMap, ThreadEvent.Update>;

export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, MatrixEventHandlerMap> {
Expand Down Expand Up @@ -319,22 +322,71 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
*/
public localTimestamp: number;

private _sender: RoomMember | null = null;
private _target: RoomMember | null = null;

/**
* Update the sentinels and forwardLooking flag for this event.
* @param stateContext - the room state to be queried
* @param toStartOfTimeline - if true the event's forwardLooking flag is set false
* @internal
*/
public setMetadata(stateContext: RoomState, toStartOfTimeline: boolean): void {
// If an event is an m.room.member state event then we should set the sentinels again in case setEventMetadata
// was already called before the state was applied and thus the sentinel points at the member from before this event.
const affectsSelf =
this.isState() && this.getType() === EventType.RoomMember && this.getSender() === this.getStateKey();

let changed = false;
// When we try to generate a sentinel member before we have that member
// in the members object, we still generate a sentinel but it doesn't
// have a membership event, so test to see if events.member is set. We
// check this to avoid overriding non-sentinel members by sentinel ones
// when adding the event to a filtered timeline
if (affectsSelf || !this.sender?.events?.member) {
const newSender = stateContext.getSentinelMember(this.getSender()!);
if (newSender !== this.sender) changed = true;
this._sender = newSender;
}
if (affectsSelf || (!this.target?.events?.member && this.getType() === EventType.RoomMember)) {
const newTarget = stateContext.getSentinelMember(this.getStateKey()!);
if (newTarget !== this.target) changed = true;
this._target = newTarget;
}

if (this.isState()) {
// room state has no concept of 'old' or 'current', but we want the
// room state to regress back to previous values if toStartOfTimeline
// is set, which means inspecting prev_content if it exists. This
// is done by toggling the forwardLooking flag.
if (toStartOfTimeline) {
this.forwardLooking = false;
}
}

if (changed) {
this.emit(MatrixEventEvent.SentinelUpdated);
}
}

/**
* The room member who sent this event, or null e.g.
* this is a presence event. This is only guaranteed to be set for events that
* appear in a timeline, ie. do not guarantee that it will be set on state
* events.
* @privateRemarks
* Should be read-only
*/
public sender: RoomMember | null = null;
public get sender(): RoomMember | null {
return this._sender;
}

/**
* The room member who is the target of this event, e.g.
* the invitee, the person being banned, etc.
* @privateRemarks
* Should be read-only
*/
public target: RoomMember | null = null;
public get target(): RoomMember | null {
return this._target;
}

/**
* The sending status of the event.
* @privateRemarks
Expand Down

0 comments on commit df213e5

Please sign in to comment.