initial version of device rehydration support
This commit is contained in:
parent
c9d98a1d19
commit
1c2e05e925
3 changed files with 85 additions and 5 deletions
|
@ -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?"),
|
||||||
|
|
60
src/Login.js
60
src/Login.js
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue