mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-11-20 03:25:52 +01:00
Render verification UI in right-panel
This commit is contained in:
parent
f3efef365d
commit
2b9f508a8f
@ -25,10 +25,12 @@ import {VerificationCompleteViewModel} from "./stages/VerificationCompleteViewMo
|
|||||||
import type {Session} from "../../../matrix/Session.js";
|
import type {Session} from "../../../matrix/Session.js";
|
||||||
import type {SASVerification} from "../../../matrix/verification/SAS/SASVerification";
|
import type {SASVerification} from "../../../matrix/verification/SAS/SASVerification";
|
||||||
import type {SASRequest} from "../../../matrix/verification/SAS/SASRequest";
|
import type {SASRequest} from "../../../matrix/verification/SAS/SASRequest";
|
||||||
|
import type {Room} from "../../../matrix/room/Room.js";
|
||||||
|
|
||||||
type Options = BaseOptions & {
|
type Options = BaseOptions & {
|
||||||
session: Session;
|
session: Session;
|
||||||
request: SASRequest;
|
request?: SASRequest;
|
||||||
|
room?: Room;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class DeviceVerificationViewModel extends ErrorReportViewModel<SegmentType, Options> {
|
export class DeviceVerificationViewModel extends ErrorReportViewModel<SegmentType, Options> {
|
||||||
@ -37,27 +39,51 @@ export class DeviceVerificationViewModel extends ErrorReportViewModel<SegmentTyp
|
|||||||
|
|
||||||
constructor(options: Readonly<Options>) {
|
constructor(options: Readonly<Options>) {
|
||||||
super(options);
|
super(options);
|
||||||
const sasRequest = options.request;
|
this.init(options);
|
||||||
if (options.request) {
|
|
||||||
this.start(sasRequest);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// We are about to send the request
|
|
||||||
this.start(this.getOption("session").userId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) => {
|
await this.logAndCatch("DeviceVerificationViewModel.start", (log) => {
|
||||||
const crossSigning = this.getOption("session").crossSigning.get();
|
const crossSigning = this.getOption("session").crossSigning.get();
|
||||||
this.sas = crossSigning.startVerification(requestOrUserId, log);
|
this.sas = crossSigning.startVerification(requestOrUserId, room, log);
|
||||||
this.addEventListeners();
|
this.addEventListeners();
|
||||||
if (typeof requestOrUserId === "string") {
|
if (typeof requestOrUserId === "string") {
|
||||||
this.updateCurrentStageViewModel(new WaitingForOtherUserViewModel(this.childOptions({ sas: this.sas })));
|
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() {
|
private addEventListeners() {
|
||||||
this.track(this.sas.disposableOn("SelectVerificationStage", (stage) => {
|
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.track(this.sas.disposableOn("VerificationCompleted", (deviceId) => {
|
||||||
this.updateCurrentStageViewModel(
|
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() {
|
get currentStageViewModel() {
|
||||||
return this._currentStageViewModel;
|
return this._currentStageViewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get type(): string {
|
||||||
|
return "verification";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,15 @@ export class SelectMethodViewModel extends ErrorReportViewModel<SegmentType, Opt
|
|||||||
return this.options.stage.otherDeviceName;
|
return this.options.stage.otherDeviceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get otherUserId() {
|
||||||
|
return this.getOption("sas").otherUserId;
|
||||||
|
}
|
||||||
|
|
||||||
get kind(): string {
|
get kind(): string {
|
||||||
return "select-method";
|
return "select-method";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isCrossSigningAnotherUser(): boolean {
|
||||||
|
return this.getOption("sas").isCrossSigningAnotherUser;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,12 @@ import {SegmentType} from "../../../navigation/index";
|
|||||||
import {ErrorReportViewModel} from "../../../ErrorReportViewModel";
|
import {ErrorReportViewModel} from "../../../ErrorReportViewModel";
|
||||||
import type {Options as BaseOptions} from "../../../ViewModel";
|
import type {Options as BaseOptions} from "../../../ViewModel";
|
||||||
import type {Session} from "../../../../matrix/Session.js";
|
import type {Session} from "../../../../matrix/Session.js";
|
||||||
|
import type {SASVerification} from "../../../../matrix/verification/SAS/SASVerification";
|
||||||
|
|
||||||
type Options = BaseOptions & {
|
type Options = BaseOptions & {
|
||||||
deviceId: string;
|
deviceId: string;
|
||||||
session: Session;
|
session: Session;
|
||||||
|
sas: SASVerification;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class VerificationCompleteViewModel extends ErrorReportViewModel<SegmentType, Options> {
|
export class VerificationCompleteViewModel extends ErrorReportViewModel<SegmentType, Options> {
|
||||||
@ -29,6 +31,10 @@ export class VerificationCompleteViewModel extends ErrorReportViewModel<SegmentT
|
|||||||
return this.options.deviceId;
|
return this.options.deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get otherUsername(): string {
|
||||||
|
return this.getOption("sas").otherUserId;
|
||||||
|
}
|
||||||
|
|
||||||
gotoSettings() {
|
gotoSettings() {
|
||||||
this.navigation.push("settings", true);
|
this.navigation.push("settings", true);
|
||||||
}
|
}
|
||||||
@ -36,4 +42,13 @@ export class VerificationCompleteViewModel extends ErrorReportViewModel<SegmentT
|
|||||||
get kind(): string {
|
get kind(): string {
|
||||||
return "verification-completed";
|
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}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,8 @@ export class SASVerification extends EventEmitter<SASProgressEvents> implements
|
|||||||
public finished: boolean = false;
|
public finished: boolean = false;
|
||||||
public readonly channel: IChannel;
|
public readonly channel: IChannel;
|
||||||
private timeout: Timeout;
|
private timeout: Timeout;
|
||||||
|
public otherUserId: string;
|
||||||
|
private ourUserId: string;
|
||||||
|
|
||||||
constructor(options: Options) {
|
constructor(options: Options) {
|
||||||
super();
|
super();
|
||||||
@ -60,6 +62,8 @@ export class SASVerification extends EventEmitter<SASProgressEvents> implements
|
|||||||
const olmSas = new olm.SAS();
|
const olmSas = new olm.SAS();
|
||||||
this.olmSas = olmSas;
|
this.olmSas = olmSas;
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
|
this.otherUserId = options.otherUserId;
|
||||||
|
this.ourUserId = options.ourUserId;
|
||||||
this.setupCancelAfterTimeout(clock);
|
this.setupCancelAfterTimeout(clock);
|
||||||
const stageOptions = {...options, olmSas, eventEmitter: this};
|
const stageOptions = {...options, olmSas, eventEmitter: this};
|
||||||
if (channel.getReceivedMessage(VerificationEventType.Start)) {
|
if (channel.getReceivedMessage(VerificationEventType.Start)) {
|
||||||
@ -118,6 +122,10 @@ export class SASVerification extends EventEmitter<SASProgressEvents> implements
|
|||||||
get otherDeviceId(): string {
|
get otherDeviceId(): string {
|
||||||
return this.channel.otherUserDeviceId;
|
return this.channel.otherUserDeviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isCrossSigningAnotherUser(): boolean {
|
||||||
|
return !(this.otherUserId === this.ourUserId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import {HomeServer} from "../../../mocks/HomeServer.js";
|
import {HomeServer} from "../../../mocks/HomeServer.js";
|
||||||
|
@ -225,9 +225,14 @@ export class RoomChannel extends Disposables implements IChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setStartMessage(entry) {
|
setStartMessage(entry) {
|
||||||
const clone = entry.clone();
|
if (!entry.content["m.relates_to"]) {
|
||||||
clone.content["m.relates_to"] = clone.event.content["m.relates_to"];
|
const clone = entry.clone();
|
||||||
this.startMessage = 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;
|
this._initiatedByUs = entry.content.from_device === this.ourDeviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1399,6 +1399,10 @@ button.RoomDetailsView_row::after {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.VerifyEmojisView {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.VerificationCompleteView,
|
.VerificationCompleteView,
|
||||||
.DeviceVerificationView,
|
.DeviceVerificationView,
|
||||||
.SelectMethodView {
|
.SelectMethodView {
|
||||||
@ -1406,6 +1410,13 @@ button.RoomDetailsView_row::after {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SelectMethodView > div,
|
||||||
|
.SelectMethodView__heading,
|
||||||
|
.SelectMethodView__title {
|
||||||
|
width: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.VerificationCompleteView__heading,
|
.VerificationCompleteView__heading,
|
||||||
@ -1427,6 +1438,15 @@ button.RoomDetailsView_row::after {
|
|||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.VerificationCancelledView__title,
|
||||||
|
.VerificationCompleteView__title,
|
||||||
|
.VerifyEmojisView__title,
|
||||||
|
.SelectMethodView__title,
|
||||||
|
.WaitingForOtherUserView__title {
|
||||||
|
font-size: 1.5em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.VerificationCompleteView__title,
|
.VerificationCompleteView__title,
|
||||||
.VerifyEmojisView__title,
|
.VerifyEmojisView__title,
|
||||||
.SelectMethodView__title,
|
.SelectMethodView__title,
|
||||||
@ -1454,6 +1474,7 @@ button.RoomDetailsView_row::after {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.EmojiContainer__emoji {
|
.EmojiContainer__emoji {
|
||||||
@ -1482,3 +1503,10 @@ button.RoomDetailsView_row::after {
|
|||||||
width: 128px;
|
width: 128px;
|
||||||
height: 128px;
|
height: 128px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.SelectMethodView__name {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@ import {RoomDetailsView} from "./RoomDetailsView.js";
|
|||||||
import {MemberListView} from "./MemberListView.js";
|
import {MemberListView} from "./MemberListView.js";
|
||||||
import {LoadingView} from "../../general/LoadingView.js";
|
import {LoadingView} from "../../general/LoadingView.js";
|
||||||
import {MemberDetailsView} from "./MemberDetailsView.js";
|
import {MemberDetailsView} from "./MemberDetailsView.js";
|
||||||
|
import {DeviceVerificationView} from "../verification/DeviceVerificationView";
|
||||||
|
|
||||||
export class RightPanelView extends TemplateView {
|
export class RightPanelView extends TemplateView {
|
||||||
render(t) {
|
render(t) {
|
||||||
@ -39,6 +40,8 @@ export class RightPanelView extends TemplateView {
|
|||||||
return new MemberListView(vm);
|
return new MemberListView(vm);
|
||||||
case "member-details":
|
case "member-details":
|
||||||
return new MemberDetailsView(vm);
|
return new MemberDetailsView(vm);
|
||||||
|
case "verification":
|
||||||
|
return new DeviceVerificationView(vm);
|
||||||
default:
|
default:
|
||||||
return new LoadingView();
|
return new LoadingView();
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,9 @@ export class SelectMethodView extends TemplateView<SelectMethodViewModel> {
|
|||||||
}
|
}
|
||||||
else return t.div([
|
else return t.div([
|
||||||
t.div({ className: "SelectMethodView__heading" }, [
|
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" },
|
t.p({ className: "SelectMethodView__description" }, this.getSubheading(vm)),
|
||||||
vm.i18n`You are about to verify your other device by comparing emojis.`
|
|
||||||
),
|
|
||||||
t.div({ className: "SelectMethodView__actions" }, [
|
t.div({ className: "SelectMethodView__actions" }, [
|
||||||
t.button(
|
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.`;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,7 @@ export class VerificationCompleteView extends TemplateView<VerificationCompleteV
|
|||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
t.p(
|
t.p(
|
||||||
{ className: "VerificationCompleteView__description" },
|
{ className: "VerificationCompleteView__description" }, vm.verificationSuccessfulMessage),
|
||||||
vm.i18n`You successfully verified device ${vm.otherDeviceId}`
|
|
||||||
),
|
|
||||||
t.div({ className: "VerificationCompleteView__actions" }, [
|
t.div({ className: "VerificationCompleteView__actions" }, [
|
||||||
t.button({
|
t.button({
|
||||||
className: {
|
className: {
|
||||||
|
Loading…
Reference in New Issue
Block a user