forked from mystiq/hydrogen-web
convert SessionDecryption to TS and adapt to use KeyLoader
This commit is contained in:
parent
b55930f084
commit
ac23119838
4 changed files with 106 additions and 93 deletions
|
@ -29,10 +29,10 @@ limitations under the License.
|
|||
|
||||
|
||||
export class DecryptionResult {
|
||||
constructor(event, senderCurve25519Key, claimedKeys) {
|
||||
constructor(event, senderCurve25519Key, claimedEd25519Key) {
|
||||
this.event = event;
|
||||
this.senderCurve25519Key = senderCurve25519Key;
|
||||
this.claimedEd25519Key = claimedKeys.ed25519;
|
||||
this.claimedEd25519Key = claimedEd25519Key;
|
||||
this._device = null;
|
||||
this._roomTracked = true;
|
||||
}
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 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.
|
||||
*/
|
||||
|
||||
import {DecryptionResult} from "../../DecryptionResult.js";
|
||||
import {DecryptionError} from "../../common.js";
|
||||
import {ReplayDetectionEntry} from "./ReplayDetectionEntry.js";
|
||||
|
||||
/**
|
||||
* Does the actual decryption of all events for a given megolm session in a batch
|
||||
*/
|
||||
export class SessionDecryption {
|
||||
constructor(sessionInfo, events, olmWorker) {
|
||||
sessionInfo.retain();
|
||||
this._sessionInfo = sessionInfo;
|
||||
this._events = events;
|
||||
this._olmWorker = olmWorker;
|
||||
this._decryptionRequests = olmWorker ? [] : null;
|
||||
}
|
||||
|
||||
async decryptAll() {
|
||||
const replayEntries = [];
|
||||
const results = new Map();
|
||||
let errors;
|
||||
const roomId = this._sessionInfo.roomId;
|
||||
|
||||
await Promise.all(this._events.map(async event => {
|
||||
try {
|
||||
const {session} = this._sessionInfo;
|
||||
const ciphertext = event.content.ciphertext;
|
||||
let decryptionResult;
|
||||
if (this._olmWorker) {
|
||||
const request = this._olmWorker.megolmDecrypt(session, ciphertext);
|
||||
this._decryptionRequests.push(request);
|
||||
decryptionResult = await request.response();
|
||||
} else {
|
||||
decryptionResult = session.decrypt(ciphertext);
|
||||
}
|
||||
const plaintext = decryptionResult.plaintext;
|
||||
const messageIndex = decryptionResult.message_index;
|
||||
let payload;
|
||||
try {
|
||||
payload = JSON.parse(plaintext);
|
||||
} catch (err) {
|
||||
throw new DecryptionError("PLAINTEXT_NOT_JSON", event, {plaintext, err});
|
||||
}
|
||||
if (payload.room_id !== roomId) {
|
||||
throw new DecryptionError("MEGOLM_WRONG_ROOM", event,
|
||||
{encryptedRoomId: payload.room_id, eventRoomId: roomId});
|
||||
}
|
||||
replayEntries.push(new ReplayDetectionEntry(session.session_id(), messageIndex, event));
|
||||
const result = new DecryptionResult(payload, this._sessionInfo.senderKey, this._sessionInfo.claimedKeys);
|
||||
results.set(event.event_id, result);
|
||||
} catch (err) {
|
||||
// ignore AbortError from cancelling decryption requests in dispose method
|
||||
if (err.name === "AbortError") {
|
||||
return;
|
||||
}
|
||||
if (!errors) {
|
||||
errors = new Map();
|
||||
}
|
||||
errors.set(event.event_id, err);
|
||||
}
|
||||
}));
|
||||
|
||||
return {results, errors, replayEntries};
|
||||
}
|
||||
|
||||
dispose() {
|
||||
if (this._decryptionRequests) {
|
||||
for (const r of this._decryptionRequests) {
|
||||
r.abort();
|
||||
}
|
||||
}
|
||||
// TODO: cancel decryptions here
|
||||
this._sessionInfo.release();
|
||||
}
|
||||
}
|
103
src/matrix/e2ee/megolm/decryption/SessionDecryption.ts
Normal file
103
src/matrix/e2ee/megolm/decryption/SessionDecryption.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
Copyright 2020 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.
|
||||
*/
|
||||
|
||||
import {DecryptionResult} from "../../DecryptionResult.js";
|
||||
import {DecryptionError} from "../../common.js";
|
||||
import {ReplayDetectionEntry} from "./ReplayDetectionEntry";
|
||||
import type {IRoomKey} from "./RoomKey.js";
|
||||
import type {KeyLoader, OlmDecryptionResult} from "./KeyLoader";
|
||||
import type {OlmWorker} from "../../OlmWorker";
|
||||
import type {TimelineEvent} from "../../../storage/types";
|
||||
|
||||
interface DecryptAllResult {
|
||||
readonly results: Map<string, DecryptionResult>;
|
||||
readonly errors?: Map<string, Error>;
|
||||
readonly replayEntries: ReplayDetectionEntry[];
|
||||
}
|
||||
/**
|
||||
* Does the actual decryption of all events for a given megolm session in a batch
|
||||
*/
|
||||
export class SessionDecryption {
|
||||
private key: IRoomKey;
|
||||
private events: TimelineEvent[];
|
||||
private keyLoader: KeyLoader;
|
||||
private olmWorker?: OlmWorker;
|
||||
private decryptionRequests?: any[];
|
||||
|
||||
constructor(key: IRoomKey, events: TimelineEvent[], olmWorker: OlmWorker | undefined, keyLoader: KeyLoader) {
|
||||
this.key = key;
|
||||
this.events = events;
|
||||
this.olmWorker = olmWorker;
|
||||
this.keyLoader = keyLoader;
|
||||
this.decryptionRequests = olmWorker ? [] : undefined;
|
||||
}
|
||||
|
||||
async decryptAll(): Promise<DecryptAllResult> {
|
||||
const replayEntries: ReplayDetectionEntry[] = [];
|
||||
const results: Map<string, DecryptionResult> = new Map();
|
||||
let errors: Map<string, Error> | undefined;
|
||||
|
||||
await this.keyLoader.useKey(this.key, async session => {
|
||||
for (const event of this.events) {
|
||||
try {
|
||||
const ciphertext = event.content.ciphertext as string;
|
||||
let decryptionResult: OlmDecryptionResult | undefined;
|
||||
// TODO: pass all cipthertexts in one go to the megolm worker and don't deserialize the key until in the worker?
|
||||
if (this.olmWorker) {
|
||||
const request = this.olmWorker.megolmDecrypt(session, ciphertext);
|
||||
this.decryptionRequests!.push(request);
|
||||
decryptionResult = await request.response();
|
||||
} else {
|
||||
decryptionResult = session.decrypt(ciphertext);
|
||||
}
|
||||
const {plaintext} = decryptionResult!;
|
||||
let payload;
|
||||
try {
|
||||
payload = JSON.parse(plaintext);
|
||||
} catch (err) {
|
||||
throw new DecryptionError("PLAINTEXT_NOT_JSON", event, {plaintext, err});
|
||||
}
|
||||
if (payload.room_id !== this.key.roomId) {
|
||||
throw new DecryptionError("MEGOLM_WRONG_ROOM", event,
|
||||
{encryptedRoomId: payload.room_id, eventRoomId: this.key.roomId});
|
||||
}
|
||||
replayEntries.push(new ReplayDetectionEntry(this.key.sessionId, decryptionResult!.message_index, event));
|
||||
const result = new DecryptionResult(payload, this.key.senderKey, this.key.claimedEd25519Key);
|
||||
results.set(event.event_id, result);
|
||||
} catch (err) {
|
||||
// ignore AbortError from cancelling decryption requests in dispose method
|
||||
if (err.name === "AbortError") {
|
||||
return;
|
||||
}
|
||||
if (!errors) {
|
||||
errors = new Map();
|
||||
}
|
||||
errors.set(event.event_id, err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {results, errors, replayEntries};
|
||||
}
|
||||
|
||||
dispose() {
|
||||
if (this.decryptionRequests) {
|
||||
for (const r of this.decryptionRequests) {
|
||||
r.abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -150,7 +150,7 @@ export class Decryption {
|
|||
throw new DecryptionError("PLAINTEXT_NOT_JSON", event, {plaintext, error});
|
||||
}
|
||||
this._validatePayload(payload, event);
|
||||
return new DecryptionResult(payload, senderKey, payload.keys);
|
||||
return new DecryptionResult(payload, senderKey, payload.keys.ed25519);
|
||||
} else {
|
||||
throw new DecryptionError("OLM_NO_MATCHING_SESSION", event,
|
||||
{knownSessionIds: senderKeyDecryption.sessions.map(s => s.id)});
|
||||
|
|
Loading…
Reference in a new issue