mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-23 11:35:04 +01:00
move key backup operation and flush bookkeeping inside KeyBackup
so we can flush from other places than Session
This commit is contained in:
parent
ebc7f1ecd7
commit
b692b3ec4f
@ -76,7 +76,6 @@ export class Session {
|
|||||||
this._getSyncToken = () => this.syncToken;
|
this._getSyncToken = () => this.syncToken;
|
||||||
this._olmWorker = olmWorker;
|
this._olmWorker = olmWorker;
|
||||||
this._keyBackup = null;
|
this._keyBackup = null;
|
||||||
this._keyBackupOperation = new ObservableValue(null);
|
|
||||||
this._hasSecretStorageKey = new ObservableValue(null);
|
this._hasSecretStorageKey = new ObservableValue(null);
|
||||||
this._observedRoomStatus = new Map();
|
this._observedRoomStatus = new Map();
|
||||||
|
|
||||||
@ -135,15 +134,16 @@ export class Session {
|
|||||||
olmUtil: this._olmUtil,
|
olmUtil: this._olmUtil,
|
||||||
senderKeyLock
|
senderKeyLock
|
||||||
});
|
});
|
||||||
|
this._keyLoader = new MegOlmKeyLoader(this._olm, PICKLE_KEY, 20);
|
||||||
this._megolmEncryption = new MegOlmEncryption({
|
this._megolmEncryption = new MegOlmEncryption({
|
||||||
account: this._e2eeAccount,
|
account: this._e2eeAccount,
|
||||||
pickleKey: PICKLE_KEY,
|
pickleKey: PICKLE_KEY,
|
||||||
olm: this._olm,
|
olm: this._olm,
|
||||||
storage: this._storage,
|
storage: this._storage,
|
||||||
|
keyLoader: this._keyLoader,
|
||||||
now: this._platform.clock.now,
|
now: this._platform.clock.now,
|
||||||
ownDeviceId: this._sessionInfo.deviceId,
|
ownDeviceId: this._sessionInfo.deviceId,
|
||||||
});
|
});
|
||||||
this._keyLoader = new MegOlmKeyLoader(this._olm, PICKLE_KEY, 20);
|
|
||||||
this._megolmDecryption = new MegOlmDecryption(this._keyLoader, this._olmWorker);
|
this._megolmDecryption = new MegOlmDecryption(this._keyLoader, this._olmWorker);
|
||||||
this._deviceMessageHandler.enableEncryption({olmDecryption, megolmDecryption: this._megolmDecryption});
|
this._deviceMessageHandler.enableEncryption({olmDecryption, megolmDecryption: this._megolmDecryption});
|
||||||
}
|
}
|
||||||
@ -282,10 +282,6 @@ export class Session {
|
|||||||
return this._keyBackup;
|
return this._keyBackup;
|
||||||
}
|
}
|
||||||
|
|
||||||
get keyBackupOperation() {
|
|
||||||
return this._keyBackupOperation;
|
|
||||||
}
|
|
||||||
|
|
||||||
get hasIdentity() {
|
get hasIdentity() {
|
||||||
return !!this._e2eeAccount;
|
return !!this._e2eeAccount;
|
||||||
}
|
}
|
||||||
@ -635,23 +631,8 @@ export class Session {
|
|||||||
await log.wrap("uploadKeys", log => this._e2eeAccount.uploadKeys(this._storage, false, log));
|
await log.wrap("uploadKeys", log => this._e2eeAccount.uploadKeys(this._storage, false, log));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// should flush and not already flushing
|
if (changes.hasNewRoomKeys) {
|
||||||
if (changes.hasNewRoomKeys && this._keyBackup && !this._keyBackupOperation.get()) {
|
this._keyBackup?.flush(log);
|
||||||
log.wrapDetached("flush key backup", async log => {
|
|
||||||
const operation = this._keyBackup.flush(log);
|
|
||||||
this._keyBackupOperation.set(operation);
|
|
||||||
try {
|
|
||||||
const success = await operation.result;
|
|
||||||
// stop key backup if the version was changed
|
|
||||||
if (!success) {
|
|
||||||
this._keyBackup = this._keyBackup.dispose();
|
|
||||||
this.needsKeyBackup.set(true);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
log.catch(err);
|
|
||||||
}
|
|
||||||
this._keyBackupOperation.set(null);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import {StoredRoomKey, keyFromBackup} from "../decryption/RoomKey";
|
|||||||
import {MEGOLM_ALGORITHM} from "../../common";
|
import {MEGOLM_ALGORITHM} from "../../common";
|
||||||
import * as Curve25519 from "./Curve25519";
|
import * as Curve25519 from "./Curve25519";
|
||||||
import {AbortableOperation} from "../../../../utils/AbortableOperation";
|
import {AbortableOperation} from "../../../../utils/AbortableOperation";
|
||||||
|
import {ObservableValue} from "../../../../observable/ObservableValue";
|
||||||
|
|
||||||
import {SetAbortableFn} from "../../../../utils/AbortableOperation";
|
import {SetAbortableFn} from "../../../../utils/AbortableOperation";
|
||||||
import type {BackupInfo, SessionData, SessionKeyInfo, SessionInfo, KeyBackupPayload} from "./types";
|
import type {BackupInfo, SessionData, SessionKeyInfo, SessionInfo, KeyBackupPayload} from "./types";
|
||||||
@ -33,7 +34,12 @@ import type {Transaction} from "../../../storage/idb/Transaction";
|
|||||||
import type * as OlmNamespace from "@matrix-org/olm";
|
import type * as OlmNamespace from "@matrix-org/olm";
|
||||||
type Olm = typeof OlmNamespace;
|
type Olm = typeof OlmNamespace;
|
||||||
|
|
||||||
|
const KEYS_PER_REQUEST = 20;
|
||||||
|
|
||||||
export class KeyBackup {
|
export class KeyBackup {
|
||||||
|
public readonly operationInProgress = new ObservableValue<AbortableOperation<Promise<boolean>, Progress> | undefined>(undefined);
|
||||||
|
public readonly needsNewKey = new ObservableValue(false);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly backupInfo: BackupInfo,
|
private readonly backupInfo: BackupInfo,
|
||||||
private readonly crypto: Curve25519.BackupEncryption,
|
private readonly crypto: Curve25519.BackupEncryption,
|
||||||
@ -56,13 +62,32 @@ export class KeyBackup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: protect against having multiple concurrent flushes
|
flush(log: ILogItem): void {
|
||||||
flush(log: ILogItem): AbortableOperation<Promise<boolean>, Progress> {
|
if (!this.operationInProgress.get()) {
|
||||||
|
log.wrapDetached("flush key backup", async log => {
|
||||||
|
const operation = this._flush(log);
|
||||||
|
this.operationInProgress.set(operation);
|
||||||
|
try {
|
||||||
|
const success = await operation.result;
|
||||||
|
// stop key backup if the version was changed
|
||||||
|
if (!success) {
|
||||||
|
this.needsNewKey.set(true);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
log.catch(err);
|
||||||
|
}
|
||||||
|
this.operationInProgress.set(undefined);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _flush(log: ILogItem): AbortableOperation<Promise<boolean>, Progress> {
|
||||||
return new AbortableOperation(async (setAbortable, setProgress) => {
|
return new AbortableOperation(async (setAbortable, setProgress) => {
|
||||||
let total = 0;
|
let total = 0;
|
||||||
let amountFinished = 0;
|
let amountFinished = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
const timeout = this.platform.clock.createTimeout(this.platform.random() * 10000);
|
const waitMs = this.platform.random() * 10000;
|
||||||
|
const timeout = this.platform.clock.createTimeout(waitMs);
|
||||||
setAbortable(timeout);
|
setAbortable(timeout);
|
||||||
await timeout.elapsed();
|
await timeout.elapsed();
|
||||||
const txn = await this.storage.readTxn([StoreNames.inboundGroupSessions]);
|
const txn = await this.storage.readTxn([StoreNames.inboundGroupSessions]);
|
||||||
@ -70,7 +95,7 @@ export class KeyBackup {
|
|||||||
// fetch total again on each iteration as while we are flushing, sync might be adding keys
|
// fetch total again on each iteration as while we are flushing, sync might be adding keys
|
||||||
total = await txn.inboundGroupSessions.countNonBackedUpSessions();
|
total = await txn.inboundGroupSessions.countNonBackedUpSessions();
|
||||||
setProgress(new Progress(total, amountFinished));
|
setProgress(new Progress(total, amountFinished));
|
||||||
const keysNeedingBackup = (await txn.inboundGroupSessions.getFirstNonBackedUpSessions(20))
|
const keysNeedingBackup = (await txn.inboundGroupSessions.getFirstNonBackedUpSessions(KEYS_PER_REQUEST))
|
||||||
.map(entry => new StoredRoomKey(entry));
|
.map(entry => new StoredRoomKey(entry));
|
||||||
if (keysNeedingBackup.length === 0) {
|
if (keysNeedingBackup.length === 0) {
|
||||||
return true;
|
return true;
|
||||||
@ -114,7 +139,9 @@ export class KeyBackup {
|
|||||||
]);
|
]);
|
||||||
setAbortable(txn);
|
setAbortable(txn);
|
||||||
try {
|
try {
|
||||||
await Promise.all(roomKeys.map(key => txn.inboundGroupSessions.markAsBackedUp(key.roomId, key.senderKey, key.sessionId)));
|
await Promise.all(roomKeys.map(key => {
|
||||||
|
return txn.inboundGroupSessions.markAsBackedUp(key.roomId, key.senderKey, key.sessionId);
|
||||||
|
}));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
txn.abort();
|
txn.abort();
|
||||||
throw err;
|
throw err;
|
||||||
|
Loading…
Reference in New Issue
Block a user