fix: harden Matrix verification fallback paths

This commit is contained in:
Gustavo Madeira Santana
2026-04-23 09:20:35 -04:00
parent ce6b53cf92
commit 35c9a0fdc9
3 changed files with 45 additions and 2 deletions

View File

@@ -372,7 +372,7 @@ export class MatrixClient {
trustOwnDeviceAfterSas: async (deviceId: string) => {
const crypto = this.client.getCrypto() as MatrixCryptoBootstrapApi | undefined;
if (typeof crypto?.crossSignDevice !== "function") {
throw new Error("Matrix crypto backend does not support cross-signing devices");
return;
}
await crypto.crossSignDevice(deviceId);
},

View File

@@ -188,6 +188,45 @@ describe("MatrixVerificationManager", () => {
expect(secondSummary.chosenMethod).toBe("m.sas.v1");
});
it("reuses the tracked id when the other device id is populated later", () => {
const manager = new MatrixVerificationManager();
const first = new MockVerificationRequest({
transactionId: "txn-device-later",
phase: VerificationPhase.Requested,
});
const second = new MockVerificationRequest({
transactionId: "txn-device-later",
phase: VerificationPhase.Ready,
otherDeviceId: "DEVICE_LATER",
pending: false,
});
const firstSummary = manager.trackVerificationRequest(first);
const secondSummary = manager.trackVerificationRequest(second);
expect(secondSummary.id).toBe(firstSummary.id);
expect(secondSummary.otherDeviceId).toBe("DEVICE_LATER");
expect(manager.listVerifications()).toHaveLength(1);
});
it("keeps separate sessions when stable other device ids differ", () => {
const manager = new MatrixVerificationManager();
const first = new MockVerificationRequest({
transactionId: "txn-different-devices",
otherDeviceId: "DEVICE_A",
});
const second = new MockVerificationRequest({
transactionId: "txn-different-devices",
otherDeviceId: "DEVICE_B",
});
const firstSummary = manager.trackVerificationRequest(first);
const secondSummary = manager.trackVerificationRequest(second);
expect(secondSummary.id).not.toBe(firstSummary.id);
expect(manager.listVerifications()).toHaveLength(2);
});
it("does not overwrite a different verification request with a colliding transaction ID", async () => {
const manager = new MatrixVerificationManager();
const first = new MockVerificationRequest({

View File

@@ -204,12 +204,16 @@ export class MatrixVerificationManager {
leftIdentity.transactionId === rightIdentity.transactionId &&
leftIdentity.roomId === rightIdentity.roomId &&
leftIdentity.otherUserId === rightIdentity.otherUserId &&
leftIdentity.otherDeviceId === rightIdentity.otherDeviceId &&
this.isSameOptionalIdentityValue(leftIdentity.otherDeviceId, rightIdentity.otherDeviceId) &&
leftIdentity.isSelfVerification === rightIdentity.isSelfVerification &&
leftIdentity.initiatedByMe === rightIdentity.initiatedByMe
);
}
private isSameOptionalIdentityValue(left: string, right: string): boolean {
return left === "" || right === "" || left === right;
}
private pruneVerificationSessions(nowMs: number): void {
for (const [id, session] of this.verificationSessions) {
const phase = this.readVerificationPhase(session.request, -1);