Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c821ec7

Browse files
committedJun 4, 2025·
Factor out common code for processing to-device events
`sliding-sync-sdk.ts` and `sync.ts` both have copies of this code, and it's redundant.
1 parent 12a9875 commit c821ec7

File tree

2 files changed

+53
-84
lines changed

2 files changed

+53
-84
lines changed
 

‎src/sliding-sync-sdk.ts

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
defaultClientOpts,
2929
defaultSyncApiOpts,
3030
type SetPresence,
31-
mapToDeviceEvent,
31+
processToDeviceMessages,
3232
} from "./sync.ts";
3333
import { type MatrixEvent } from "./models/event.ts";
3434
import {
@@ -150,51 +150,11 @@ class ExtensionToDevice implements Extension<ExtensionToDeviceRequest, Extension
150150
}
151151

152152
public async onResponse(data: ExtensionToDeviceResponse): Promise<void> {
153-
const cancelledKeyVerificationTxns: string[] = [];
154153
let events = data["events"] || [];
155154
if (events.length > 0 && this.cryptoCallbacks) {
156155
events = await this.cryptoCallbacks.preprocessToDeviceMessages(events);
157156
}
158-
events
159-
.map(mapToDeviceEvent)
160-
.map((toDeviceEvent) => {
161-
// map is a cheap inline forEach
162-
// We want to flag m.key.verification.start events as cancelled
163-
// if there's an accompanying m.key.verification.cancel event, so
164-
// we pull out the transaction IDs from the cancellation events
165-
// so we can flag the verification events as cancelled in the loop
166-
// below.
167-
if (toDeviceEvent.getType() === "m.key.verification.cancel") {
168-
const txnId: string | undefined = toDeviceEvent.getContent()["transaction_id"];
169-
if (txnId) {
170-
cancelledKeyVerificationTxns.push(txnId);
171-
}
172-
}
173-
174-
// as mentioned above, .map is a cheap inline forEach, so return
175-
// the unmodified event.
176-
return toDeviceEvent;
177-
})
178-
.forEach((toDeviceEvent) => {
179-
const content = toDeviceEvent.getContent();
180-
if (toDeviceEvent.getType() == "m.room.message" && content.msgtype == "m.bad.encrypted") {
181-
// the mapper already logged a warning.
182-
logger.log("Ignoring undecryptable to-device event from " + toDeviceEvent.getSender());
183-
return;
184-
}
185-
186-
if (
187-
toDeviceEvent.getType() === "m.key.verification.start" ||
188-
toDeviceEvent.getType() === "m.key.verification.request"
189-
) {
190-
const txnId = content["transaction_id"];
191-
if (cancelledKeyVerificationTxns.includes(txnId)) {
192-
toDeviceEvent.flagCancelled();
193-
}
194-
}
195-
196-
this.client.emit(ClientEvent.ToDeviceEvent, toDeviceEvent);
197-
});
157+
processToDeviceMessages(events, this.client);
198158

199159
this.nextBatch = data.next_batch;
200160
}

‎src/sync.ts

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,47 +1150,7 @@ export class SyncApi {
11501150
toDeviceMessages = await this.syncOpts.cryptoCallbacks.preprocessToDeviceMessages(toDeviceMessages);
11511151
}
11521152

