2020-09-02 13:33:27 +02:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2021-03-01 15:04:45 +01:00
|
|
|
import {OLM_ALGORITHM} from "./e2ee/common.js";
|
|
|
|
import {countBy, groupBy} from "../utils/groupBy.js";
|
2020-09-02 13:33:27 +02:00
|
|
|
|
|
|
|
export class DeviceMessageHandler {
|
2020-09-02 14:24:38 +02:00
|
|
|
constructor({storage}) {
|
2020-09-02 13:33:27 +02:00
|
|
|
this._storage = storage;
|
2020-09-02 14:24:38 +02:00
|
|
|
this._olmDecryption = null;
|
|
|
|
this._megolmDecryption = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
enableEncryption({olmDecryption, megolmDecryption}) {
|
2020-09-02 13:33:27 +02:00
|
|
|
this._olmDecryption = olmDecryption;
|
2020-09-02 14:24:38 +02:00
|
|
|
this._megolmDecryption = megolmDecryption;
|
2020-09-02 13:33:27 +02:00
|
|
|
}
|
|
|
|
|
2021-03-01 15:04:45 +01:00
|
|
|
obtainSyncLock(toDeviceEvents) {
|
|
|
|
return this._olmDecryption?.obtainDecryptionLock(toDeviceEvents);
|
2020-09-02 13:33:27 +02:00
|
|
|
}
|
|
|
|
|
2021-03-01 15:04:45 +01:00
|
|
|
async prepareSync(toDeviceEvents, lock, txn, log) {
|
|
|
|
log.set("messageTypes", countBy(toDeviceEvents, e => e.type));
|
|
|
|
const encryptedEvents = toDeviceEvents.filter(e => e.type === "m.room.encrypted");
|
2020-09-02 14:24:38 +02:00
|
|
|
if (!this._olmDecryption) {
|
2021-03-01 15:04:45 +01:00
|
|
|
log.log("can't decrypt, encryption not enabled", log.level.Warn);
|
2020-09-02 14:24:38 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-09-02 13:33:27 +02:00
|
|
|
// only know olm for now
|
2021-03-01 15:04:45 +01:00
|
|
|
const olmEvents = encryptedEvents.filter(e => e.content?.algorithm === OLM_ALGORITHM);
|
|
|
|
if (olmEvents.length) {
|
|
|
|
const olmDecryptChanges = await this._olmDecryption.decryptAll(olmEvents, lock, txn);
|
|
|
|
log.set("decryptedTypes", countBy(olmDecryptChanges.results, r => r.event?.type));
|
|
|
|
for (const err of olmDecryptChanges.errors) {
|
|
|
|
log.child("decrypt_error").catch(err);
|
|
|
|
}
|
|
|
|
const newRoomKeys = this._megolmDecryption.roomKeysFromDeviceMessages(olmDecryptChanges.results, log);
|
|
|
|
return new SyncPreparation(olmDecryptChanges, newRoomKeys);
|
2020-09-02 13:33:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-01 15:04:45 +01:00
|
|
|
/** check that prep is not undefined before calling this */
|
|
|
|
async writeSync(prep, txn) {
|
|
|
|
// write olm changes
|
|
|
|
prep.olmDecryptChanges.write(txn);
|
|
|
|
await Promise.all(prep.newRoomKeys.map(key => this._megolmDecryption.writeRoomKey(key, txn)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class SyncPreparation {
|
|
|
|
constructor(olmDecryptChanges, newRoomKeys) {
|
|
|
|
this.olmDecryptChanges = olmDecryptChanges;
|
|
|
|
this.newRoomKeys = newRoomKeys;
|
|
|
|
this.newKeysByRoom = groupBy(newRoomKeys, r => r.roomId);
|
|
|
|
}
|
|
|
|
|
|
|
|
dispose() {
|
|
|
|
if (this.newRoomKeys) {
|
|
|
|
for (const k of this.newRoomKeys) {
|
|
|
|
k.dispose();
|
|
|
|
}
|
|
|
|
}
|
2020-09-02 13:33:27 +02:00
|
|
|
}
|
|
|
|
}
|