try to unlock secret storage with dehydration key
parent
744f46417a
commit
503f32948c
|
@ -31,7 +31,7 @@ import {verificationMethods} from 'matrix-js-sdk/src/crypto';
|
||||||
import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientBackedSettingsHandler";
|
import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientBackedSettingsHandler";
|
||||||
import * as StorageManager from './utils/StorageManager';
|
import * as StorageManager from './utils/StorageManager';
|
||||||
import IdentityAuthClient from './IdentityAuthClient';
|
import IdentityAuthClient from './IdentityAuthClient';
|
||||||
import { crossSigningCallbacks } from './SecurityManager';
|
import { crossSigningCallbacks, tryToUnlockSecretStorageWithDehydrationKey } from './SecurityManager';
|
||||||
import {SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
|
import {SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
|
||||||
|
|
||||||
export interface IMatrixClientCreds {
|
export interface IMatrixClientCreds {
|
||||||
|
@ -193,6 +193,7 @@ class _MatrixClientPeg implements IMatrixClientPeg {
|
||||||
this.matrixClient.setCryptoTrustCrossSignedDevices(
|
this.matrixClient.setCryptoTrustCrossSignedDevices(
|
||||||
!SettingsStore.getValue('e2ee.manuallyVerifyAllSessions'),
|
!SettingsStore.getValue('e2ee.manuallyVerifyAllSessions'),
|
||||||
);
|
);
|
||||||
|
await tryToUnlockSecretStorageWithDehydrationKey(this.matrixClient);
|
||||||
StorageManager.setCryptoInitialised(true);
|
StorageManager.setCryptoInitialised(true);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -34,15 +34,9 @@ let secretStorageKeys = {};
|
||||||
let secretStorageKeyInfo = {};
|
let secretStorageKeyInfo = {};
|
||||||
let secretStorageBeingAccessed = false;
|
let secretStorageBeingAccessed = false;
|
||||||
|
|
||||||
let dehydrationInfo = {};
|
let nonInteractive = false;
|
||||||
|
|
||||||
export function cacheDehydrationKey(key, keyInfo = {}) {
|
let dehydrationCache = {};
|
||||||
dehydrationInfo = {key, keyInfo};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDehydrationKeyCache() {
|
|
||||||
return dehydrationInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isCachingAllowed() {
|
function isCachingAllowed() {
|
||||||
return secretStorageBeingAccessed;
|
return secretStorageBeingAccessed;
|
||||||
|
@ -103,18 +97,15 @@ async function getSecretStorageKey({ keys: keyInfos }, ssssItemName) {
|
||||||
return [keyId, secretStorageKeys[keyId]];
|
return [keyId, secretStorageKeys[keyId]];
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we dehydrated a device, see if that key works for SSSS
|
if (dehydrationCache.key) {
|
||||||
if (dehydrationInfo.key) {
|
if (await MatrixClientPeg.get().checkSecretStorageKey(dehydrationCache.key, keyInfo)) {
|
||||||
try {
|
cacheSecretStorageKey(keyId, dehydrationCache.key, keyInfo);
|
||||||
const key = dehydrationInfo.key;
|
return [keyId, dehydrationCache.key];
|
||||||
if (await MatrixClientPeg.get().checkSecretStorageKey(key, keyInfo)) {
|
|
||||||
// Save to cache to avoid future prompts in the current session
|
|
||||||
cacheSecretStorageKey(keyId, key, keyInfo);
|
|
||||||
dehydrationInfo = {};
|
|
||||||
return [name, key];
|
|
||||||
}
|
}
|
||||||
} catch {}
|
}
|
||||||
dehydrationInfo = {};
|
|
||||||
|
if (nonInteractive) {
|
||||||
|
throw new Error("Could not unlock non-interactively");
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputToKey = makeInputToKey(keyInfo);
|
const inputToKey = makeInputToKey(keyInfo);
|
||||||
|
@ -186,8 +177,10 @@ export async function getDehydrationKey(keyInfo, checkFunc) {
|
||||||
throw new AccessCancelledError();
|
throw new AccessCancelledError();
|
||||||
}
|
}
|
||||||
const key = await inputToKey(input);
|
const key = await inputToKey(input);
|
||||||
|
|
||||||
// need to copy the key because rehydration (unpickling) will clobber it
|
// need to copy the key because rehydration (unpickling) will clobber it
|
||||||
cacheDehydrationKey(key, keyInfo);
|
dehydrationCache = {key: new Uint8Array(key), keyInfo};
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,3 +351,53 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: this function name is a bit of a mouthful
|
||||||
|
export async function tryToUnlockSecretStorageWithDehydrationKey(client) {
|
||||||
|
const key = dehydrationCache.key;
|
||||||
|
let restoringBackup = false;
|
||||||
|
if (key && await client.isSecretStorageReady()) {
|
||||||
|
console.log("Trying to set up cross-signing using dehydration key");
|
||||||
|
secretStorageBeingAccessed = true;
|
||||||
|
nonInteractive = true;
|
||||||
|
try {
|
||||||
|
await client.checkOwnCrossSigningTrust();
|
||||||
|
|
||||||
|
// we also need to set a new dehydrated device to replace the
|
||||||
|
// device we rehydrated
|
||||||
|
const dehydrationKeyInfo =
|
||||||
|
dehydrationCache.keyInfo && dehydrationCache.keyInfo.passphrase
|
||||||
|
? {passphrase: dehydrationCache.keyInfo.passphrase}
|
||||||
|
: {};
|
||||||
|
await client.setDehydrationKey(key, dehydrationKeyInfo);
|
||||||
|
|
||||||
|
// and restore from backup
|
||||||
|
const backupInfo = await client.getKeyBackupVersion();
|
||||||
|
if (backupInfo) {
|
||||||
|
restoringBackup = true;
|
||||||
|
// don't await, because this can take a long time
|
||||||
|
client.restoreKeyBackupWithSecretStorage(backupInfo)
|
||||||
|
.finally(() => {
|
||||||
|
secretStorageBeingAccessed = false;
|
||||||
|
nonInteractive = false;
|
||||||
|
if (!isCachingAllowed()) {
|
||||||
|
secretStorageKeys = {};
|
||||||
|
secretStorageKeyInfo = {};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
dehydrationCache = {};
|
||||||
|
// the secret storage cache is needed for restoring from backup, so
|
||||||
|
// don't clear it yet if we're restoring from backup
|
||||||
|
if (!restoringBackup) {
|
||||||
|
secretStorageBeingAccessed = false;
|
||||||
|
nonInteractive = false;
|
||||||
|
if (!isCachingAllowed()) {
|
||||||
|
secretStorageKeys = {};
|
||||||
|
secretStorageKeyInfo = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue