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",
|
||||
operations = "operations",
|
||||
accountData = "accountData",
|
||||
sessionsNeedingBackup = "sessionsNeedingBackup",
|
||||
}
|
||||
|
||||
export const STORE_NAMES: Readonly<StoreNames[]> = Object.values(StoreNames);
|
||||
|
|
|
@ -36,7 +36,6 @@ import {OutboundGroupSessionStore} from "./stores/OutboundGroupSessionStore";
|
|||
import {GroupSessionDecryptionStore} from "./stores/GroupSessionDecryptionStore";
|
||||
import {OperationStore} from "./stores/OperationStore";
|
||||
import {AccountDataStore} from "./stores/AccountDataStore";
|
||||
import {SessionNeedingBackupStore} from "./stores/SessionNeedingBackupStore";
|
||||
import type {ILogger, ILogItem} from "../../../logging/types";
|
||||
|
||||
export type IDBKey = IDBValidKey | IDBKeyRange;
|
||||
|
@ -153,10 +152,6 @@ export class Transaction {
|
|||
return this._store(StoreNames.inboundGroupSessions, idbStore => new InboundGroupSessionStore(idbStore));
|
||||
}
|
||||
|
||||
get sessionsNeedingBackup(): SessionNeedingBackupStore {
|
||||
return this._store(StoreNames.sessionsNeedingBackup, idbStore => new SessionNeedingBackupStore(idbStore));
|
||||
}
|
||||
|
||||
get outboundGroupSessions(): OutboundGroupSessionStore {
|
||||
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 {SummaryData} from "../../room/RoomSummary";
|
||||
import {RoomMemberStore, MemberData} from "./stores/RoomMemberStore";
|
||||
import {encodeKey as encodeBackupKey} from "./stores/SessionNeedingBackupStore";
|
||||
import {InboundGroupSessionStore, InboundGroupSessionEntry} from "./stores/InboundGroupSessionStore";
|
||||
import {InboundGroupSessionStore, InboundGroupSessionEntry, BackupStatus} from "./stores/InboundGroupSessionStore";
|
||||
import {RoomStateEntry} from "./stores/RoomStateStore";
|
||||
import {SessionStore} from "./stores/SessionStore";
|
||||
import {Store} from "./Store";
|
||||
|
@ -34,7 +33,7 @@ export const schema: MigrationFunc[] = [
|
|||
changeSSSSKeyPrefix,
|
||||
backupAndRestoreE2EEAccountToLocalStorage,
|
||||
clearAllStores,
|
||||
createSessionsNeedingBackup
|
||||
addInboundSessionBackupIndex
|
||||
];
|
||||
// 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
|
||||
async function createSessionsNeedingBackup(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem): Promise<void> {
|
||||
const backupStore = db.createObjectStore("sessionsNeedingBackup", {keyPath: "key"});
|
||||
const session = txn.objectStore("session");
|
||||
const ssssKey = await reqAsPromise(session.get(`${SESSION_E2EE_KEY_PREFIX}ssssKey`) as IDBRequest<string>);
|
||||
const keyBackupEnabled = !!ssssKey;
|
||||
log.set("key backup", keyBackupEnabled);
|
||||
if (keyBackupEnabled) {
|
||||
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);
|
||||
}
|
||||
// v15 add backup index to inboundGroupSessions
|
||||
async function addInboundSessionBackupIndex(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem): Promise<void> {
|
||||
const inboundGroupSessions = txn.objectStore("inboundGroupSessions");
|
||||
await iterateCursor<InboundGroupSessionEntry>(inboundGroupSessions.openCursor(), (value, key, cursor) => {
|
||||
value.backup = BackupStatus.NotBackedUp;
|
||||
return NOT_DONE;
|
||||
});
|
||||
inboundGroupSessions.createIndex("byBackup", "backup", {unique: false});
|
||||
}
|
||||
|
|
|
@ -17,6 +17,11 @@ limitations under the License.
|
|||
import {MIN_UNICODE, MAX_UNICODE} from "./common";
|
||||
import {Store} from "../Store";
|
||||
|
||||
export enum BackupStatus {
|
||||
NotBackedUp = 0,
|
||||
BackedUp = 1
|
||||
}
|
||||
|
||||
export interface InboundGroupSessionEntry {
|
||||
roomId: string;
|
||||
senderKey: string;
|
||||
|
@ -24,6 +29,7 @@ export interface InboundGroupSessionEntry {
|
|||
session?: string;
|
||||
claimedKeys?: { [algorithm : string] : string };
|
||||
eventIds?: string[];
|
||||
backup: BackupStatus
|
||||
}
|
||||
|
||||
type InboundGroupSessionStorageEntry = InboundGroupSessionEntry & { key: string };
|
||||
|
@ -63,4 +69,19 @@ export class InboundGroupSessionStore {
|
|||
);
|
||||
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