forked from mystiq/hydrogen-web
replace SessionsNeedingBackup store with backup field on inbound session
This commit is contained in:
parent
6f1484005b
commit
48e72f9b69
5 changed files with 31 additions and 91 deletions
|
@ -33,7 +33,6 @@ export enum StoreNames {
|
||||||
groupSessionDecryptions = "groupSessionDecryptions",
|
groupSessionDecryptions = "groupSessionDecryptions",
|
||||||
operations = "operations",
|
operations = "operations",
|
||||||
accountData = "accountData",
|
accountData = "accountData",
|
||||||
sessionsNeedingBackup = "sessionsNeedingBackup",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const STORE_NAMES: Readonly<StoreNames[]> = Object.values(StoreNames);
|
export const STORE_NAMES: Readonly<StoreNames[]> = Object.values(StoreNames);
|
||||||
|
|
|
@ -36,7 +36,6 @@ import {OutboundGroupSessionStore} from "./stores/OutboundGroupSessionStore";
|
||||||
import {GroupSessionDecryptionStore} from "./stores/GroupSessionDecryptionStore";
|
import {GroupSessionDecryptionStore} from "./stores/GroupSessionDecryptionStore";
|
||||||
import {OperationStore} from "./stores/OperationStore";
|
import {OperationStore} from "./stores/OperationStore";
|
||||||
import {AccountDataStore} from "./stores/AccountDataStore";
|
import {AccountDataStore} from "./stores/AccountDataStore";
|
||||||
import {SessionNeedingBackupStore} from "./stores/SessionNeedingBackupStore";
|
|
||||||
import type {ILogger, ILogItem} from "../../../logging/types";
|
import type {ILogger, ILogItem} from "../../../logging/types";
|
||||||
|
|
||||||
export type IDBKey = IDBValidKey | IDBKeyRange;
|
export type IDBKey = IDBValidKey | IDBKeyRange;
|
||||||
|
@ -152,10 +151,6 @@ export class Transaction {
|
||||||
get inboundGroupSessions(): InboundGroupSessionStore {
|
get inboundGroupSessions(): InboundGroupSessionStore {
|
||||||
return this._store(StoreNames.inboundGroupSessions, idbStore => new InboundGroupSessionStore(idbStore));
|
return this._store(StoreNames.inboundGroupSessions, idbStore => new InboundGroupSessionStore(idbStore));
|
||||||
}
|
}
|
||||||
|
|
||||||
get sessionsNeedingBackup(): SessionNeedingBackupStore {
|
|
||||||
return this._store(StoreNames.sessionsNeedingBackup, idbStore => new SessionNeedingBackupStore(idbStore));
|
|
||||||
}
|
|
||||||
|
|
||||||
get outboundGroupSessions(): OutboundGroupSessionStore {
|
get outboundGroupSessions(): OutboundGroupSessionStore {
|
||||||
return this._store(StoreNames.outboundGroupSessions, idbStore => new OutboundGroupSessionStore(idbStore));
|
return this._store(StoreNames.outboundGroupSessions, idbStore => new OutboundGroupSessionStore(idbStore));
|
||||||
|
|
|
@ -6,8 +6,7 @@ import {addRoomToIdentity} from "../../e2ee/DeviceTracker.js";
|
||||||
import {SESSION_E2EE_KEY_PREFIX} from "../../e2ee/common.js";
|
import {SESSION_E2EE_KEY_PREFIX} from "../../e2ee/common.js";
|
||||||
import {SummaryData} from "../../room/RoomSummary";
|
import {SummaryData} from "../../room/RoomSummary";
|
||||||
import {RoomMemberStore, MemberData} from "./stores/RoomMemberStore";
|
import {RoomMemberStore, MemberData} from "./stores/RoomMemberStore";
|
||||||
import {encodeKey as encodeBackupKey} from "./stores/SessionNeedingBackupStore";
|
import {InboundGroupSessionStore, InboundGroupSessionEntry, BackupStatus} from "./stores/InboundGroupSessionStore";
|
||||||
import {InboundGroupSessionStore, InboundGroupSessionEntry} from "./stores/InboundGroupSessionStore";
|
|
||||||
import {RoomStateEntry} from "./stores/RoomStateStore";
|
import {RoomStateEntry} from "./stores/RoomStateStore";
|
||||||
import {SessionStore} from "./stores/SessionStore";
|
import {SessionStore} from "./stores/SessionStore";
|
||||||
import {Store} from "./Store";
|
import {Store} from "./Store";
|
||||||
|
@ -34,7 +33,7 @@ export const schema: MigrationFunc[] = [
|
||||||
changeSSSSKeyPrefix,
|
changeSSSSKeyPrefix,
|
||||||
backupAndRestoreE2EEAccountToLocalStorage,
|
backupAndRestoreE2EEAccountToLocalStorage,
|
||||||
clearAllStores,
|
clearAllStores,
|
||||||
createSessionsNeedingBackup
|
addInboundSessionBackupIndex
|
||||||
];
|
];
|
||||||
// TODO: how to deal with git merge conflicts of this array?
|
// TODO: how to deal with git merge conflicts of this array?
|
||||||
|
|
||||||
|
@ -279,26 +278,12 @@ async function clearAllStores(db: IDBDatabase, txn: IDBTransaction) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// v15 adds the sessionsNeedingBackup store, for key backup
|
// v15 add backup index to inboundGroupSessions
|
||||||
async function createSessionsNeedingBackup(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem): Promise<void> {
|
async function addInboundSessionBackupIndex(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem): Promise<void> {
|
||||||
const backupStore = db.createObjectStore("sessionsNeedingBackup", {keyPath: "key"});
|
const inboundGroupSessions = txn.objectStore("inboundGroupSessions");
|
||||||
const session = txn.objectStore("session");
|
await iterateCursor<InboundGroupSessionEntry>(inboundGroupSessions.openCursor(), (value, key, cursor) => {
|
||||||
const ssssKey = await reqAsPromise(session.get(`${SESSION_E2EE_KEY_PREFIX}ssssKey`) as IDBRequest<string>);
|
value.backup = BackupStatus.NotBackedUp;
|
||||||
const keyBackupEnabled = !!ssssKey;
|
return NOT_DONE;
|
||||||
log.set("key backup", keyBackupEnabled);
|
});
|
||||||
if (keyBackupEnabled) {
|
inboundGroupSessions.createIndex("byBackup", "backup", {unique: false});
|
||||||
let count = 0;
|
|
||||||
try {
|
|
||||||
const inboundGroupSessions = txn.objectStore("inboundGroupSessions");
|
|
||||||
await iterateCursor<InboundGroupSessionEntry>(inboundGroupSessions.openCursor(), session => {
|
|
||||||
backupStore.add({key: encodeBackupKey(session.roomId, session.senderKey, session.sessionId)});
|
|
||||||
count += 1;
|
|
||||||
return NOT_DONE;
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
txn.abort();
|
|
||||||
log.log("could not migrate operations").catch(err);
|
|
||||||
}
|
|
||||||
log.set("count", count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,11 @@ limitations under the License.
|
||||||
import {MIN_UNICODE, MAX_UNICODE} from "./common";
|
import {MIN_UNICODE, MAX_UNICODE} from "./common";
|
||||||
import {Store} from "../Store";
|
import {Store} from "../Store";
|
||||||
|
|
||||||
|
export enum BackupStatus {
|
||||||
|
NotBackedUp = 0,
|
||||||
|
BackedUp = 1
|
||||||
|
}
|
||||||
|
|
||||||
export interface InboundGroupSessionEntry {
|
export interface InboundGroupSessionEntry {
|
||||||
roomId: string;
|
roomId: string;
|
||||||
senderKey: string;
|
senderKey: string;
|
||||||
|
@ -24,6 +29,7 @@ export interface InboundGroupSessionEntry {
|
||||||
session?: string;
|
session?: string;
|
||||||
claimedKeys?: { [algorithm : string] : string };
|
claimedKeys?: { [algorithm : string] : string };
|
||||||
eventIds?: string[];
|
eventIds?: string[];
|
||||||
|
backup: BackupStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
type InboundGroupSessionStorageEntry = InboundGroupSessionEntry & { key: string };
|
type InboundGroupSessionStorageEntry = InboundGroupSessionEntry & { key: string };
|
||||||
|
@ -63,4 +69,19 @@ export class InboundGroupSessionStore {
|
||||||
);
|
);
|
||||||
this._store.delete(range);
|
this._store.delete(range);
|
||||||
}
|
}
|
||||||
|
countNonBackedUpSessions(): Promise<number> {
|
||||||
|
return this._store.index("byBackup").count();
|
||||||
|
}
|
||||||
|
|
||||||
|
getFirstNonBackedUpSessions(amount: number): Promise<InboundGroupSessionEntry[]> {
|
||||||
|
return this._store.index("byBackup").selectLimit(0, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
async markAsBackedUp(roomId: string, senderKey: string, sessionId: string): Promise<void> {
|
||||||
|
const entry = await this._store.get(encodeKey(roomId, senderKey, sessionId));
|
||||||
|
if (entry) {
|
||||||
|
entry.backup = BackupStatus.BackedUp;
|
||||||
|
this._store.put(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,60 +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 type {Store} from "../Store";
|
|
||||||
|
|
||||||
export type BackupEntry = {
|
|
||||||
roomId: string;
|
|
||||||
senderKey: string;
|
|
||||||
sessionId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type StorageEntry = {
|
|
||||||
key: string
|
|
||||||
};
|
|
||||||
|
|
||||||
export function encodeKey(roomId: string, senderKey: string, sessionId: string): string {
|
|
||||||
return `${roomId}|${senderKey}|${sessionId}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function decodeKey(key: string): BackupEntry {
|
|
||||||
const [roomId, senderKey, sessionId] = key.split("|");
|
|
||||||
return {roomId, senderKey, sessionId};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SessionNeedingBackupStore {
|
|
||||||
constructor(private store: Store<StorageEntry>) {}
|
|
||||||
|
|
||||||
async getFirstEntries(amount: number): Promise<BackupEntry[]> {
|
|
||||||
const storageEntries = await this.store.selectLimit(undefined, amount);
|
|
||||||
return storageEntries.map(s => decodeKey(s.key));
|
|
||||||
}
|
|
||||||
|
|
||||||
set(roomId: string, senderKey: string, sessionId: string): void {
|
|
||||||
const storageEntry : StorageEntry = {
|
|
||||||
key: encodeKey(roomId, senderKey, sessionId),
|
|
||||||
};
|
|
||||||
this.store.put(storageEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(roomId: string, senderKey: string, sessionId: string): void {
|
|
||||||
this.store.delete(encodeKey(roomId, senderKey, sessionId));
|
|
||||||
}
|
|
||||||
|
|
||||||
count(): Promise<number> {
|
|
||||||
return this.store.count();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue