Render verification UI in right-panel

This commit is contained in:
RMidhunSuresh 2023-04-17 22:47:37 +05:30
parent f3efef365d
commit 2b9f508a8f
9 changed files with 136 additions and 23 deletions

View File

@ -25,10 +25,12 @@ import {VerificationCompleteViewModel} from "./stages/VerificationCompleteViewMo
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 {Room} from "../../../matrix/room/Room.js";
type Options = BaseOptions & {
session: Session;
request: SASRequest;
request?: SASRequest;
room?: Room;
};
export class DeviceVerificationViewModel extends ErrorReportViewModel<SegmentType, Options> {
@ -37,27 +39,51 @@ export class DeviceVerificationViewModel extends ErrorReportViewModel<SegmentTyp
constructor(options: Readonly<Options>) {
super(options);
const sasRequest = options.request;
if (options.request) {
this.start(sasRequest);
}
else {
// We are about to send the request
this.start(this.getOption("session").userId);
}
this.init(options);
}
private async start(requestOrUserId: SASRequest | string) {
private async init(options: Options): Promise<void> {
const room = options.room;
let requestOrUserId: SASRequest | string;
if (options.request) {
requestOrUserId = options.request;
}
else if (room) {
requestOrUserId = await this.findMemberFromRoom(room);
}
else {
requestOrUserId = this.getOption("session").userId;
}
await this.start(requestOrUserId, room);
}
private async start(requestOrUserId: SASRequest | string, room?: Room) {
await this.logAndCatch("DeviceVerificationViewModel.start", (log) => {
const crossSigning = this.getOption("session").crossSigning.get();
this.sas = crossSigning.startVerification(requestOrUserId, log);
this.sas = crossSigning.startVerification(requestOrUserId, room, log);
this.addEventListeners();
if (typeof requestOrUserId === "string") {
this.updateCurrentStageViewModel(new WaitingForOtherUserViewModel(this.childOptions({ sas: this.sas })));
}
return crossSigning.signDevice(this.sas, log);
return this.sas.verify();
// return crossSigning.signDevice(this.sas, log);
});
}
private async findMemberFromRoom(room: Room) {
const memberlist = await room.loadMemberList();
const members = memberlist.members;
if (members.size !== 2) {
throw new Error("There are more than two members in this room!");
}
const ourUserId = this.getOption("session").userId;
for (const userId of members.keys()) {
if (userId !== ourUserId) {
memberlist.release();
return userId;
}
}
}
private addEventListeners() {
this.track(this.sas.disposableOn("SelectVerificationStage", (stage) => {
@ -79,7 +105,7 @@ export class DeviceVerificationViewModel extends ErrorReportViewModel<SegmentTyp
}));
this.track(this.sas.disposableOn("VerificationCompleted", (deviceId) => {
this.updateCurrentStageViewModel(
new VerificationCompleteViewModel(this.childOptions({ deviceId: deviceId! }))
new VerificationCompleteViewModel(this.childOptions({ deviceId: deviceId!, sas: this.sas }))
);
}));
}
@ -100,4 +126,8 @@ export class DeviceVerificationViewModel extends ErrorReportViewModel<SegmentTyp
get currentStageViewModel() {
return this._currentStageViewModel;
}
get type(): string {
return "verification";
}
}

View File

@ -48,7 +48,15 @@ export class SelectMethodViewModel extends ErrorReportViewModel<SegmentType, Opt
return this.options.stage.otherDeviceName;
}
get otherUserId() {
return this.getOption("sas").otherUserId;
}
get kind(): string {
return "select-method";
}
get isCrossSigningAnotherUser(): boolean {
return this.getOption("sas").isCrossSigningAnotherUser;
}
}

View File

@ -18,10 +18,12 @@ import {SegmentType} from "../../../navigation/index";
import {ErrorReportViewModel} from "../../../ErrorReportViewModel";
import type {Options as BaseOptions} from "../../../ViewModel";
import type {Session} from "../../../../matrix/Session.js";
import type {SASVerification} from "../../../../matrix/verification/SAS/SASVerification";
type Options = BaseOptions & {
deviceId: string;
session: Session;
sas: SASVerification;
};
export class VerificationCompleteViewModel extends ErrorReportViewModel<SegmentType, Options> {
@ -29,6 +31,10 @@ export class VerificationCompleteViewModel extends ErrorReportViewModel<SegmentT
return this.options.deviceId;
}
get otherUsername(): string {
return this.getOption("sas").otherUserId;
}
gotoSettings() {
this.navigation.push("settings", true);
}
@ -36,4 +42,13 @@ export class VerificationCompleteViewModel extends ErrorReportViewModel<SegmentT
get kind(): string {
return "verification-completed";
}
get verificationSuccessfulMessage(): string {
if (this.getOption("sas").isCrossSigningAnotherUser) {
return this.i18n`You successfully verified user ${this.otherUsername}`;
}
else {
return this.i18n`You successfully verified device ${this.otherDeviceId}`;
}
}
}

View File