1153-
const cancelledKeyVerificationTxns: string[] = [];
1154-
toDeviceMessages
1155-
.map(mapToDeviceEvent)
1156-
.map((toDeviceEvent) => {
1157-
// map is a cheap inline forEach
1158-
// We want to flag m.key.verification.start events as cancelled
1159-
// if there's an accompanying m.key.verification.cancel event, so
1160-
// we pull out the transaction IDs from the cancellation events
1161-
// so we can flag the verification events as cancelled in the loop
1162-
// below.
1163-
if (toDeviceEvent.getType() === "m.key.verification.cancel") {
1164-
const txnId: string = toDeviceEvent.getContent()["transaction_id"];
1165-
if (txnId) {
1166-
cancelledKeyVerificationTxns.push(txnId);
1167-
}
1168-
}
1169-
1170-
// as mentioned above, .map is a cheap inline forEach, so return
1171-
// the unmodified event.
1172-
return toDeviceEvent;
1173-
})
1174-
.forEach(function (toDeviceEvent) {
1175-
const content = toDeviceEvent.getContent();
1176-
if (toDeviceEvent.getType() == "m.room.message" && content.msgtype == "m.bad.encrypted") {
1177-
// the mapper already logged a warning.
1178-
logger.log("Ignoring undecryptable to-device event from " + toDeviceEvent.getSender());
1179-
return;
1180-
}
1181-
1182-
if (
1183-
toDeviceEvent.getType() === "m.key.verification.start" ||
1184-
toDeviceEvent.getType() === "m.key.verification.request"
1185-
) {
1186-
const txnId = content["transaction_id"];
1187-
if (cancelledKeyVerificationTxns.includes(txnId)) {
1188-
toDeviceEvent.flagCancelled();
1189-
}
1190-
}
1191-
1192-
client.emit(ClientEvent.ToDeviceEvent, toDeviceEvent);
1193-
});
1153+
processToDeviceMessages(toDeviceMessages, client);
11941154
} else {
11951155
// no more to-device events: we can stop polling with a short timeout.
11961156
this.catchingUp = false;
@@ -1946,7 +1906,56 @@ export function _createAndReEmitRoom(client: MatrixClient, roomId: string, opts:
19461906
return room;
19471907
}
19481908

1949-
export function mapToDeviceEvent(plainOldJsObject: Partial<IEvent>): MatrixEvent {
1909+
/**
1910+
* Process a list of (decrypted, where possible) received to-device events.
1911+
*
1912+
* Converts the events into `MatrixEvent`s, and emits appropriate {@link ClientEvent.ToDeviceEvent} events.
1913+
* */
1914+
export function processToDeviceMessages(toDeviceMessages: IToDeviceEvent[], client: MatrixClient): void {
1915+
const cancelledKeyVerificationTxns: string[] = [];
1916+
toDeviceMessages
1917+
.map(mapToDeviceEvent)
1918+
.map((toDeviceEvent) => {
1919+
// map is a cheap inline forEach
1920+
// We want to flag m.key.verification.start events as cancelled
1921+
// if there's an accompanying m.key.verification.cancel event, so
1922+
// we pull out the transaction IDs from the cancellation events
1923+
// so we can flag the verification events as cancelled in the loop
1924+
// below.
1925+
if (toDeviceEvent.getType() === "m.key.verification.cancel") {
1926+
const txnId: string = toDeviceEvent.getContent()["transaction_id"];
1927+
if (txnId) {
1928+
cancelledKeyVerificationTxns.push(txnId);
1929+
}
1930+
}
1931+
1932+
// as mentioned above, .map is a cheap inline forEach, so return
1933+
// the unmodified event.
1934+
return toDeviceEvent;
1935+
})
1936+
.forEach(function (toDeviceEvent) {
1937+
const content = toDeviceEvent.getContent();
1938+
if (toDeviceEvent.getType() == "m.room.message" && content.msgtype == "m.bad.encrypted") {
1939+
// the mapper already logged a warning.
1940+
logger.log("Ignoring undecryptable to-device event from " + toDeviceEvent.getSender());
1941+
return;
1942+
}
1943+
1944+
if (
1945+
toDeviceEvent.getType() === "m.key.verification.start" ||
1946+
toDeviceEvent.getType() === "m.key.verification.request"
1947+
) {
1948+
const txnId = content["transaction_id"];
1949+
if (cancelledKeyVerificationTxns.includes(txnId)) {
1950+
toDeviceEvent.flagCancelled();
1951+
}
1952+
}
1953+
1954+
client.emit(ClientEvent.ToDeviceEvent, toDeviceEvent);
1955+
});
1956+
}
1957+
1958+
function mapToDeviceEvent(plainOldJsObject: Partial<IEvent>): MatrixEvent {
19501959
// to-device events should not have a `room_id` property, but let's be sure
19511960
delete plainOldJsObject.room_id;
19521961
return new MatrixEvent(plainOldJsObject);

0 commit comments

Comments
 (0)
Please sign in to comment.