Files
ThreadNet-Web/src/components/views/toasts/VerificationRequestToast.tsx
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

192 lines
7.4 KiB
TypeScript
Raw Normal View History

2019-11-22 16:00:39 +01:00
/*
2024-09-09 14:57:16 +01:00
Copyright 2024 New Vector Ltd.
2021-03-26 11:13:39 +00:00
Copyright 2019-2021 The Matrix.org Foundation C.I.C.
2019-11-22 16:00:39 +01:00
2024-09-09 14:57:16 +01:00
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
2019-11-22 16:00:39 +01:00
*/
import React from "react";
import {
canAcceptVerificationRequest,
VerificationRequest,
VerificationRequestEvent,
} from "matrix-js-sdk/src/crypto-api";
2021-10-22 17:23:32 -05:00
import { logger } from "matrix-js-sdk/src/logger";
import { Device } from "matrix-js-sdk/src/matrix";
2019-11-22 16:00:39 +01:00
import { _t } from "../../../languageHandler";
2021-06-29 13:11:58 +01:00
import { MatrixClientPeg } from "../../../MatrixClientPeg";
2022-01-05 16:14:44 +01:00
import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases";
2021-06-29 13:11:58 +01:00
import { userLabelForEventRoom } from "../../../utils/KeyVerificationStateObserver";
2020-05-13 20:41:41 -06:00
import dis from "../../../dispatcher/dispatcher";
2020-01-16 20:23:47 +00:00
import ToastStore from "../../../stores/ToastStore";
import Modal from "../../../Modal";
import GenericToast from "./GenericToast";
2021-06-29 13:11:58 +01:00
import { Action } from "../../../dispatcher/actions";
2021-07-01 15:11:18 +01:00
import VerificationRequestDialog from "../dialogs/VerificationRequestDialog";
2022-01-05 16:14:44 +01:00
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { getDeviceCryptoInfo } from "../../../utils/crypto/deviceInfo";
interface IProps {
toastKey: string;
request: VerificationRequest;
}
interface IState {
/** number of seconds left in the timeout counter. Zero if there is no timeout. */
counter: number;
device?: Device;
2021-03-08 16:44:14 +00:00
ip?: string;
}
export default class VerificationRequestToast extends React.PureComponent<IProps, IState> {
private intervalHandle?: number;
2019-11-22 16:00:39 +01:00
2023-02-13 11:39:16 +00:00
public constructor(props: IProps) {
2019-11-22 16:00:39 +01:00
super(props);
this.state = { counter: Math.ceil((props.request.timeout ?? 0) / 1000) };
2019-11-22 16:00:39 +01:00
}
public async componentDidMount(): Promise<void> {
2021-06-29 13:11:58 +01:00
const { request } = this.props;
if (request.timeout && request.timeout > 0) {
2022-11-30 11:32:56 +00:00
this.intervalHandle = window.setInterval(() => {
2021-06-29 13:11:58 +01:00
let { counter } = this.state;
counter = Math.max(0, counter - 1);
2021-06-29 13:11:58 +01:00
this.setState({ counter });
}, 1000);
}
request.on(VerificationRequestEvent.Change, this.checkRequestIsPending);
// We should probably have a separate class managing the active verification toasts,
// rather than monitoring this in the toast component itself, since we'll get problems
// like the toast not going away when the verification is cancelled unless it's the
// one on the top (ie. the one that's mounted).
// As a quick & dirty fix, check the toast is still relevant when it mounts (this prevents
// a toast hanging around after logging in if you did a verification as part of login).
this.checkRequestIsPending();
const otherDeviceId = request.otherDeviceId;
if (request.isSelfVerification && !!otherDeviceId) {
const cli = MatrixClientPeg.safeGet();
const device = await cli.getDevice(otherDeviceId);
2021-03-08 04:46:47 +00:00
this.setState({
ip: device.last_seen_ip,
device: await getDeviceCryptoInfo(cli, cli.getSafeUserId(), otherDeviceId),
2021-03-08 04:46:47 +00:00
});
}
2019-11-22 16:00:39 +01:00
}
public componentWillUnmount(): void {
clearInterval(this.intervalHandle);
2021-06-29 13:11:58 +01:00
const { request } = this.props;
request.off(VerificationRequestEvent.Change, this.checkRequestIsPending);
2019-11-22 16:00:39 +01:00
}
private checkRequestIsPending = (): void => {
2021-06-29 13:11:58 +01:00
const { request } = this.props;
if (!canAcceptVerificationRequest(request)) {
2020-01-16 20:23:47 +00:00
ToastStore.sharedInstance().dismissToast(this.props.toastKey);
2019-11-22 16:00:39 +01:00
}
};
2019-11-22 16:00:39 +01:00
public cancel = (): void => {
2020-01-16 20:23:47 +00:00
ToastStore.sharedInstance().dismissToast(this.props.toastKey);
2019-11-22 16:00:39 +01:00
try {
this.props.request.cancel();
} catch (err) {
2021-10-15 16:30:53 +02:00
logger.error("Error while cancelling verification request", err);
2019-11-22 16:00:39 +01:00
}
2020-06-18 14:32:43 +01:00
};
2019-11-22 16:00:39 +01:00
public accept = async (): Promise<void> => {
2020-01-16 20:23:47 +00:00
ToastStore.sharedInstance().dismissToast(this.props.toastKey);
2021-06-29 13:11:58 +01:00
const { request } = this.props;
2019-11-22 16:00:39 +01:00
// no room id for to_device requests
const cli = MatrixClientPeg.safeGet();
try {
if (request.roomId) {
dis.dispatch<ViewRoomPayload>({
2021-11-25 17:49:43 -03:00
action: Action.ViewRoom,
room_id: request.roomId,
should_peek: false,
metricsTrigger: "VerificationRequest",
});
const member = cli.getUser(request.otherUserId) ?? undefined;
RightPanelStore.instance.setCards(
[
{ phase: RightPanelPhases.RoomSummary },
{ phase: RightPanelPhases.RoomMemberInfo, state: { member } },
{ phase: RightPanelPhases.EncryptionPanel, state: { verificationRequest: request, member } },
],
2022-01-05 16:14:44 +01:00
undefined,
request.roomId,
2022-01-05 16:14:44 +01:00
);
} else {
2022-06-14 17:51:51 +01:00
Modal.createDialog(
VerificationRequestDialog,
{
verificationRequest: request,
2021-03-08 04:46:47 +00:00
onFinished: () => {
request.cancel();
2022-12-12 12:24:14 +01:00
},
2021-03-08 04:46:47 +00:00
},
undefined,
/* priority = */ false,
/* static = */ true,
);
}
await request.accept();
} catch (err) {
logger.error("Failed to accept verification request", err);
}
2019-11-22 16:00:39 +01:00
};
public render(): React.ReactNode {
2021-06-29 13:11:58 +01:00
const { request } = this.props;
2021-03-26 11:13:39 +00:00
let description;
let detail;
if (request.isSelfVerification) {
if (this.state.device) {
description = this.state.device.displayName;
detail = _t("encryption|verification|request_toast_detail", {
deviceId: this.state.device.deviceId,
2021-03-08 16:44:14 +00:00
ip: this.state.ip,
});
}
} else {
const client = MatrixClientPeg.safeGet();
const userId = request.otherUserId;
const roomId = request.roomId;
description = roomId ? userLabelForEventRoom(client, userId, roomId) : userId;
// for legacy to_device verification requests
2021-03-26 11:13:39 +00:00
if (description === userId) {
const user = client.getUser(userId);
if (user && user.displayName) {
description = _t("name_and_id", { name: user.displayName, userId });
}
2019-11-22 16:00:39 +01:00
}
}
const declineLabel =
this.state.counter === 0
? _t("action|ignore")
: _t("encryption|verification|request_toast_decline_counter", { counter: this.state.counter });
return (
<GenericToast
2021-03-26 11:13:39 +00:00
description={description}
detail={detail}
2024-07-30 13:57:15 +01:00
primaryLabel={
request.isSelfVerification || !request.roomId
? _t("encryption|verification|request_toast_accept")
: _t("encryption|verification|request_toast_accept_user")
}
2024-07-30 13:57:15 +01:00
onPrimaryClick={this.accept}
secondaryLabel={declineLabel}
onSecondaryClick={this.cancel}
/>
);
2019-11-22 16:00:39 +01:00
}
}