From 7aeda70ff66614c74e69a4345202ebcbbfde8769 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 15 Feb 2022 18:19:49 +0100 Subject: [PATCH 01/13] convert DecryptionResult --- ...ecryptionResult.js => DecryptionResult.ts} | 44 +++++++++++-------- .../megolm/decryption/SessionDecryption.ts | 2 +- 2 files changed, 26 insertions(+), 20 deletions(-) rename src/matrix/e2ee/{DecryptionResult.js => DecryptionResult.ts} (66%) diff --git a/src/matrix/e2ee/DecryptionResult.js b/src/matrix/e2ee/DecryptionResult.ts similarity index 66% rename from src/matrix/e2ee/DecryptionResult.js rename to src/matrix/e2ee/DecryptionResult.ts index e1c2bcc4..67c242bc 100644 --- a/src/matrix/e2ee/DecryptionResult.js +++ b/src/matrix/e2ee/DecryptionResult.ts @@ -26,35 +26,41 @@ limitations under the License. * see DeviceTracker */ +import type {DeviceIdentity} from "../storage/idb/stores/DeviceIdentityStore"; +type DecryptedEvent = { + type?: string, + content?: Record +} export class DecryptionResult { - constructor(event, senderCurve25519Key, claimedEd25519Key) { - this.event = event; - this.senderCurve25519Key = senderCurve25519Key; - this.claimedEd25519Key = claimedEd25519Key; - this._device = null; - this._roomTracked = true; + private device?: DeviceIdentity; + private roomTracked: boolean = true; + + constructor( + public readonly event: DecryptedEvent, + public readonly senderCurve25519Key: string, + public readonly claimedEd25519Key: string + ) {} + + setDevice(device: DeviceIdentity) { + this.device = device; } - setDevice(device) { - this._device = device; + setRoomNotTrackedYet(): void { + this.roomTracked = false; } - setRoomNotTrackedYet() { - this._roomTracked = false; - } - - get isVerified() { - if (this._device) { - const comesFromDevice = this._device.ed25519Key === this.claimedEd25519Key; + get isVerified(): boolean { + if (this.device) { + const comesFromDevice = this.device.ed25519Key === this.claimedEd25519Key; return comesFromDevice; } return false; } - get isUnverified() { - if (this._device) { + get isUnverified(): boolean { + if (this.device) { return !this.isVerified; } else if (this.isVerificationUnknown) { return false; @@ -63,8 +69,8 @@ export class DecryptionResult { } } - get isVerificationUnknown() { + get isVerificationUnknown(): boolean { // verification is unknown if we haven't yet fetched the devices for the room - return !this._device && !this._roomTracked; + return !this.device && !this.roomTracked; } } diff --git a/src/matrix/e2ee/megolm/decryption/SessionDecryption.ts b/src/matrix/e2ee/megolm/decryption/SessionDecryption.ts index f56feb47..57ef9a96 100644 --- a/src/matrix/e2ee/megolm/decryption/SessionDecryption.ts +++ b/src/matrix/e2ee/megolm/decryption/SessionDecryption.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {DecryptionResult} from "../../DecryptionResult.js"; +import {DecryptionResult} from "../../DecryptionResult"; import {DecryptionError} from "../../common.js"; import {ReplayDetectionEntry} from "./ReplayDetectionEntry"; import type {RoomKey} from "./RoomKey"; From 74c640f9375d59f84ca450d4635c77b2829be94b Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 15 Feb 2022 18:20:49 +0100 Subject: [PATCH 02/13] convert Session --- src/matrix/e2ee/olm/Encryption.js | 2 +- .../e2ee/olm/{Session.js => Session.ts} | 35 +++++++++++-------- .../storage/idb/stores/OlmSessionStore.ts | 18 +++++----- 3 files changed, 31 insertions(+), 24 deletions(-) rename src/matrix/e2ee/olm/{Session.js => Session.ts} (53%) diff --git a/src/matrix/e2ee/olm/Encryption.js b/src/matrix/e2ee/olm/Encryption.js index 652c657c..3e78470d 100644 --- a/src/matrix/e2ee/olm/Encryption.js +++ b/src/matrix/e2ee/olm/Encryption.js @@ -16,7 +16,7 @@ limitations under the License. import {groupByWithCreator} from "../../../utils/groupBy"; import {verifyEd25519Signature, OLM_ALGORITHM} from "../common.js"; -import {createSessionEntry} from "./Session.js"; +import {createSessionEntry} from "./Session"; function findFirstSessionId(sessionIds) { return sessionIds.reduce((first, sessionId) => { diff --git a/src/matrix/e2ee/olm/Session.js b/src/matrix/e2ee/olm/Session.ts similarity index 53% rename from src/matrix/e2ee/olm/Session.js rename to src/matrix/e2ee/olm/Session.ts index 9b5f4db0..f97c8478 100644 --- a/src/matrix/e2ee/olm/Session.js +++ b/src/matrix/e2ee/olm/Session.ts @@ -14,7 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -export function createSessionEntry(olmSession, senderKey, timestamp, pickleKey) { +import type {OlmSessionEntry} from "../../storage/idb/stores/OlmSessionStore"; +import type * as OlmNamespace from "@matrix-org/olm"; +type Olm = typeof OlmNamespace; + +export function createSessionEntry(olmSession: Olm.Session, senderKey: string, timestamp: number, pickleKey: string): OlmSessionEntry { return { session: olmSession.pickle(pickleKey), sessionId: olmSession.session_id(), @@ -24,35 +28,38 @@ export function createSessionEntry(olmSession, senderKey, timestamp, pickleKey) } export class Session { - constructor(data, pickleKey, olm, isNew = false) { - this.data = data; - this._olm = olm; - this._pickleKey = pickleKey; - this.isNew = isNew; + public isModified: boolean; + + constructor( + public readonly data: OlmSessionEntry, + private readonly pickleKey: string, + private readonly olm: Olm, + public isNew: boolean = false + ) { this.isModified = isNew; } - static create(senderKey, olmSession, olm, pickleKey, timestamp) { + static create(senderKey: string, olmSession: Olm.Session, olm: Olm, pickleKey: string, timestamp: number): Session { const data = createSessionEntry(olmSession, senderKey, timestamp, pickleKey); return new Session(data, pickleKey, olm, true); } - get id() { + get id(): string { return this.data.sessionId; } - load() { - const session = new this._olm.Session(); - session.unpickle(this._pickleKey, this.data.session); + load(): Olm.Session { + const session = new this.olm.Session(); + session.unpickle(this.pickleKey, this.data.session); return session; } - unload(olmSession) { + unload(olmSession: Olm.Session): void { olmSession.free(); } - save(olmSession) { - this.data.session = olmSession.pickle(this._pickleKey); + save(olmSession: Olm.Session): void { + this.data.session = olmSession.pickle(this.pickleKey); this.isModified = true; } } diff --git a/src/matrix/storage/idb/stores/OlmSessionStore.ts b/src/matrix/storage/idb/stores/OlmSessionStore.ts index d5a79de2..1263a649 100644 --- a/src/matrix/storage/idb/stores/OlmSessionStore.ts +++ b/src/matrix/storage/idb/stores/OlmSessionStore.ts @@ -24,19 +24,19 @@ function decodeKey(key: string): { senderKey: string, sessionId: string } { return {senderKey, sessionId}; } -interface OlmSession { +export type OlmSessionEntry = { session: string; sessionId: string; senderKey: string; lastUsed: number; } -type OlmSessionEntry = OlmSession & { key: string }; +type OlmSessionStoredEntry = OlmSessionEntry & { key: string }; export class OlmSessionStore { - private _store: Store; + private _store: Store; - constructor(store: Store) { + constructor(store: Store) { this._store = store; } @@ -55,20 +55,20 @@ export class OlmSessionStore { return sessionIds; } - getAll(senderKey: string): Promise { + getAll(senderKey: string): Promise { const range = this._store.IDBKeyRange.lowerBound(encodeKey(senderKey, "")); return this._store.selectWhile(range, session => { return session.senderKey === senderKey; }); } - get(senderKey: string, sessionId: string): Promise { + get(senderKey: string, sessionId: string): Promise { return this._store.get(encodeKey(senderKey, sessionId)); } - set(session: OlmSession): void { - (session as OlmSessionEntry).key = encodeKey(session.senderKey, session.sessionId); - this._store.put(session as OlmSessionEntry); + set(session: OlmSessionEntry): void { + (session as OlmSessionStoredEntry).key = encodeKey(session.senderKey, session.sessionId); + this._store.put(session as OlmSessionStoredEntry); } remove(senderKey: string, sessionId: string): void { From a4fd1615ddbc0472e02825eb9a3fe3185a225c0c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 15 Feb 2022 18:21:29 +0100 Subject: [PATCH 03/13] convert decryption --- src/matrix/Session.js | 18 +- .../e2ee/olm/{Decryption.js => Decryption.ts} | 161 ++++++++++-------- src/matrix/e2ee/olm/types.ts | 43 +++++ src/utils/Lock.ts | 8 +- 4 files changed, 150 insertions(+), 80 deletions(-) rename src/matrix/e2ee/olm/{Decryption.js => Decryption.ts} (70%) create mode 100644 src/matrix/e2ee/olm/types.ts diff --git a/src/matrix/Session.js b/src/matrix/Session.js index 83a2df02..72d8a313 100644 --- a/src/matrix/Session.js +++ b/src/matrix/Session.js @@ -26,7 +26,7 @@ import {User} from "./User.js"; import {DeviceMessageHandler} from "./DeviceMessageHandler.js"; import {Account as E2EEAccount} from "./e2ee/Account.js"; import {uploadAccountAsDehydratedDevice} from "./e2ee/Dehydration.js"; -import {Decryption as OlmDecryption} from "./e2ee/olm/Decryption.js"; +import {Decryption as OlmDecryption} from "./e2ee/olm/Decryption"; import {Encryption as OlmEncryption} from "./e2ee/olm/Encryption.js"; import {Decryption as MegOlmDecryption} from "./e2ee/megolm/Decryption"; import {KeyLoader as MegOlmKeyLoader} from "./e2ee/megolm/decryption/KeyLoader"; @@ -123,15 +123,15 @@ export class Session { // TODO: this should all go in a wrapper in e2ee/ that is bootstrapped by passing in the account // and can create RoomEncryption objects and handle encrypted to_device messages and device list changes. const senderKeyLock = new LockMap(); - const olmDecryption = new OlmDecryption({ - account: this._e2eeAccount, - pickleKey: PICKLE_KEY, - olm: this._olm, - storage: this._storage, - now: this._platform.clock.now, - ownUserId: this._user.id, + const olmDecryption = new OlmDecryption( + this._e2eeAccount, + PICKLE_KEY, + this._olm, + this._storage, + this._platform.clock.now, + this._user.id, senderKeyLock - }); + ); this._olmEncryption = new OlmEncryption({ account: this._e2eeAccount, pickleKey: PICKLE_KEY, diff --git a/src/matrix/e2ee/olm/Decryption.js b/src/matrix/e2ee/olm/Decryption.ts similarity index 70% rename from src/matrix/e2ee/olm/Decryption.js rename to src/matrix/e2ee/olm/Decryption.ts index 16e617a5..0fd4f0f9 100644 --- a/src/matrix/e2ee/olm/Decryption.js +++ b/src/matrix/e2ee/olm/Decryption.ts @@ -16,32 +16,52 @@ limitations under the License. import {DecryptionError} from "../common.js"; import {groupBy} from "../../../utils/groupBy"; -import {MultiLock} from "../../../utils/Lock"; +import {MultiLock, ILock} from "../../../utils/Lock"; import {Session} from "./Session.js"; -import {DecryptionResult} from "../DecryptionResult.js"; +import {DecryptionResult} from "../DecryptionResult"; + +import type {OlmMessage, OlmPayload} from "./types"; +import type {Account} from "../Account"; +import type {LockMap} from "../../../utils/LockMap"; +import type {Storage} from "../../storage/idb/Storage"; +import type {Transaction} from "../../storage/idb/Transaction"; +import type {OlmEncryptedEvent} from "./types"; +import type * as OlmNamespace from "@matrix-org/olm"; +type Olm = typeof OlmNamespace; const SESSION_LIMIT_PER_SENDER_KEY = 4; -function isPreKeyMessage(message) { +type DecryptionResults = { + results: DecryptionResult[], + errors: DecryptionError[], + senderKeyDecryption: SenderKeyDecryption +}; + +type CreateAndDecryptResult = { + session: Session, + plaintext: string +}; + +function isPreKeyMessage(message: OlmMessage): boolean { return message.type === 0; } -function sortSessions(sessions) { +function sortSessions(sessions: Session[]) { sessions.sort((a, b) => { return b.data.lastUsed - a.data.lastUsed; }); } export class Decryption { - constructor({account, pickleKey, now, ownUserId, storage, olm, senderKeyLock}) { - this._account = account; - this._pickleKey = pickleKey; - this._now = now; - this._ownUserId = ownUserId; - this._storage = storage; - this._olm = olm; - this._senderKeyLock = senderKeyLock; - } + constructor( + private readonly account: Account, + private readonly pickleKey: string, + private readonly now: () => number, + private readonly ownUserId: string, + private readonly storage: Storage, + private readonly olm: Olm, + private readonly senderKeyLock: LockMap + ) {} // we need to lock because both encryption and decryption can't be done in one txn, // so for them not to step on each other toes, we need to lock. @@ -50,8 +70,8 @@ export class Decryption { // - decryptAll below fails (to release the lock as early as we can) // - DecryptionChanges.write succeeds // - Sync finishes the writeSync phase (or an error was thrown, in case we never get to DecryptionChanges.write) - async obtainDecryptionLock(events) { - const senderKeys = new Set(); + async obtainDecryptionLock(events: OlmEncryptedEvent[]): Promise { + const senderKeys = new Set(); for (const event of events) { const senderKey = event.content?.["sender_key"]; if (senderKey) { @@ -61,7 +81,7 @@ export class Decryption { // take a lock on all senderKeys so encryption or other calls to decryptAll (should not happen) // don't modify the sessions at the same time const locks = await Promise.all(Array.from(senderKeys).map(senderKey => { - return this._senderKeyLock.takeLock(senderKey); + return this.senderKeyLock.takeLock(senderKey); })); return new MultiLock(locks); } @@ -83,18 +103,18 @@ export class Decryption { * @param {[type]} events * @return {Promise} [description] */ - async decryptAll(events, lock, txn) { + async decryptAll(events: OlmEncryptedEvent[], lock: ILock, txn: Transaction): Promise { try { - const eventsPerSenderKey = groupBy(events, event => event.content?.["sender_key"]); - const timestamp = this._now(); + const eventsPerSenderKey = groupBy(events, (event: OlmEncryptedEvent) => event.content?.["sender_key"]); + const timestamp = this.now(); // decrypt events for different sender keys in parallel const senderKeyOperations = await Promise.all(Array.from(eventsPerSenderKey.entries()).map(([senderKey, events]) => { - return this._decryptAllForSenderKey(senderKey, events, timestamp, txn); + return this._decryptAllForSenderKey(senderKey!, events, timestamp, txn); })); - const results = senderKeyOperations.reduce((all, r) => all.concat(r.results), []); - const errors = senderKeyOperations.reduce((all, r) => all.concat(r.errors), []); + const results = senderKeyOperations.reduce((all, r) => all.concat(r.results), [] as DecryptionResult[]); + const errors = senderKeyOperations.reduce((all, r) => all.concat(r.errors), [] as DecryptionError[]); const senderKeyDecryptions = senderKeyOperations.map(r => r.senderKeyDecryption); - return new DecryptionChanges(senderKeyDecryptions, results, errors, this._account, lock); + return new DecryptionChanges(senderKeyDecryptions, results, errors, this.account, lock); } catch (err) { // make sure the locks are release if something throws // otherwise they will be released in DecryptionChanges after having written @@ -104,11 +124,11 @@ export class Decryption { } } - async _decryptAllForSenderKey(senderKey, events, timestamp, readSessionsTxn) { + async _decryptAllForSenderKey(senderKey: string, events: OlmEncryptedEvent[], timestamp: number, readSessionsTxn: Transaction): Promise { const sessions = await this._getSessions(senderKey, readSessionsTxn); - const senderKeyDecryption = new SenderKeyDecryption(senderKey, sessions, this._olm, timestamp); - const results = []; - const errors = []; + const senderKeyDecryption = new SenderKeyDecryption(senderKey, sessions, this.olm, timestamp); + const results: DecryptionResult[] = []; + const errors: DecryptionError[] = []; // events for a single senderKey need to be decrypted one by one for (const event of events) { try { @@ -121,10 +141,10 @@ export class Decryption { return {results, errors, senderKeyDecryption}; } - _decryptForSenderKey(senderKeyDecryption, event, timestamp) { + _decryptForSenderKey(senderKeyDecryption: SenderKeyDecryption, event: OlmEncryptedEvent, timestamp: number): DecryptionResult { const senderKey = senderKeyDecryption.senderKey; const message = this._getMessageAndValidateEvent(event); - let plaintext; + let plaintext: string | undefined; try { plaintext = senderKeyDecryption.decrypt(message); } catch (err) { @@ -133,7 +153,7 @@ export class Decryption { } // could not decrypt with any existing session if (typeof plaintext !== "string" && isPreKeyMessage(message)) { - let createResult; + let createResult: CreateAndDecryptResult; try { createResult = this._createSessionAndDecrypt(senderKey, message, timestamp); } catch (error) { @@ -143,14 +163,14 @@ export class Decryption { plaintext = createResult.plaintext; } if (typeof plaintext === "string") { - let payload; + let payload: OlmPayload; try { payload = JSON.parse(plaintext); } catch (error) { throw new DecryptionError("PLAINTEXT_NOT_JSON", event, {plaintext, error}); } this._validatePayload(payload, event); - return new DecryptionResult(payload, senderKey, payload.keys.ed25519); + return new DecryptionResult(payload, senderKey, payload.keys!.ed25519!); } else { throw new DecryptionError("OLM_NO_MATCHING_SESSION", event, {knownSessionIds: senderKeyDecryption.sessions.map(s => s.id)}); @@ -158,16 +178,16 @@ export class Decryption { } // only for pre-key messages after having attempted decryption with existing sessions - _createSessionAndDecrypt(senderKey, message, timestamp) { + _createSessionAndDecrypt(senderKey: string, message: OlmMessage, timestamp: number): CreateAndDecryptResult { let plaintext; // if we have multiple messages encrypted with the same new session, // this could create multiple sessions as the OTK isn't removed yet // (this only happens in DecryptionChanges.write) // This should be ok though as we'll first try to decrypt with the new session - const olmSession = this._account.createInboundOlmSession(senderKey, message.body); + const olmSession = this.account.createInboundOlmSession(senderKey, message.body); try { plaintext = olmSession.decrypt(message.type, message.body); - const session = Session.create(senderKey, olmSession, this._olm, this._pickleKey, timestamp); + const session = Session.create(senderKey, olmSession, this.olm, this.pickleKey, timestamp); session.unload(olmSession); return {session, plaintext}; } catch (err) { @@ -176,12 +196,12 @@ export class Decryption { } } - _getMessageAndValidateEvent(event) { + _getMessageAndValidateEvent(event: OlmEncryptedEvent): OlmMessage { const ciphertext = event.content?.ciphertext; if (!ciphertext) { throw new DecryptionError("OLM_MISSING_CIPHERTEXT", event); } - const message = ciphertext?.[this._account.identityKeys.curve25519]; + const message = ciphertext?.[this.account.identityKeys.curve25519]; if (!message) { throw new DecryptionError("OLM_NOT_INCLUDED_IN_RECIPIENTS", event); } @@ -189,22 +209,22 @@ export class Decryption { return message; } - async _getSessions(senderKey, txn) { + async _getSessions(senderKey: string, txn: Transaction): Promise { const sessionEntries = await txn.olmSessions.getAll(senderKey); // sort most recent used sessions first - const sessions = sessionEntries.map(s => new Session(s, this._pickleKey, this._olm)); + const sessions = sessionEntries.map(s => new Session(s, this.pickleKey, this.olm)); sortSessions(sessions); return sessions; } - _validatePayload(payload, event) { + _validatePayload(payload: OlmPayload, event: OlmEncryptedEvent): void { if (payload.sender !== event.sender) { throw new DecryptionError("OLM_FORWARDED_MESSAGE", event, {sentBy: event.sender, encryptedBy: payload.sender}); } - if (payload.recipient !== this._ownUserId) { + if (payload.recipient !== this.ownUserId) { throw new DecryptionError("OLM_BAD_RECIPIENT", event, {recipient: payload.recipient}); } - if (payload.recipient_keys?.ed25519 !== this._account.identityKeys.ed25519) { + if (payload.recipient_keys?.ed25519 !== this.account.identityKeys.ed25519) { throw new DecryptionError("OLM_BAD_RECIPIENT_KEY", event, {key: payload.recipient_keys?.ed25519}); } // TODO: check room_id @@ -219,21 +239,21 @@ export class Decryption { // decryption helper for a single senderKey class SenderKeyDecryption { - constructor(senderKey, sessions, olm, timestamp) { - this.senderKey = senderKey; - this.sessions = sessions; - this._olm = olm; - this._timestamp = timestamp; - } + constructor( + public readonly senderKey: string, + public readonly sessions: Session[], + private readonly olm: Olm, + private readonly timestamp: number + ) {} - addNewSession(session) { + addNewSession(session: Session) { // add at top as it is most recent this.sessions.unshift(session); } - decrypt(message) { + decrypt(message: OlmMessage): string | undefined { for (const session of this.sessions) { - const plaintext = this._decryptWithSession(session, message); + const plaintext = this.decryptWithSession(session, message); if (typeof plaintext === "string") { // keep them sorted so will try the same session first for other messages // and so we can assume the excess ones are at the end @@ -244,11 +264,11 @@ class SenderKeyDecryption { } } - getModifiedSessions() { + getModifiedSessions(): Session[] { return this.sessions.filter(session => session.isModified); } - get hasNewSessions() { + get hasNewSessions(): boolean { return this.sessions.some(session => session.isNew); } @@ -257,7 +277,10 @@ class SenderKeyDecryption { // if this turns out to be a real cost for IE11, // we could look into adding a less expensive serialization mechanism // for olm sessions to libolm - _decryptWithSession(session, message) { + private decryptWithSession(session: Session, message: OlmMessage): string | undefined { + if (message.type === undefined || message.body === undefined) { + throw new Error("Invalid message without type or body"); + } const olmSession = session.load(); try { if (isPreKeyMessage(message) && !olmSession.matches_inbound(message.body)) { @@ -266,7 +289,7 @@ class SenderKeyDecryption { try { const plaintext = olmSession.decrypt(message.type, message.body); session.save(olmSession); - session.lastUsed = this._timestamp; + session.data.lastUsed = this.timestamp; return plaintext; } catch (err) { if (isPreKeyMessage(message)) { @@ -286,27 +309,27 @@ class SenderKeyDecryption { * @property {Array} errors see DecryptionError.event to retrieve the event that failed to decrypt. */ class DecryptionChanges { - constructor(senderKeyDecryptions, results, errors, account, lock) { - this._senderKeyDecryptions = senderKeyDecryptions; - this._account = account; - this.results = results; - this.errors = errors; - this._lock = lock; + constructor( + private readonly senderKeyDecryptions: SenderKeyDecryption[], + private readonly results: DecryptionResult[], + private readonly errors: DecryptionError[], + private readonly account: Account, + private readonly lock: ILock + ) {} + + get hasNewSessions(): boolean { + return this.senderKeyDecryptions.some(skd => skd.hasNewSessions); } - get hasNewSessions() { - return this._senderKeyDecryptions.some(skd => skd.hasNewSessions); - } - - write(txn) { + write(txn: Transaction): void { try { - for (const senderKeyDecryption of this._senderKeyDecryptions) { + for (const senderKeyDecryption of this.senderKeyDecryptions) { for (const session of senderKeyDecryption.getModifiedSessions()) { txn.olmSessions.set(session.data); if (session.isNew) { const olmSession = session.load(); try { - this._account.writeRemoveOneTimeKey(olmSession, txn); + this.account.writeRemoveOneTimeKey(olmSession, txn); } finally { session.unload(olmSession); } @@ -322,7 +345,7 @@ class DecryptionChanges { } } } finally { - this._lock.release(); + this.lock.release(); } } } diff --git a/src/matrix/e2ee/olm/types.ts b/src/matrix/e2ee/olm/types.ts new file mode 100644 index 00000000..b9e394d5 --- /dev/null +++ b/src/matrix/e2ee/olm/types.ts @@ -0,0 +1,43 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export type OlmMessage = { + type?: 0 | 1, + body?: string +} + +export type OlmEncryptedMessageContent = { + algorithm?: "m.olm.v1.curve25519-aes-sha2" + sender_key?: string, + ciphertext?: { + [deviceCurve25519Key: string]: OlmMessage + } +} + +export type OlmEncryptedEvent = { + type?: "m.room.encrypted", + content?: OlmEncryptedMessageContent + sender?: string +} + +export type OlmPayload = { + type?: string; + content?: Record; + sender?: string; + recipient?: string; + recipient_keys?: {ed25519?: string}; + keys?: {ed25519?: string}; +} diff --git a/src/utils/Lock.ts b/src/utils/Lock.ts index 238d88f9..ff623eba 100644 --- a/src/utils/Lock.ts +++ b/src/utils/Lock.ts @@ -14,7 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -export class Lock { +export interface ILock { + release(): void; +} + +export class Lock implements ILock { private _promise?: Promise; private _resolve?: (() => void); @@ -52,7 +56,7 @@ export class Lock { } } -export class MultiLock { +export class MultiLock implements ILock { constructor(public readonly locks: Lock[]) { } From eb5ca200f2559a29545e1c3390960bc723317baf Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 16 Feb 2022 18:00:03 +0100 Subject: [PATCH 04/13] missed rename here --- src/matrix/e2ee/olm/Decryption.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/matrix/e2ee/olm/Decryption.ts b/src/matrix/e2ee/olm/Decryption.ts index 0fd4f0f9..7d9be4a3 100644 --- a/src/matrix/e2ee/olm/Decryption.ts +++ b/src/matrix/e2ee/olm/Decryption.ts @@ -17,7 +17,7 @@ limitations under the License. import {DecryptionError} from "../common.js"; import {groupBy} from "../../../utils/groupBy"; import {MultiLock, ILock} from "../../../utils/Lock"; -import {Session} from "./Session.js"; +import {Session} from "./Session"; import {DecryptionResult} from "../DecryptionResult"; import type {OlmMessage, OlmPayload} from "./types"; @@ -246,7 +246,7 @@ class SenderKeyDecryption { private readonly timestamp: number ) {} - addNewSession(session: Session) { + addNewSession(session: Session): void { // add at top as it is most recent this.sessions.unshift(session); } From e3e90ed1671c247f623ceba95d1ff58d7bcf6f01 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 16 Feb 2022 18:00:13 +0100 Subject: [PATCH 05/13] convert olm/Encryption to TS --- src/matrix/Session.js | 20 +-- .../e2ee/olm/{Encryption.js => Encryption.ts} | 141 +++++++++++------- 2 files changed, 94 insertions(+), 67 deletions(-) rename src/matrix/e2ee/olm/{Encryption.js => Encryption.ts} (64%) diff --git a/src/matrix/Session.js b/src/matrix/Session.js index 72d8a313..8652a1d7 100644 --- a/src/matrix/Session.js +++ b/src/matrix/Session.js @@ -27,7 +27,7 @@ import {DeviceMessageHandler} from "./DeviceMessageHandler.js"; import {Account as E2EEAccount} from "./e2ee/Account.js"; import {uploadAccountAsDehydratedDevice} from "./e2ee/Dehydration.js"; import {Decryption as OlmDecryption} from "./e2ee/olm/Decryption"; -import {Encryption as OlmEncryption} from "./e2ee/olm/Encryption.js"; +import {Encryption as OlmEncryption} from "./e2ee/olm/Encryption"; import {Decryption as MegOlmDecryption} from "./e2ee/megolm/Decryption"; import {KeyLoader as MegOlmKeyLoader} from "./e2ee/megolm/decryption/KeyLoader"; import {KeyBackup} from "./e2ee/megolm/keybackup/KeyBackup"; @@ -132,16 +132,16 @@ export class Session { this._user.id, senderKeyLock ); - this._olmEncryption = new OlmEncryption({ - account: this._e2eeAccount, - pickleKey: PICKLE_KEY, - olm: this._olm, - storage: this._storage, - now: this._platform.clock.now, - ownUserId: this._user.id, - olmUtil: this._olmUtil, + this._olmEncryption = new OlmEncryption( + this._e2eeAccount, + PICKLE_KEY, + this._olm, + this._storage, + this._platform.clock.now, + this._user.id, + this._olmUtil, senderKeyLock - }); + ); this._keyLoader = new MegOlmKeyLoader(this._olm, PICKLE_KEY, 20); this._megolmEncryption = new MegOlmEncryption({ account: this._e2eeAccount, diff --git a/src/matrix/e2ee/olm/Encryption.js b/src/matrix/e2ee/olm/Encryption.ts similarity index 64% rename from src/matrix/e2ee/olm/Encryption.js rename to src/matrix/e2ee/olm/Encryption.ts index 3e78470d..ebc38170 100644 --- a/src/matrix/e2ee/olm/Encryption.js +++ b/src/matrix/e2ee/olm/Encryption.ts @@ -18,6 +18,32 @@ import {groupByWithCreator} from "../../../utils/groupBy"; import {verifyEd25519Signature, OLM_ALGORITHM} from "../common.js"; import {createSessionEntry} from "./Session"; +import type {OlmMessage, OlmPayload, OlmEncryptedMessageContent} from "./types"; +import type {Account} from "../Account"; +import type {LockMap} from "../../../utils/LockMap"; +import type {Storage} from "../../storage/idb/Storage"; +import type {Transaction} from "../../storage/idb/Transaction"; +import type {DeviceIdentity} from "../../storage/idb/stores/DeviceIdentityStore"; +import type {HomeServerApi} from "../../net/HomeServerApi"; +import type {ILogItem} from "../../../logging/types"; +import type * as OlmNamespace from "@matrix-org/olm"; +type Olm = typeof OlmNamespace; + +type ClaimedOTKResponse = { + [userId: string]: { + [deviceId: string]: { + [algorithmAndOtk: string]: { + key: string, + signatures: { + [userId: string]: { + [algorithmAndDevice: string]: string + } + } + } + } + } +}; + function findFirstSessionId(sessionIds) { return sessionIds.reduce((first, sessionId) => { if (!first || sessionId < first) { @@ -36,19 +62,19 @@ const OTK_ALGORITHM = "signed_curve25519"; const MAX_BATCH_SIZE = 20; export class Encryption { - constructor({account, olm, olmUtil, ownUserId, storage, now, pickleKey, senderKeyLock}) { - this._account = account; - this._olm = olm; - this._olmUtil = olmUtil; - this._ownUserId = ownUserId; - this._storage = storage; - this._now = now; - this._pickleKey = pickleKey; - this._senderKeyLock = senderKeyLock; - } + constructor( + private readonly account: Account, + private readonly olm: Olm, + private readonly olmUtil: Olm.Utility, + private readonly ownUserId: string, + private readonly storage: Storage, + private readonly now: () => number, + private readonly pickleKey: string, + private readonly senderKeyLock: LockMap + ) {} - async encrypt(type, content, devices, hsApi, log) { - let messages = []; + async encrypt(type: string, content: Record, devices: DeviceIdentity[], hsApi: HomeServerApi, log: ILogItem): Promise { + let messages: EncryptedMessage[] = []; for (let i = 0; i < devices.length ; i += MAX_BATCH_SIZE) { const batchDevices = devices.slice(i, i + MAX_BATCH_SIZE); const batchMessages = await this._encryptForMaxDevices(type, content, batchDevices, hsApi, log); @@ -57,12 +83,12 @@ export class Encryption { return messages; } - async _encryptForMaxDevices(type, content, devices, hsApi, log) { + async _encryptForMaxDevices(type: string, content: Record, devices: DeviceIdentity[], hsApi: HomeServerApi, log: ILogItem): Promise { // TODO: see if we can only hold some of the locks until after the /keys/claim call (if needed) // take a lock on all senderKeys so decryption and other calls to encrypt (should not happen) // don't modify the sessions at the same time const locks = await Promise.all(devices.map(device => { - return this._senderKeyLock.takeLock(device.curve25519Key); + return this.senderKeyLock.takeLock(device.curve25519Key); })); try { const { @@ -70,9 +96,9 @@ export class Encryption { existingEncryptionTargets, } = await this._findExistingSessions(devices); - const timestamp = this._now(); + const timestamp = this.now(); - let encryptionTargets = []; + let encryptionTargets: EncryptionTarget[] = []; try { if (devicesWithoutSession.length) { const newEncryptionTargets = await log.wrap("create sessions", log => this._createNewSessions( @@ -100,8 +126,8 @@ export class Encryption { } } - async _findExistingSessions(devices) { - const txn = await this._storage.readTxn([this._storage.storeNames.olmSessions]); + async _findExistingSessions(devices: DeviceIdentity[]): Promise<{devicesWithoutSession: DeviceIdentity[], existingEncryptionTargets: EncryptionTarget[]}> { + const txn = await this.storage.readTxn([this.storage.storeNames.olmSessions]); const sessionIdsForDevice = await Promise.all(devices.map(async device => { return await txn.olmSessions.getSessionIds(device.curve25519Key); })); @@ -116,18 +142,18 @@ export class Encryption { const sessionId = findFirstSessionId(sessionIds); return EncryptionTarget.fromSessionId(device, sessionId); } - }).filter(target => !!target); + }).filter(target => !!target) as EncryptionTarget[]; return {devicesWithoutSession, existingEncryptionTargets}; } - _encryptForDevice(type, content, target) { + _encryptForDevice(type: string, content: Record, target: EncryptionTarget): OlmEncryptedMessageContent { const {session, device} = target; const plaintext = JSON.stringify(this._buildPlainTextMessageForDevice(type, content, device)); - const message = session.encrypt(plaintext); + const message = session!.encrypt(plaintext); const encryptedContent = { algorithm: OLM_ALGORITHM, - sender_key: this._account.identityKeys.curve25519, + sender_key: this.account.identityKeys.curve25519, ciphertext: { [device.curve25519Key]: message } @@ -135,27 +161,27 @@ export class Encryption { return encryptedContent; } - _buildPlainTextMessageForDevice(type, content, device) { + _buildPlainTextMessageForDevice(type: string, content: Record, device: DeviceIdentity): OlmPayload { return { keys: { - "ed25519": this._account.identityKeys.ed25519 + "ed25519": this.account.identityKeys.ed25519 }, recipient_keys: { "ed25519": device.ed25519Key }, recipient: device.userId, - sender: this._ownUserId, + sender: this.ownUserId, content, type } } - async _createNewSessions(devicesWithoutSession, hsApi, timestamp, log) { + async _createNewSessions(devicesWithoutSession: DeviceIdentity[], hsApi: HomeServerApi, timestamp: number, log: ILogItem): Promise { const newEncryptionTargets = await log.wrap("claim", log => this._claimOneTimeKeys(hsApi, devicesWithoutSession, log)); try { for (const target of newEncryptionTargets) { const {device, oneTimeKey} = target; - target.session = await this._account.createOutboundOlmSession(device.curve25519Key, oneTimeKey); + target.session = await this.account.createOutboundOlmSession(device.curve25519Key, oneTimeKey); } await this._storeSessions(newEncryptionTargets, timestamp); } catch (err) { @@ -167,12 +193,12 @@ export class Encryption { return newEncryptionTargets; } - async _claimOneTimeKeys(hsApi, deviceIdentities, log) { + async _claimOneTimeKeys(hsApi: HomeServerApi, deviceIdentities: DeviceIdentity[], log: ILogItem): Promise { // create a Map> const devicesByUser = groupByWithCreator(deviceIdentities, - device => device.userId, - () => new Map(), - (deviceMap, device) => deviceMap.set(device.deviceId, device) + (device: DeviceIdentity) => device.userId, + (): Map => new Map(), + (deviceMap: Map, device: DeviceIdentity) => deviceMap.set(device.deviceId, device) ); const oneTimeKeys = Array.from(devicesByUser.entries()).reduce((usersObj, [userId, deviceMap]) => { usersObj[userId] = Array.from(deviceMap.values()).reduce((devicesObj, device) => { @@ -188,12 +214,12 @@ export class Encryption { if (Object.keys(claimResponse.failures).length) { log.log({l: "failures", servers: Object.keys(claimResponse.failures)}, log.level.Warn); } - const userKeyMap = claimResponse?.["one_time_keys"]; + const userKeyMap = claimResponse?.["one_time_keys"] as ClaimedOTKResponse; return this._verifyAndCreateOTKTargets(userKeyMap, devicesByUser, log); } - _verifyAndCreateOTKTargets(userKeyMap, devicesByUser, log) { - const verifiedEncryptionTargets = []; + _verifyAndCreateOTKTargets(userKeyMap: ClaimedOTKResponse, devicesByUser: Map>, log: ILogItem): EncryptionTarget[] { + const verifiedEncryptionTargets: EncryptionTarget[] = []; for (const [userId, userSection] of Object.entries(userKeyMap)) { for (const [deviceId, deviceSection] of Object.entries(userSection)) { const [firstPropName, keySection] = Object.entries(deviceSection)[0]; @@ -202,7 +228,7 @@ export class Encryption { const device = devicesByUser.get(userId)?.get(deviceId); if (device) { const isValidSignature = verifyEd25519Signature( - this._olmUtil, userId, deviceId, device.ed25519Key, keySection, log); + this.olmUtil, userId, deviceId, device.ed25519Key, keySection, log); if (isValidSignature) { const target = EncryptionTarget.fromOTK(device, keySection.key); verifiedEncryptionTargets.push(target); @@ -214,8 +240,8 @@ export class Encryption { return verifiedEncryptionTargets; } - async _loadSessions(encryptionTargets) { - const txn = await this._storage.readTxn([this._storage.storeNames.olmSessions]); + async _loadSessions(encryptionTargets: EncryptionTarget[]): Promise { + const txn = await this.storage.readTxn([this.storage.storeNames.olmSessions]); // given we run loading in parallel, there might still be some // storage requests that will finish later once one has failed. // those should not allocate a session anymore. @@ -223,10 +249,10 @@ export class Encryption { try { await Promise.all(encryptionTargets.map(async encryptionTarget => { const sessionEntry = await txn.olmSessions.get( - encryptionTarget.device.curve25519Key, encryptionTarget.sessionId); + encryptionTarget.device.curve25519Key, encryptionTarget.sessionId!); if (sessionEntry && !failed) { - const olmSession = new this._olm.Session(); - olmSession.unpickle(this._pickleKey, sessionEntry.session); + const olmSession = new this.olm.Session(); + olmSession.unpickle(this.pickleKey, sessionEntry.session); encryptionTarget.session = olmSession; } })); @@ -240,12 +266,12 @@ export class Encryption { } } - async _storeSessions(encryptionTargets, timestamp) { - const txn = await this._storage.readWriteTxn([this._storage.storeNames.olmSessions]); + async _storeSessions(encryptionTargets: EncryptionTarget[], timestamp: number): Promise { + const txn = await this.storage.readWriteTxn([this.storage.storeNames.olmSessions]); try { for (const target of encryptionTargets) { const sessionEntry = createSessionEntry( - target.session, target.device.curve25519Key, timestamp, this._pickleKey); + target.session!, target.device.curve25519Key, timestamp, this.pickleKey); txn.olmSessions.set(sessionEntry); } } catch (err) { @@ -261,23 +287,24 @@ export class Encryption { // (and later converted to a session) in case of a new session // or an existing session class EncryptionTarget { - constructor(device, oneTimeKey, sessionId) { - this.device = device; - this.oneTimeKey = oneTimeKey; - this.sessionId = sessionId; - // an olmSession, should probably be called olmSession - this.session = null; - } + + public session: Olm.Session | null = null; - static fromOTK(device, oneTimeKey) { + constructor( + public readonly device: DeviceIdentity, + public readonly oneTimeKey: string | null, + public readonly sessionId: string | null + ) {} + + static fromOTK(device: DeviceIdentity, oneTimeKey: string): EncryptionTarget { return new EncryptionTarget(device, oneTimeKey, null); } - static fromSessionId(device, sessionId) { + static fromSessionId(device: DeviceIdentity, sessionId: string): EncryptionTarget { return new EncryptionTarget(device, null, sessionId); } - dispose() { + dispose(): void { if (this.session) { this.session.free(); } @@ -285,8 +312,8 @@ class EncryptionTarget { } class EncryptedMessage { - constructor(content, device) { - this.content = content; - this.device = device; - } + constructor( + public readonly content: OlmEncryptedMessageContent, + public readonly device: DeviceIdentity + ) {} } From 347edb5988c7c133f7d1b08cb6e952251a659a0d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 18 Feb 2022 16:47:47 +0100 Subject: [PATCH 06/13] remove unused storage property --- src/matrix/Session.js | 1 - src/matrix/e2ee/olm/Decryption.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/matrix/Session.js b/src/matrix/Session.js index 8652a1d7..ac060b0b 100644 --- a/src/matrix/Session.js +++ b/src/matrix/Session.js @@ -127,7 +127,6 @@ export class Session { this._e2eeAccount, PICKLE_KEY, this._olm, - this._storage, this._platform.clock.now, this._user.id, senderKeyLock diff --git a/src/matrix/e2ee/olm/Decryption.ts b/src/matrix/e2ee/olm/Decryption.ts index 7d9be4a3..77990586 100644 --- a/src/matrix/e2ee/olm/Decryption.ts +++ b/src/matrix/e2ee/olm/Decryption.ts @@ -58,7 +58,6 @@ export class Decryption { private readonly pickleKey: string, private readonly now: () => number, private readonly ownUserId: string, - private readonly storage: Storage, private readonly olm: Olm, private readonly senderKeyLock: LockMap ) {} From 78e0bb1ff0feac3f545ad0921ac8cd57fadd3f0e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 18 Feb 2022 17:00:56 +0100 Subject: [PATCH 07/13] replace isPreKeyMessage with const enum --- src/matrix/e2ee/olm/Decryption.ts | 13 +++++-------- src/matrix/e2ee/olm/types.ts | 7 ++++++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/matrix/e2ee/olm/Decryption.ts b/src/matrix/e2ee/olm/Decryption.ts index 77990586..9698add9 100644 --- a/src/matrix/e2ee/olm/Decryption.ts +++ b/src/matrix/e2ee/olm/Decryption.ts @@ -19,6 +19,7 @@ import {groupBy} from "../../../utils/groupBy"; import {MultiLock, ILock} from "../../../utils/Lock"; import {Session} from "./Session"; import {DecryptionResult} from "../DecryptionResult"; +import {OlmPayloadType} from "./types"; import type {OlmMessage, OlmPayload} from "./types"; import type {Account} from "../Account"; @@ -42,10 +43,6 @@ type CreateAndDecryptResult = { plaintext: string }; -function isPreKeyMessage(message: OlmMessage): boolean { - return message.type === 0; -} - function sortSessions(sessions: Session[]) { sessions.sort((a, b) => { return b.data.lastUsed - a.data.lastUsed; @@ -151,7 +148,7 @@ export class Decryption { throw new DecryptionError("OLM_BAD_ENCRYPTED_MESSAGE", event, {senderKey, error: err.message}); } // could not decrypt with any existing session - if (typeof plaintext !== "string" && isPreKeyMessage(message)) { + if (typeof plaintext !== "string" && message.type === OlmPayloadType.PreKey) { let createResult: CreateAndDecryptResult; try { createResult = this._createSessionAndDecrypt(senderKey, message, timestamp); @@ -282,16 +279,16 @@ class SenderKeyDecryption { } const olmSession = session.load(); try { - if (isPreKeyMessage(message) && !olmSession.matches_inbound(message.body)) { + if (message.type === OlmPayloadType.PreKey && !olmSession.matches_inbound(message.body)) { return; } try { - const plaintext = olmSession.decrypt(message.type, message.body); + const plaintext = olmSession.decrypt(message.type as number, message.body!); session.save(olmSession); session.data.lastUsed = this.timestamp; return plaintext; } catch (err) { - if (isPreKeyMessage(message)) { + if (message.type === OlmPayloadType.PreKey) { throw new Error(`Error decrypting prekey message with existing session id ${session.id}: ${err.message}`); } // decryption failed, bail out diff --git a/src/matrix/e2ee/olm/types.ts b/src/matrix/e2ee/olm/types.ts index b9e394d5..5302dad8 100644 --- a/src/matrix/e2ee/olm/types.ts +++ b/src/matrix/e2ee/olm/types.ts @@ -14,8 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ +export const enum OlmPayloadType { + PreKey = 0, + Normal = 1 +} + export type OlmMessage = { - type?: 0 | 1, + type?: OlmPayloadType, body?: string } From 620409b3f0bace8694ebd3698cf3dd9d4dfc351e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 18 Feb 2022 17:10:26 +0100 Subject: [PATCH 08/13] fixup: ctor argument order as it was an object before, order didn't matter --- src/matrix/Session.js | 2 +- src/matrix/e2ee/olm/Encryption.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/matrix/Session.js b/src/matrix/Session.js index ac060b0b..ae1dea61 100644 --- a/src/matrix/Session.js +++ b/src/matrix/Session.js @@ -126,9 +126,9 @@ export class Session { const olmDecryption = new OlmDecryption( this._e2eeAccount, PICKLE_KEY, - this._olm, this._platform.clock.now, this._user.id, + this._olm, senderKeyLock ); this._olmEncryption = new OlmEncryption( diff --git a/src/matrix/e2ee/olm/Encryption.ts b/src/matrix/e2ee/olm/Encryption.ts index ebc38170..9b754272 100644 --- a/src/matrix/e2ee/olm/Encryption.ts +++ b/src/matrix/e2ee/olm/Encryption.ts @@ -64,12 +64,12 @@ const MAX_BATCH_SIZE = 20; export class Encryption { constructor( private readonly account: Account, + private readonly pickleKey: string, private readonly olm: Olm, - private readonly olmUtil: Olm.Utility, - private readonly ownUserId: string, private readonly storage: Storage, private readonly now: () => number, - private readonly pickleKey: string, + private readonly ownUserId: string, + private readonly olmUtil: Olm.Utility, private readonly senderKeyLock: LockMap ) {} From 3330530f68e44a2d088c9a1fe09ebed5a757b9d0 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 18 Feb 2022 17:18:25 +0100 Subject: [PATCH 09/13] Update src/matrix/e2ee/DecryptionResult.ts Co-authored-by: R Midhun Suresh --- src/matrix/e2ee/DecryptionResult.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/e2ee/DecryptionResult.ts b/src/matrix/e2ee/DecryptionResult.ts index 67c242bc..7735856a 100644 --- a/src/matrix/e2ee/DecryptionResult.ts +++ b/src/matrix/e2ee/DecryptionResult.ts @@ -43,7 +43,7 @@ export class DecryptionResult { public readonly claimedEd25519Key: string ) {} - setDevice(device: DeviceIdentity) { + setDevice(device: DeviceIdentity): void { this.device = device; } From 82299e5aeab357750ca7f27f271da5d73f6f2829 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 18 Feb 2022 17:18:33 +0100 Subject: [PATCH 10/13] Update src/matrix/e2ee/olm/Decryption.ts Co-authored-by: R Midhun Suresh --- src/matrix/e2ee/olm/Decryption.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/e2ee/olm/Decryption.ts b/src/matrix/e2ee/olm/Decryption.ts index 9698add9..e437716a 100644 --- a/src/matrix/e2ee/olm/Decryption.ts +++ b/src/matrix/e2ee/olm/Decryption.ts @@ -43,7 +43,7 @@ type CreateAndDecryptResult = { plaintext: string }; -function sortSessions(sessions: Session[]) { +function sortSessions(sessions: Session[]): void { sessions.sort((a, b) => { return b.data.lastUsed - a.data.lastUsed; }); From 3f9f0e98c7166af620dcc26297ebac0765ff6313 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 18 Feb 2022 17:21:14 +0100 Subject: [PATCH 11/13] remove unused olm property in SenderKeyDecryption --- src/matrix/e2ee/olm/Decryption.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/matrix/e2ee/olm/Decryption.ts b/src/matrix/e2ee/olm/Decryption.ts index e437716a..06ad18dc 100644 --- a/src/matrix/e2ee/olm/Decryption.ts +++ b/src/matrix/e2ee/olm/Decryption.ts @@ -122,7 +122,7 @@ export class Decryption { async _decryptAllForSenderKey(senderKey: string, events: OlmEncryptedEvent[], timestamp: number, readSessionsTxn: Transaction): Promise { const sessions = await this._getSessions(senderKey, readSessionsTxn); - const senderKeyDecryption = new SenderKeyDecryption(senderKey, sessions, this.olm, timestamp); + const senderKeyDecryption = new SenderKeyDecryption(senderKey, sessions, timestamp); const results: DecryptionResult[] = []; const errors: DecryptionError[] = []; // events for a single senderKey need to be decrypted one by one @@ -238,7 +238,6 @@ class SenderKeyDecryption { constructor( public readonly senderKey: string, public readonly sessions: Session[], - private readonly olm: Olm, private readonly timestamp: number ) {} From 8adc5a9faea2b30390944e01273c6ca0038cf133 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 18 Feb 2022 17:24:55 +0100 Subject: [PATCH 12/13] these were public actually --- src/matrix/e2ee/olm/Decryption.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/matrix/e2ee/olm/Decryption.ts b/src/matrix/e2ee/olm/Decryption.ts index 06ad18dc..9db198be 100644 --- a/src/matrix/e2ee/olm/Decryption.ts +++ b/src/matrix/e2ee/olm/Decryption.ts @@ -306,8 +306,8 @@ class SenderKeyDecryption { class DecryptionChanges { constructor( private readonly senderKeyDecryptions: SenderKeyDecryption[], - private readonly results: DecryptionResult[], - private readonly errors: DecryptionError[], + public readonly results: DecryptionResult[], + public readonly errors: DecryptionError[], private readonly account: Account, private readonly lock: ILock ) {} From b6d9993ed03e52fa052ec8c306aae7027e56ba56 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 1 Mar 2022 17:08:49 +0100 Subject: [PATCH 13/13] remove unused import --- src/matrix/e2ee/olm/Decryption.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/matrix/e2ee/olm/Decryption.ts b/src/matrix/e2ee/olm/Decryption.ts index 9db198be..0f96f2fc 100644 --- a/src/matrix/e2ee/olm/Decryption.ts +++ b/src/matrix/e2ee/olm/Decryption.ts @@ -24,7 +24,6 @@ import {OlmPayloadType} from "./types"; import type {OlmMessage, OlmPayload} from "./types"; import type {Account} from "../Account"; import type {LockMap} from "../../../utils/LockMap"; -import type {Storage} from "../../storage/idb/Storage"; import type {Transaction} from "../../storage/idb/Transaction"; import type {OlmEncryptedEvent} from "./types"; import type * as OlmNamespace from "@matrix-org/olm";