@ -53,6 +53,8 @@ export class SASVerification extends EventEmitter<SASProgressEvents> implements
public finished: boolean = false;
public readonly channel: IChannel;
private timeout: Timeout;
public otherUserId: string;
private ourUserId: string;
constructor(options: Options) {
super();
@ -60,6 +62,8 @@ export class SASVerification extends EventEmitter<SASProgressEvents> implements
const olmSas = new olm.SAS();
this.olmSas = olmSas;
this.channel = channel;
this.otherUserId = options.otherUserId;
this.ourUserId = options.ourUserId;
this.setupCancelAfterTimeout(clock);
const stageOptions = {...options, olmSas, eventEmitter: this};
if (channel.getReceivedMessage(VerificationEventType.Start)) {
@ -118,6 +122,10 @@ export class SASVerification extends EventEmitter<SASProgressEvents> implements
get otherDeviceId(): string {
return this.channel.otherUserDeviceId;
}
get isCrossSigningAnotherUser(): boolean {
return !(this.otherUserId === this.ourUserId);
}
}
import {HomeServer} from "../../../mocks/HomeServer.js";

View File

@ -225,9 +225,14 @@ export class RoomChannel extends Disposables implements IChannel {
}
setStartMessage(entry) {
const clone = entry.clone();
clone.content["m.relates_to"] = clone.event.content["m.relates_to"];
this.startMessage = clone;
if (!entry.content["m.relates_to"]) {
const clone = entry.clone();
clone.content["m.relates_to"] = clone.event.content["m.relates_to"];
this.startMessage = clone;
}
else {
this.startMessage = entry;
}
this._initiatedByUs = entry.content.from_device === this.ourDeviceId;
}

View File

@ -1399,6 +1399,10 @@ button.RoomDetailsView_row::after {
justify-content: center;
}
.VerifyEmojisView {
width: 100%;
}
.VerificationCompleteView,
.DeviceVerificationView,
.SelectMethodView {
@ -1406,6 +1410,13 @@ button.RoomDetailsView_row::after {
align-items: center;
justify-content: center;
flex-direction: column;
width: 100%;
}
.SelectMethodView > div,
.SelectMethodView__heading,
.SelectMethodView__title {
width: inherit;
}
.VerificationCompleteView__heading,
@ -1427,6 +1438,15 @@ button.RoomDetailsView_row::after {
padding: 16px;
}
.VerificationCancelledView__title,
.VerificationCompleteView__title,
.VerifyEmojisView__title,
.SelectMethodView__title,
.WaitingForOtherUserView__title {
font-size: 1.5em;
text-align: center;
}
.VerificationCompleteView__title,
.VerifyEmojisView__title,
.SelectMethodView__title,
@ -1454,6 +1474,7 @@ button.RoomDetailsView_row::after {
display: flex;
justify-content: center;
gap: 16px;
flex-wrap: wrap;
}
.EmojiContainer__emoji {
@ -1482,3 +1503,10 @@ button.RoomDetailsView_row::after {
width: 128px;
height: 128px;
}
.SelectMethodView__name {
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
display: inline-block;
}

View File

@ -19,6 +19,7 @@ import {RoomDetailsView} from "./RoomDetailsView.js";
import {MemberListView} from "./MemberListView.js";
import {LoadingView} from "../../general/LoadingView.js";
import {MemberDetailsView} from "./MemberDetailsView.js";
import {DeviceVerificationView} from "../verification/DeviceVerificationView";
export class RightPanelView extends TemplateView {
render(t) {
@ -39,6 +40,8 @@ export class RightPanelView extends TemplateView {
return new MemberListView(vm);
case "member-details":
return new MemberDetailsView(vm);
case "verification":
return new DeviceVerificationView(vm);
default:
return new LoadingView();
}

View File

@ -27,11 +27,9 @@ export class SelectMethodView extends TemplateView<SelectMethodViewModel> {
}
else return t.div([
t.div({ className: "SelectMethodView__heading" }, [
t.h2( { className: "SelectMethodView__title" }, vm.i18n`Verify device '${vm.deviceName}' by comparing emojis?`),
t.h2( { className: "SelectMethodView__title" }, this.getHeading(t, vm)),
]),
t.p({ className: "SelectMethodView__description" },
vm.i18n`You are about to verify your other device by comparing emojis.`
),
t.p({ className: "SelectMethodView__description" }, this.getSubheading(vm)),
t.div({ className: "SelectMethodView__actions" }, [
t.button(
{
@ -59,4 +57,24 @@ export class SelectMethodView extends TemplateView<SelectMethodViewModel> {
}),
]);
}
getHeading(t: Builder<SelectMethodViewModel>, vm: SelectMethodViewModel) {
if (vm.isCrossSigningAnotherUser) {
return [vm.i18n`Verify user `, t.span({
className: "SelectMethodView__name"
}, vm.otherUserId), vm.i18n` by comparing emojis?`];
} else {
return [vm.i18n`Verify device`, t.span({
className: "SelectMethodView__name"
}, vm.deviceName), vm.i18n` by comparing emojis?`];
}
}
getSubheading(vm: SelectMethodViewModel): string {
if (vm.isCrossSigningAnotherUser) {
return vm.i18n`You are about to verify user (${vm.otherUserId}) by comparing emojis.`;
} else {
return vm.i18n`You are about to verify your other device (${vm.deviceName}) by comparing emojis.`;
}
}
}

View File

@ -28,9 +28,7 @@ export class VerificationCompleteView extends TemplateView<VerificationCompleteV
),
]),
t.p(
{ className: "VerificationCompleteView__description" },
vm.i18n`You successfully verified device ${vm.otherDeviceId}`
),
{ className: "VerificationCompleteView__description" }, vm.verificationSuccessfulMessage),
t.div({ className: "VerificationCompleteView__actions" }, [
t.button({
className: {