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 {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} 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";
|
||||||
|
@ -39,6 +41,21 @@ export const schema: MigrationFunc[] = [
|
||||||
// TypeScript note: for now, do not bother introducing interfaces / alias
|
// TypeScript note: for now, do not bother introducing interfaces / alias
|
||||||
// for old schemas. Just take them as `any`.
|
// 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
|
// how do we deal with schema updates vs existing data migration in a way that
|
||||||
//v1
|
//v1
|
||||||
function createInitialStores(db: IDBDatabase): void {
|
function createInitialStores(db: IDBDatabase): void {
|
||||||
|
@ -223,17 +240,7 @@ async function changeSSSSKeyPrefix(db: IDBDatabase, txn: IDBTransaction) {
|
||||||
// v13
|
// v13
|
||||||
async function backupAndRestoreE2EEAccountToLocalStorage(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem) {
|
async function backupAndRestoreE2EEAccountToLocalStorage(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem) {
|
||||||
const session = txn.objectStore("session");
|
const session = txn.objectStore("session");
|
||||||
// the Store object gets passed in several things through the Transaction class (a wrapper around IDBTransaction),
|
const sessionStore = new SessionStore(new Store(session, createDatabaseNameHelper(db)), localStorage);
|
||||||
// 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);
|
|
||||||
// if we already have an e2ee identity, write a backup to local storage.
|
// 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,
|
// 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
|
// 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
|
// v15 adds the sessionsNeedingBackup store, for key backup
|
||||||
function createSessionsNeedingBackup(db: IDBDatabase): void {
|
async function createSessionsNeedingBackup(db: IDBDatabase, txn: IDBTransaction, localStorage: IDOMStorage, log: ILogItem): Promise<void> {
|
||||||
db.createObjectStore("sessionsNeedingBackup", {keyPath: "key"});
|
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
|
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}`;
|
return `${roomId}|${senderKey}|${sessionId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue