forked from mystiq/hydrogen-web
add migration when backup is enabled
This commit is contained in:
parent
60ed276b8a
commit
e80acd4d57
2 changed files with 40 additions and 14 deletions
|
@ -6,6 +6,8 @@ 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 {RoomStateEntry} from "./stores/RoomStateStore";
|
||||
import {SessionStore} from "./stores/SessionStore";
|
||||
import {Store} from "./Store";
|
||||
|
@ -39,6 +41,21 @@ export const schema: MigrationFunc[] = [
|
|||
// TypeScript note: for now, do not bother introducing interfaces / alias
|
||||
// for old schemas. Just take them as `any`.
|
||||
|
||||
function createDatabaseNameHelper(db: IDBDatabase): ITransaction {
|
||||
// the Store object gets passed in several things through the Transaction class (a wrapper around IDBTransaction),
|
||||
// the only thing we should need here is the databaseName though, so we mock it out.
|
||||
// ideally we should have an easier way to go from the idb primitive layer to the specific store classes where
|
||||
// we implement logic, but for now we need this.
|
||||
const databaseNameHelper: ITransaction = {
|
||||
databaseName: db.name,
|
||||
get idbFactory(): IDBFactory { throw new Error("unused");},
|
||||
get IDBKeyRange(): typeof IDBKeyRange { throw new Error("unused");},
|
||||
addWriteError() {},
|
||||
};
|
||||
return databaseNameHelper;
|
||||
}
|
||||
|
||||
|
||||
// how do we deal with schema updates vs existing data migration in a way that
|
||||
//v1
|
||||
function createInitialStores(db: IDBDatabase): void {
|
||||
|
@ -223,17 +240,7 @@ async function changeSSSSKeyPrefix(db: IDBDatabase, txn: IDBTransaction) {
|
|||
// v13
|
||||
async function backupAndRestoreE2EEAccountToLocalStorage(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem) {
|
||||
const session = txn.objectStore("session");
|
||||
// the Store object gets passed in several things through the Transaction class (a wrapper around IDBTransaction),
|
||||
// the only thing we should need here is the databaseName though, so we mock it out.
|
||||
// ideally we should have an easier way to go from the idb primitive layer to the specific store classes where
|
||||
// we implement logic, but for now we need this.
|
||||
const databaseNameHelper: ITransaction = {
|
||||
databaseName: db.name,
|
||||
get idbFactory(): IDBFactory { throw new Error("unused");},
|
||||
get IDBKeyRange(): typeof IDBKeyRange { throw new Error("unused");},
|
||||
addWriteError() {},
|
||||
};
|
||||
const sessionStore = new SessionStore(new Store(session, databaseNameHelper), localStorage);
|
||||
const sessionStore = new SessionStore(new Store(session, createDatabaseNameHelper(db)), localStorage);
|
||||
// if we already have an e2ee identity, write a backup to local storage.
|
||||
// further updates to e2ee keys in the session store will also write to local storage from 0.2.15 on,
|
||||
// but here we make sure a backup is immediately created after installing the update and we don't wait until
|
||||
|
@ -273,6 +280,25 @@ async function clearAllStores(db: IDBDatabase, txn: IDBTransaction) {
|
|||
}
|
||||
|
||||
// v15 adds the sessionsNeedingBackup store, for key backup
|
||||
function createSessionsNeedingBackup(db: IDBDatabase): void {
|
||||
db.createObjectStore("sessionsNeedingBackup", {keyPath: "key"});
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ type StorageEntry = {
|
|||
key: string
|
||||
};
|
||||
|
||||
function encodeKey(roomId: string, senderKey: string, sessionId: string): string {
|
||||
export function encodeKey(roomId: string, senderKey: string, sessionId: string): string {
|
||||
return `${roomId}|${senderKey}|${sessionId}`;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue