mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2025-01-19 16:51:40 +01:00
WIP for enabling session backup from dehydration key
This commit is contained in:
parent
6d9d8797fe
commit
567cdd5510
@ -40,7 +40,8 @@ import {
|
||||
keyFromCredential as ssssKeyFromCredential,
|
||||
readKey as ssssReadKey,
|
||||
writeKey as ssssWriteKey,
|
||||
removeKey as ssssRemoveKey
|
||||
removeKey as ssssRemoveKey,
|
||||
keyFromDehydratedDeviceKey as createSSSSKeyFromDehydratedDeviceKey
|
||||
} from "./ssss/index.js";
|
||||
import {SecretStorage} from "./ssss/SecretStorage.js";
|
||||
import {ObservableValue, RetainedObservableValue} from "../observable/ObservableValue";
|
||||
@ -205,6 +206,12 @@ export class Session {
|
||||
this._storage.storeNames.accountData,
|
||||
]);
|
||||
await this._createSessionBackup(key, readTxn);
|
||||
this._writeSSSSKey(key);
|
||||
this._hasSecretStorageKey.set(true);
|
||||
return key;
|
||||
}
|
||||
|
||||
async _writeSSSSKey(key) {
|
||||
// only after having read a secret, write the key
|
||||
// as we only find out if it was good if the MAC verification succeeds
|
||||
const writeTxn = await this._storage.readWriteTxn([
|
||||
@ -217,8 +224,6 @@ export class Session {
|
||||
throw err;
|
||||
}
|
||||
await writeTxn.complete();
|
||||
this._hasSecretStorageKey.set(true);
|
||||
return key;
|
||||
}
|
||||
|
||||
async disableSecretStorage() {
|
||||
@ -419,7 +424,7 @@ export class Session {
|
||||
* and useful to store so we can later tell what capabilities
|
||||
* our homeserver has.
|
||||
*/
|
||||
async start(lastVersionResponse, log) {
|
||||
async start(lastVersionResponse, dehydratedDevice, log) {
|
||||
if (lastVersionResponse) {
|
||||
// store /versions response
|
||||
const txn = await this._storage.readWriteTxn([
|
||||
@ -431,6 +436,12 @@ export class Session {
|
||||
}
|
||||
// enable session backup, this requests the latest backup version
|
||||
if (!this._sessionBackup) {
|
||||
if (dehydratedDevice) {
|
||||
const ssssKey = await createSSSSKeyFromDehydratedDeviceKey(dehydratedDevice.key, this._storage);
|
||||
if (ssssKey) {
|
||||
this._writeSSSSKey(ssssKey);
|
||||
}
|
||||
}
|
||||
const txn = await this._storage.readTxn([
|
||||
this._storage.storeNames.session,
|
||||
this._storage.storeNames.accountData,
|
||||
|
@ -259,7 +259,9 @@ export class SessionContainer {
|
||||
this._requestScheduler.start();
|
||||
this._sync.start();
|
||||
this._sessionStartedByReconnector = true;
|
||||
await log.wrap("session start", log => this._session.start(this._reconnector.lastVersionsResponse, log));
|
||||
const d = dehydratedDevice;
|
||||
dehydratedDevice = undefined;
|
||||
await log.wrap("session start", log => this._session.start(this._reconnector.lastVersionsResponse, d, log));
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -278,8 +280,10 @@ export class SessionContainer {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
const d = dehydratedDevice;
|
||||
dehydratedDevice = undefined;
|
||||
// log as ref as we don't want to await it
|
||||
await log.wrap("session start", log => this._session.start(lastVersionsResponse, log));
|
||||
await log.wrap("session start", log => this._session.start(lastVersionsResponse, d, log));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ class EncryptedDehydratedDevice {
|
||||
try {
|
||||
const pickledAccount = this._dehydratedDevice.device_data.account;
|
||||
account.unpickle(key.binaryKey, pickledAccount);
|
||||
return new DehydratedDevice(this._dehydratedDevice, account, keyType, key);
|
||||
return new DehydratedDevice(this._dehydratedDevice, account, key);
|
||||
} catch (err) {
|
||||
account.free();
|
||||
if (err.message === "OLM.BAD_ACCOUNT_KEY") {
|
||||
@ -78,10 +78,9 @@ class EncryptedDehydratedDevice {
|
||||
}
|
||||
|
||||
class DehydratedDevice {
|
||||
constructor(dehydratedDevice, account, keyType, key) {
|
||||
constructor(dehydratedDevice, account, key) {
|
||||
this._dehydratedDevice = dehydratedDevice;
|
||||
this._account = account;
|
||||
this._keyType = keyType;
|
||||
this._key = key;
|
||||
}
|
||||
|
||||
@ -109,10 +108,6 @@ class DehydratedDevice {
|
||||
return this._key;
|
||||
}
|
||||
|
||||
get keyType() {
|
||||
return this._keyType;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._account?.free();
|
||||
this._account = undefined;
|
||||
|
@ -31,6 +31,28 @@ export class KeyDescription {
|
||||
get algorithm() {
|
||||
return this._keyDescription?.algorithm;
|
||||
}
|
||||
|
||||
isCompatible(d) {
|
||||
const kd = this._keyDescription;
|
||||
const kdOther = d._keyDescription;
|
||||
if (kd.algorithm === "m.secret_storage.v1.aes-hmac-sha2") {
|
||||
if (kdOther.algorithm !== kd.algorithm) {
|
||||
return false;
|
||||
}
|
||||
if (kd.passphrase) {
|
||||
if (!kdOther.passphrase) {
|
||||
return false;
|
||||
}
|
||||
return kd.passphrase.algorithm === kdOther.passphrase.algorithm &&
|
||||
kd.passphrase.iterations === kdOther.passphrase.iterations &&
|
||||
kd.passphrase.salt === kdOther.passphrase.salt;
|
||||
} else {
|
||||
return !!kd.iv && kd.iv === kdOther.iv &&
|
||||
!!kd.mac && kd.mac === kdOther.mac;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class Key {
|
||||
@ -39,6 +61,10 @@ export class Key {
|
||||
this._binaryKey = binaryKey;
|
||||
}
|
||||
|
||||
withDescription(description) {
|
||||
return new Key(description, this._binaryKey);
|
||||
}
|
||||
|
||||
get description() {
|
||||
return this._keyDescription;
|
||||
}
|
||||
|
@ -50,7 +50,9 @@ export async function readKey(txn) {
|
||||
return;
|
||||
}
|
||||
const keyAccountData = await txn.accountData.get(`m.secret_storage.key.${keyData.id}`);
|
||||
return new Key(new KeyDescription(keyData.id, keyAccountData.content), keyData.binaryKey);
|
||||
if (keyAccountData) {
|
||||
return new Key(new KeyDescription(keyData.id, keyAccountData.content), keyData.binaryKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -77,3 +79,10 @@ export async function keyFromCredentialAndDescription(type, credential, keyDescr
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
export async function keyFromDehydratedDeviceKey(key, storage) {
|
||||
const keyDescription = await readDefaultKeyDescription(storage);
|
||||
if (key.description.isCompatible(keyDescription)) {
|
||||
return key.withDescription(keyDescription);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user