Files
ThreadNet-Web/src/components/views/right_panel/EncryptionPanel.tsx
T

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

177 lines
7.3 KiB
TypeScript
Raw Normal View History

2019-12-10 17:53:51 +01:00
/*
2024-09-09 14:57:16 +01:00
Copyright 2024 New Vector Ltd.
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
2019-12-10 17:53:51 +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-12-10 17:53:51 +01:00
*/
import React, { useCallback, useEffect, useRef, useState } from "react";
import { VerificationPhase, VerificationRequest, VerificationRequestEvent } from "matrix-js-sdk/src/crypto-api";
import { RoomMember, User } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
2019-12-16 18:16:22 +01:00
import EncryptionInfo from "./EncryptionInfo";
import VerificationPanel from "./VerificationPanel";
2021-06-18 16:21:46 +01:00
import { ensureDMExists } from "../../../createRoom";
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
2020-01-28 11:13:09 +00:00
import Modal from "../../../Modal";
2021-06-18 16:21:46 +01:00
import { _t } from "../../../languageHandler";
2022-01-05 16:14:44 +01:00
import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases";
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
2022-03-02 16:33:40 -07:00
import ErrorDialog from "../dialogs/ErrorDialog";
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
2024-10-16 16:43:07 +01:00
import WarningDeprecatedSvg from "../../../../res/img/e2e/warning-deprecated.svg";
import WarningSvg from "../../../../res/img/e2e/warning.svg";
2019-12-10 17:53:51 +01:00
2020-01-28 11:13:09 +00:00
// cancellation codes which constitute a key mismatch
const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
2020-07-18 23:09:11 +05:30
interface IProps {
2021-06-18 16:21:46 +01:00
member: RoomMember | User;
2020-07-18 23:09:11 +05:30
onClose: () => void;
verificationRequest?: VerificationRequest;
2021-07-01 13:45:33 +01:00
verificationRequestPromise?: Promise<VerificationRequest>;
2020-07-18 23:09:11 +05:30
layout: string;
isRoomEncrypted: boolean;
}
const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
const cli = useMatrixClientContext();
const { verificationRequest, verificationRequestPromise, member, onClose, layout, isRoomEncrypted } = props;
const [request, setRequest] = useState(verificationRequest);
2020-02-27 12:35:34 +01:00
// state to show a spinner immediately after clicking "start verification",
// before we have a request
const [isRequesting, setRequesting] = useState(false);
const [phase, doSetPhase] = useState(request?.phase);
const setPhase = (phase: VerificationPhase | undefined): void => {
logger.debug(`EncryptionPanel: phase now ${phase === undefined ? phase : VerificationPhase[phase]}`);
doSetPhase(phase);
};
2020-02-24 13:39:20 +01:00
useEffect(() => {
setRequest(verificationRequest);
if (verificationRequest) {
setRequesting(false);
2020-02-24 13:39:20 +01:00
setPhase(verificationRequest.phase);
}
}, [verificationRequest]);
useEffect(() => {
async function awaitPromise(): Promise<void> {
setRequesting(true);
const requestFromPromise = await verificationRequestPromise;
setRequesting(false);
setRequest(requestFromPromise);
setPhase(requestFromPromise?.phase);
}
if (verificationRequestPromise) {
awaitPromise();
}
}, [verificationRequestPromise]);
// Use a ref to track whether we are already showing the mismatch modal as state may not update fast enough
// if two change events are fired in quick succession like can happen with rust crypto.
const isShowingMismatchModal = useRef(false);
const changeHandler = useCallback(() => {
2020-01-28 11:13:09 +00:00
// handle transitions -> cancelled for mismatches which fire a modal instead of showing a card
if (
!isShowingMismatchModal.current &&
request?.phase === VerificationPhase.Cancelled &&
MISMATCHES.includes(request.cancellationCode ?? "")
) {
isShowingMismatchModal.current = true;
2022-06-14 17:51:51 +01:00
Modal.createDialog(ErrorDialog, {
2024-10-16 16:43:07 +01:00
headerImage: WarningDeprecatedSvg,
title: _t("encryption|messages_not_secure|title"),
2020-01-28 11:13:09 +00:00
description: (
<div>
{_t("encryption|messages_not_secure|heading")}
2020-01-28 11:13:09 +00:00
<ul>
<li>{_t("encryption|messages_not_secure|cause_1")}</li>
<li>{_t("encryption|messages_not_secure|cause_2")}</li>
<li>{_t("encryption|messages_not_secure|cause_3")}</li>
<li>{_t("encryption|messages_not_secure|cause_4")}</li>
2020-01-28 11:13:09 +00:00
</ul>
</div>
),
onFinished: onClose,
});
return; // don't update phase here as we will be transitioning away from this view shortly
}
if (request) {
setPhase(request.phase);
}
}, [onClose, request]);
2022-02-08 13:14:52 +01:00
useTypedEventEmitter(request, VerificationRequestEvent.Change, changeHandler);
const onStartVerification = useCallback(async (): Promise<void> => {
setRequesting(true);
let verificationRequest_: VerificationRequest;
try {
const roomId = await ensureDMExists(cli, member.userId);
if (!roomId) {
throw new Error("Unable to create Room for verification");
}
2023-09-18 18:34:00 +02:00
verificationRequest_ = await cli.getCrypto()!.requestVerificationDM(member.userId, roomId);
} catch (e) {
console.error("Error starting verification", e);
setRequesting(false);
Modal.createDialog(ErrorDialog, {
2024-10-16 16:43:07 +01:00
headerImage: WarningSvg,
title: _t("encryption|verification|error_starting_title"),
description: _t("encryption|verification|error_starting_description"),
});
return;
}
setRequest(verificationRequest_);
setPhase(verificationRequest_.phase);
// Notify the RightPanelStore about this
if (RightPanelStore.instance.currentCard.phase != RightPanelPhases.EncryptionPanel) {
RightPanelStore.instance.pushCard({
phase: RightPanelPhases.EncryptionPanel,
state: { member, verificationRequest: verificationRequest_ },
});
}
if (!RightPanelStore.instance.isOpen) RightPanelStore.instance.togglePanel(null);
}, [cli, member]);
const requested: boolean =
(!request && isRequesting) ||
(!!request &&
(phase === VerificationPhase.Requested || phase === VerificationPhase.Unsent || phase === undefined));
const isSelfVerification = request ? request.isSelfVerification : member.userId === cli.getUserId();
2022-02-08 13:14:52 +01:00
2020-01-28 11:13:09 +00:00
if (!request || requested) {
const initiatedByMe = (!request && isRequesting) || (!!request && request.initiatedByMe);
return (
2020-03-26 16:51:24 +01:00
<EncryptionInfo
isRoomEncrypted={isRoomEncrypted}
onStartVerification={onStartVerification}
member={member}
2020-04-02 17:51:25 +02:00
isSelfVerification={isSelfVerification}
2020-03-26 16:51:24 +01:00
waitingForOtherParty={requested && initiatedByMe}
2020-04-02 17:51:25 +02:00
waitingForNetwork={requested && !initiatedByMe}
inDialog={layout === "dialog"}
/>
);
} else {
return (
2020-01-28 11:13:09 +00:00
<VerificationPanel
isRoomEncrypted={isRoomEncrypted}
2020-01-31 15:04:44 +00:00
layout={layout}
2020-01-28 11:13:09 +00:00
onClose={onClose}
member={member}
request={request}
key={request.transactionId}
inDialog={layout === "dialog"}
phase={phase}
/>
);
}
};
export default EncryptionPanel;