initial version of device rehydration support

This commit is contained in:
Hubert Chathi 2020-08-31 14:40:16 -04:00
parent c9d98a1d19
commit 1c2e05e925
3 changed files with 85 additions and 5 deletions

View file

@ -40,7 +40,7 @@ export class AccessCancelledError extends Error {
} }
} }
async function confirmToDismiss() { export async function confirmToDismiss() {
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
const [sure] = await Modal.createDialog(QuestionDialog, { const [sure] = await Modal.createDialog(QuestionDialog, {
title: _t("Cancel entering passphrase?"), title: _t("Cancel entering passphrase?"),

View file

@ -18,7 +18,12 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import Modal from './Modal';
import * as sdk from './index';
import { AccessCancelledError, confirmToDismiss } from "./CrossSigningManager";
import Matrix from "matrix-js-sdk"; import Matrix from "matrix-js-sdk";
import { deriveKey } from 'matrix-js-sdk/src/crypto/key_passphrase';
import { decodeRecoveryKey } from 'matrix-js-sdk/src/crypto/recoverykey';
export default class Login { export default class Login {
constructor(hsUrl, isUrl, fallbackHsUrl, opts) { constructor(hsUrl, isUrl, fallbackHsUrl, opts) {
@ -159,12 +164,18 @@ export default class Login {
* @returns {MatrixClientCreds} * @returns {MatrixClientCreds}
*/ */
export async function sendLoginRequest(hsUrl, isUrl, loginType, loginParams) { export async function sendLoginRequest(hsUrl, isUrl, loginType, loginParams) {
let rehydrationKeyInfo;
let rehydrationKey;
const client = Matrix.createClient({ const client = Matrix.createClient({
baseUrl: hsUrl, baseUrl: hsUrl,
idBaseUrl: isUrl, idBaseUrl: isUrl,
cryptoCallbacks: {
getDehydrationKey
}
}); });
const data = await client.login(loginType, loginParams); const data = await client.loginWithRehydration(null, loginType, loginParams);
const wellknown = data.well_known; const wellknown = data.well_known;
if (wellknown) { if (wellknown) {
@ -185,5 +196,52 @@ export async function sendLoginRequest(hsUrl, isUrl, loginType, loginParams) {
userId: data.user_id, userId: data.user_id,
deviceId: data.device_id, deviceId: data.device_id,
accessToken: data.access_token, accessToken: data.access_token,
rehydrationKeyInfo,
rehydrationKey,
olmAccount: data._olm_account,
}; };
} }
async function getDehydrationKey(keyInfo) {
const inputToKey = async ({ passphrase, recoveryKey }) => {
if (passphrase) {
return deriveKey(
passphrase,
keyInfo.passphrase.salt,
keyInfo.passphrase.iterations,
);
} else {
return decodeRecoveryKey(recoveryKey);
}
};
const AccessSecretStorageDialog =
sdk.getComponent("dialogs.secretstorage.AccessSecretStorageDialog");
const { finished } = Modal.createTrackedDialog("Access Secret Storage dialog", "",
AccessSecretStorageDialog,
/* props= */
{
keyInfo,
checkPrivateKey: async (input) => {
// FIXME:
return true;
},
},
/* className= */ null,
/* isPriorityModal= */ false,
/* isStaticModal= */ false,
/* options= */ {
onBeforeClose: async (reason) => {
if (reason === "backgroundClick") {
return confirmToDismiss();
}
return true;
},
},
);
const [input] = await finished;
if (!input) {
throw new AccessCancelledError();
}
const key = await inputToKey(input);
return key;
}

View file

@ -42,6 +42,9 @@ export interface IMatrixClientCreds {
accessToken: string; accessToken: string;
guest: boolean; guest: boolean;
pickleKey?: string; pickleKey?: string;
rehydrationKey?: Uint8Array;
rehydrationKeyInfo?: {[props: string]: any};
olmAccount?: any;
} }
// TODO: Move this to the js-sdk // TODO: Move this to the js-sdk
@ -248,12 +251,10 @@ class _MatrixClientPeg implements IMatrixClientPeg {
private createClient(creds: IMatrixClientCreds): void { private createClient(creds: IMatrixClientCreds): void {
// TODO: Make these opts typesafe with the js-sdk // TODO: Make these opts typesafe with the js-sdk
const opts = { const opts: any = {
baseUrl: creds.homeserverUrl, baseUrl: creds.homeserverUrl,
idBaseUrl: creds.identityServerUrl, idBaseUrl: creds.identityServerUrl,
accessToken: creds.accessToken, accessToken: creds.accessToken,
userId: creds.userId,
deviceId: creds.deviceId,
pickleKey: creds.pickleKey, pickleKey: creds.pickleKey,
timelineSupport: true, timelineSupport: true,
forceTURN: !SettingsStore.getValue('webRtcAllowPeerToPeer'), forceTURN: !SettingsStore.getValue('webRtcAllowPeerToPeer'),
@ -268,6 +269,23 @@ class _MatrixClientPeg implements IMatrixClientPeg {
cryptoCallbacks: {}, cryptoCallbacks: {},
}; };
if (creds.olmAccount) {
opts.deviceToImport = {
olmDevice: {
pickledAccount: creds.olmAccount.pickle("DEFAULT_KEY"),
sessions: [],
pickleKey: "DEFAULT_KEY",
},
userId: creds.userId,
deviceId: creds.deviceId,
};
} else {
opts.userId = creds.userId;
opts.deviceId = creds.deviceId;
}
// FIXME: modify crossSigningCallbacks.getSecretStorageKey so that it tries using rehydrationkey and/or saves the passphrase info
// These are always installed regardless of the labs flag so that // These are always installed regardless of the labs flag so that
// cross-signing features can toggle on without reloading and also be // cross-signing features can toggle on without reloading and also be
// accessed immediately after login. // accessed immediately after login.
@ -275,6 +293,10 @@ class _MatrixClientPeg implements IMatrixClientPeg {
this.matrixClient = createMatrixClient(opts); this.matrixClient = createMatrixClient(opts);
if (creds.rehydrationKey) {
this.matrixClient.cacheDehydrationKey(creds.rehydrationKey, creds.rehydrationKeyInfo || {});
}
// we're going to add eventlisteners for each matrix event tile, so the // we're going to add eventlisteners for each matrix event tile, so the
// potential number of event listeners is quite high. // potential number of event listeners is quite high.
this.matrixClient.setMaxListeners(500); this.matrixClient.setMaxListeners(500);