migrate SetupEncryptionStore to TypeScript

pull/21833/head
Germain Souquet 2021-06-14 20:58:20 +01:00
parent 68db2438ea
commit 5f2ab50a90
3 changed files with 61 additions and 46 deletions

View File

@ -44,6 +44,7 @@ import { EventIndexPeg } from "../indexing/EventIndexPeg";
import {VoiceRecordingStore} from "../stores/VoiceRecordingStore"; import {VoiceRecordingStore} from "../stores/VoiceRecordingStore";
import PerformanceMonitor from "../performance"; import PerformanceMonitor from "../performance";
import UIStore from "../stores/UIStore"; import UIStore from "../stores/UIStore";
import { SetupEncryptionStore } from "../stores/SetupEncryptionStore";
declare global { declare global {
interface Window { interface Window {
@ -84,6 +85,7 @@ declare global {
mxPerformanceMonitor: PerformanceMonitor; mxPerformanceMonitor: PerformanceMonitor;
mxPerformanceEntryNames: any; mxPerformanceEntryNames: any;
mxUIStore: UIStore; mxUIStore: UIStore;
mxSetupEncryptionStore?: SetupEncryptionStore;
} }
interface Document { interface Document {

View File

@ -18,11 +18,11 @@ import React from 'react';
import SetupEncryptionBody from '../../../structures/auth/SetupEncryptionBody'; import SetupEncryptionBody from '../../../structures/auth/SetupEncryptionBody';
import BaseDialog from '../BaseDialog'; import BaseDialog from '../BaseDialog';
import { _t } from '../../../../languageHandler'; import { _t } from '../../../../languageHandler';
import { SetupEncryptionStore, PHASE_DONE } from '../../../../stores/SetupEncryptionStore'; import { SetupEncryptionStore, PHASE } from '../../../../stores/SetupEncryptionStore';
import {replaceableComponent} from "../../../../utils/replaceableComponent"; import {replaceableComponent} from "../../../../utils/replaceableComponent";
function iconFromPhase(phase: string) { function iconFromPhase(phase: PHASE) {
if (phase === PHASE_DONE) { if (phase === PHASE.DONE) {
return require("../../../../../res/img/e2e/verified.svg"); return require("../../../../../res/img/e2e/verified.svg");
} else { } else {
return require("../../../../../res/img/e2e/warning.svg"); return require("../../../../../res/img/e2e/warning.svg");
@ -34,7 +34,7 @@ interface IProps {
} }
interface IState { interface IState {
icon: any; icon: PHASE;
} }
@replaceableComponent("views.dialogs.security.SetupEncryptionDialog") @replaceableComponent("views.dialogs.security.SetupEncryptionDialog")

View File

@ -15,29 +15,42 @@ limitations under the License.
*/ */
import EventEmitter from 'events'; import EventEmitter from 'events';
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
import { IKeyBackupVersion } from "matrix-js-sdk/src/crypto/keybackup";
import { ISecretStorageKeyInfo } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from '../MatrixClientPeg'; import { MatrixClientPeg } from '../MatrixClientPeg';
import { accessSecretStorage, AccessCancelledError } from '../SecurityManager'; import { accessSecretStorage, AccessCancelledError } from '../SecurityManager';
import { PHASE_DONE as VERIF_PHASE_DONE } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import { PHASE_DONE as VERIF_PHASE_DONE } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
export const PHASE_LOADING = 0; export enum PHASE {
export const PHASE_INTRO = 1; LOADING = 0,
export const PHASE_BUSY = 2; INTRO = 1,
export const PHASE_DONE = 3; //final done stage, but still showing UX BUSY = 2,
export const PHASE_CONFIRM_SKIP = 4; DONE = 3, // final done stage, but still showing UX
export const PHASE_FINISHED = 5; //UX can be closed CONFIRM_SKIP = 4,
FINISHED = 5, // UX can be closed
}
export class SetupEncryptionStore extends EventEmitter { export class SetupEncryptionStore extends EventEmitter {
static sharedInstance() { private started: boolean;
if (!global.mx_SetupEncryptionStore) global.mx_SetupEncryptionStore = new SetupEncryptionStore(); public phase: PHASE;
return global.mx_SetupEncryptionStore; public verificationRequest: VerificationRequest;
public backupInfo: IKeyBackupVersion;
public keyId: string;
public keyInfo: ISecretStorageKeyInfo;
public hasDevicesToVerifyAgainst: boolean;
public static sharedInstance() {
if (!window.mxSetupEncryptionStore) window.mxSetupEncryptionStore = new SetupEncryptionStore();
return window.mxSetupEncryptionStore;
} }
start() { public start(): void {
if (this._started) { if (this.started) {
return; return;
} }
this._started = true; this.started = true;
this.phase = PHASE_LOADING; this.phase = PHASE.LOADING;
this.verificationRequest = null; this.verificationRequest = null;
this.backupInfo = null; this.backupInfo = null;
@ -48,34 +61,34 @@ export class SetupEncryptionStore extends EventEmitter {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
cli.on("crypto.verification.request", this.onVerificationRequest); cli.on("crypto.verification.request", this.onVerificationRequest);
cli.on('userTrustStatusChanged', this._onUserTrustStatusChanged); cli.on('userTrustStatusChanged', this.onUserTrustStatusChanged);
const requestsInProgress = cli.getVerificationRequestsToDeviceInProgress(cli.getUserId()); const requestsInProgress = cli.getVerificationRequestsToDeviceInProgress(cli.getUserId());
if (requestsInProgress.length) { if (requestsInProgress.length) {
// If there are multiple, we take the most recent. Equally if the user sends another request from // If there are multiple, we take the most recent. Equally if the user sends another request from
// another device after this screen has been shown, we'll switch to the new one, so this // another device after this screen has been shown, we'll switch to the new one, so this
// generally doesn't support multiple requests. // generally doesn't support multiple requests.
this._setActiveVerificationRequest(requestsInProgress[requestsInProgress.length - 1]); this.setActiveVerificationRequest(requestsInProgress[requestsInProgress.length - 1]);
} }
this.fetchKeyInfo(); this.fetchKeyInfo();
} }
stop() { public stop(): void {
if (!this._started) { if (!this.started) {
return; return;
} }
this._started = false; this.started = false;
if (this.verificationRequest) { if (this.verificationRequest) {
this.verificationRequest.off("change", this.onVerificationRequestChange); this.verificationRequest.off("change", this.onVerificationRequestChange);
} }
if (MatrixClientPeg.get()) { if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("crypto.verification.request", this.onVerificationRequest); MatrixClientPeg.get().removeListener("crypto.verification.request", this.onVerificationRequest);
MatrixClientPeg.get().removeListener('userTrustStatusChanged', this._onUserTrustStatusChanged); MatrixClientPeg.get().removeListener('userTrustStatusChanged', this.onUserTrustStatusChanged);
} }
} }
async fetchKeyInfo() { public async fetchKeyInfo(): Promise<void> {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
const keys = await cli.isSecretStored('m.cross_signing.master', false); const keys = await cli.isSecretStored('m.cross_signing.master', false);
if (keys === null || Object.keys(keys).length === 0) { if (keys === null || Object.keys(keys).length === 0) {
@ -97,15 +110,15 @@ export class SetupEncryptionStore extends EventEmitter {
if (!this.hasDevicesToVerifyAgainst && !this.keyInfo) { if (!this.hasDevicesToVerifyAgainst && !this.keyInfo) {
// skip before we can even render anything. // skip before we can even render anything.
this.phase = PHASE_FINISHED; this.phase = PHASE.FINISHED;
} else { } else {
this.phase = PHASE_INTRO; this.phase = PHASE.INTRO;
} }
this.emit("update"); this.emit("update");
} }
async usePassPhrase() { public async usePassPhrase(): Promise<void> {
this.phase = PHASE_BUSY; this.phase = PHASE.BUSY;
this.emit("update"); this.emit("update");
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
try { try {
@ -120,7 +133,7 @@ export class SetupEncryptionStore extends EventEmitter {
// passphase cached for that work. This dialog itself will only wait // passphase cached for that work. This dialog itself will only wait
// on the first trust check, and the key backup restore will happen // on the first trust check, and the key backup restore will happen
// in the background. // in the background.
await new Promise((resolve, reject) => { await new Promise((resolve: (value?: unknown) => void, reject: (reason?: any) => void) => {
accessSecretStorage(async () => { accessSecretStorage(async () => {
await cli.checkOwnCrossSigningTrust(); await cli.checkOwnCrossSigningTrust();
resolve(); resolve();
@ -134,7 +147,7 @@ export class SetupEncryptionStore extends EventEmitter {
}); });
if (cli.getCrossSigningId()) { if (cli.getCrossSigningId()) {
this.phase = PHASE_DONE; this.phase = PHASE.DONE;
this.emit("update"); this.emit("update");
} }
} catch (e) { } catch (e) {
@ -142,25 +155,25 @@ export class SetupEncryptionStore extends EventEmitter {
console.log(e); console.log(e);
} }
// this will throw if the user hits cancel, so ignore // this will throw if the user hits cancel, so ignore
this.phase = PHASE_INTRO; this.phase = PHASE.INTRO;
this.emit("update"); this.emit("update");
} }
} }
_onUserTrustStatusChanged = (userId) => { private onUserTrustStatusChanged = (userId: string) => {
if (userId !== MatrixClientPeg.get().getUserId()) return; if (userId !== MatrixClientPeg.get().getUserId()) return;
const publicKeysTrusted = MatrixClientPeg.get().getCrossSigningId(); const publicKeysTrusted = MatrixClientPeg.get().getCrossSigningId();
if (publicKeysTrusted) { if (publicKeysTrusted) {
this.phase = PHASE_DONE; this.phase = PHASE.DONE;
this.emit("update"); this.emit("update");
} }
} }
onVerificationRequest = (request) => { public onVerificationRequest = (request: VerificationRequest): void => {
this._setActiveVerificationRequest(request); this.setActiveVerificationRequest(request);
} }
onVerificationRequestChange = () => { public onVerificationRequestChange = (): void => {
if (this.verificationRequest.cancelled) { if (this.verificationRequest.cancelled) {
this.verificationRequest.off("change", this.onVerificationRequestChange); this.verificationRequest.off("change", this.onVerificationRequestChange);
this.verificationRequest = null; this.verificationRequest = null;
@ -172,34 +185,34 @@ export class SetupEncryptionStore extends EventEmitter {
// cross signing to be ready to use, so wait for the user trust status to // cross signing to be ready to use, so wait for the user trust status to
// change (or change to DONE if it's already ready). // change (or change to DONE if it's already ready).
const publicKeysTrusted = MatrixClientPeg.get().getCrossSigningId(); const publicKeysTrusted = MatrixClientPeg.get().getCrossSigningId();
this.phase = publicKeysTrusted ? PHASE_DONE : PHASE_BUSY; this.phase = publicKeysTrusted ? PHASE.DONE : PHASE.BUSY;
this.emit("update"); this.emit("update");
} }
} }
skip() { public skip(): void {
this.phase = PHASE_CONFIRM_SKIP; this.phase = PHASE.CONFIRM_SKIP;
this.emit("update"); this.emit("update");
} }
skipConfirm() { public skipConfirm(): void {
this.phase = PHASE_FINISHED; this.phase = PHASE.FINISHED;
this.emit("update"); this.emit("update");
} }
returnAfterSkip() { public returnAfterSkip(): void {
this.phase = PHASE_INTRO; this.phase = PHASE.INTRO;
this.emit("update"); this.emit("update");
} }
done() { public done(): void {
this.phase = PHASE_FINISHED; this.phase = PHASE.FINISHED;
this.emit("update"); this.emit("update");
// async - ask other clients for keys, if necessary // async - ask other clients for keys, if necessary
MatrixClientPeg.get().crypto.cancelAndResendAllOutgoingKeyRequests(); MatrixClientPeg.get().crypto.cancelAndResendAllOutgoingKeyRequests();
} }
async _setActiveVerificationRequest(request) { private async setActiveVerificationRequest(request: VerificationRequest): Promise<void> {
if (request.otherUserId !== MatrixClientPeg.get().getUserId()) return; if (request.otherUserId !== MatrixClientPeg.get().getUserId()) return;
if (this.verificationRequest) { if (this.verificationRequest) {