Show a view when keys are missing

This commit is contained in:
RMidhunSuresh 2023-06-09 13:33:36 +05:30
parent 00479df71e
commit 4f42e1b34c
6 changed files with 127 additions and 7 deletions

View File

@ -22,16 +22,24 @@ import {VerificationCancelledViewModel} from "./stages/VerificationCancelledView
import {SelectMethodViewModel} from "./stages/SelectMethodViewModel";
import {VerifyEmojisViewModel} from "./stages/VerifyEmojisViewModel";
import {VerificationCompleteViewModel} from "./stages/VerificationCompleteViewModel";
import {MissingKeysViewModel} from "./stages/MissingKeysViewModel";
import type {Session} from "../../../matrix/Session.js";
import type {SASVerification} from "../../../matrix/verification/SAS/SASVerification";
import type {SASRequest} from "../../../matrix/verification/SAS/SASRequest";
import type {CrossSigning} from "../../../matrix/verification/CrossSigning";
import type {ILogItem} from "../../../logging/types";
type Options = BaseOptions & {
session: Session;
request: SASRequest;
};
const neededSecrets = [
"m.cross_signing.master",
"m.cross_signing.self_signing",
"m.cross_signing.user_signing",
];
export class DeviceVerificationViewModel extends ErrorReportViewModel<SegmentType, Options> {
private sas: SASVerification;
private _currentStageViewModel: any;
@ -53,14 +61,47 @@ export class DeviceVerificationViewModel extends ErrorReportViewModel<SegmentTyp
await this.logAndCatch("DeviceVerificationViewModel.start", async (log) => {
const crossSigning = this.getOption("session").crossSigning.get() as CrossSigning;
this.sas = crossSigning.startVerification(requestOrUserId, log)!;
if (!await this.performPreVerificationChecks(crossSigning, log)) {
return;
}
this.addEventListeners();
if (typeof requestOrUserId === "string") {
this.updateCurrentStageViewModel(new WaitingForOtherUserViewModel(this.childOptions({ sas: this.sas })));
}
this._needsToRequestSecret = !await crossSigning.areWeVerified(log);
return this.sas.start();
});
}
private async performPreVerificationChecks(crossSigning: CrossSigning, log: ILogItem): Promise<boolean> {
return await log.wrap("DeviceVerificationViewModel.performPreVerificationChecks", async (_log) => {
const areWeVerified = await crossSigning.areWeVerified(log);
// If we're not verified, we'll need to ask the other device for secrets later
this._needsToRequestSecret = !areWeVerified;
if (this._needsToRequestSecret) {
return true;
}
/**
* It's possible that we are verified but don't have access
* to the private cross-signing keys. In this case we really
* can't verify the other device because we need these keys
* to sign their device.
*
* If this happens, we'll simply ask the user to enable key-backup
* (and secret storage) and try again later.
*/
const session = this.getOption("session");
const promises = neededSecrets.map(s => session.secretFetcher.getSecret(s));
const secrets = await Promise.all(promises)
for (const secret of secrets) {
if (!secret) {
// We really can't proceed!
this.updateCurrentStageViewModel(new MissingKeysViewModel(this.childOptions({})));
return false;
}
}
return true;
});
}
private addEventListeners() {
this.track(this.sas.disposableOn("SelectVerificationStage", (stage) => {
@ -91,11 +132,6 @@ export class DeviceVerificationViewModel extends ErrorReportViewModel<SegmentTyp
private async requestSecrets() {
await this.platform.logger.run("DeviceVerificationViewModel.requestSecrets", async (log) => {
if (this._needsToRequestSecret) {
const neededSecrets = [
"m.cross_signing.master",
"m.cross_signing.self_signing",
"m.cross_signing.user_signing",
];
const secretSharing = this.getOption("session").secretSharing;
const promises = neededSecrets.map((secret) => secretSharing.requestSecret(secret, log));
await Promise.all(promises);
@ -110,7 +146,7 @@ export class DeviceVerificationViewModel extends ErrorReportViewModel<SegmentTyp
}
dispose(): void {
if (!this.sas.finished) {
if (this.sas && !this.sas.finished) {
this.sas.abort().catch(() => {/** ignore */});
}
super.dispose();

View File

@ -0,0 +1,28 @@
/*
Copyright 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {ViewModel, Options} from "../../../ViewModel";
import {SegmentType} from "../../../navigation/index";
export class MissingKeysViewModel extends ViewModel<SegmentType, Options> {
gotoSettings() {
this.navigation.push("settings", true);
}
get kind(): string {
return "keys-missing";
}
}

View File

@ -401,6 +401,10 @@ export class Session {
return this._secretSharing;
}
get secretFetcher() {
return this._secretFetcher;
}
get hasIdentity() {
return !!this._e2eeAccount;
}

View File

@ -1411,6 +1411,7 @@ button.RoomDetailsView_row::after {
.VerificationCompleteView__heading,
.VerifyEmojisView__heading,
.SelectMethodView__heading,
.MissingKeysView__heading,
.WaitingForOtherUserView__heading {
display: flex;
align-items: center;
@ -1432,6 +1433,7 @@ button.RoomDetailsView_row::after {
.SelectMethodView__title,
.WaitingForOtherUserView__title,
.VerificationCancelledView__description,
.MissingKeysView__description,
.VerificationCompleteView__description,
.VerifyEmojisView__description,
.SelectMethodView__description,
@ -1441,6 +1443,7 @@ button.RoomDetailsView_row::after {
}
.VerificationCancelledView__actions,
.MissingKeysView__actions,
.SelectMethodView__actions,
.VerifyEmojisView__actions,
.WaitingForOtherUserView__actions {

View File

@ -21,6 +21,7 @@ import {VerificationCancelledView} from "./stages/VerificationCancelledView";
import {SelectMethodView} from "./stages/SelectMethodView";
import {VerifyEmojisView} from "./stages/VerifyEmojisView";
import {VerificationCompleteView} from "./stages/VerificationCompleteView";
import {MissingKeysView} from "./stages/MissingKeysView";
export class DeviceVerificationView extends TemplateView<DeviceVerificationViewModel> {
render(t: Builder<DeviceVerificationViewModel>) {
@ -37,6 +38,7 @@ export class DeviceVerificationView extends TemplateView<DeviceVerificationViewM
case "select-method": return new SelectMethodView(vm);
case "verify-emojis": return new VerifyEmojisView(vm);
case "verification-completed": return new VerificationCompleteView(vm);
case "keys-missing": return new MissingKeysView(vm);
default: return null;
}
})

View File

@ -0,0 +1,47 @@
/*
Copyright 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {Builder, TemplateView} from "../../../general/TemplateView";
import type {MissingKeysViewModel} from "../../../../../../domain/session/verification/stages/MissingKeysViewModel";
export class MissingKeysView extends TemplateView<MissingKeysViewModel> {
render(t: Builder<MissingKeysViewModel>, vm: MissingKeysViewModel) {
return t.div(
{
className: "MissingKeysView",
},
[
t.h2(
{ className: "MissingKeysView__heading" },
vm.i18n`Verification is currently not possible!`
),
t.p(
{ className: "MissingKeysView__description" },
vm.i18n`Some keys needed for verification is missing. You can fix this by enabling key backup in settings.`
),
t.div({ className: "MissingKeysView__actions" }, [
t.button({
className: {
"button-action": true,
"primary": true,
},
onclick: () => vm.gotoSettings(),
}, "Open Settings")
]),
]
);
}
}