mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-02-25 06:33:07 +01:00
134 lines
4.2 KiB
React
134 lines
4.2 KiB
React
|
import React, { useState, useEffect, useRef } from 'react';
|
||
|
import './ImportE2ERoomKeys.scss';
|
||
|
|
||
|
import initMatrix from '../../../client/initMatrix';
|
||
|
import cons from '../../../client/state/cons';
|
||
|
import { decryptMegolmKeyFile } from '../../../util/cryptE2ERoomKeys';
|
||
|
|
||
|
import Text from '../../atoms/text/Text';
|
||
|
import IconButton from '../../atoms/button/IconButton';
|
||
|
import Button from '../../atoms/button/Button';
|
||
|
import Input from '../../atoms/input/Input';
|
||
|
import Spinner from '../../atoms/spinner/Spinner';
|
||
|
|
||
|
import CirclePlusIC from '../../../../public/res/ic/outlined/circle-plus.svg';
|
||
|
|
||
|
import { useStore } from '../../hooks/useStore';
|
||
|
|
||
|
function ImportE2ERoomKeys() {
|
||
|
const isMountStore = useStore();
|
||
|
const [keyFile, setKeyFile] = useState(null);
|
||
|
const [status, setStatus] = useState({
|
||
|
isOngoing: false,
|
||
|
msg: null,
|
||
|
type: cons.status.PRE_FLIGHT,
|
||
|
});
|
||
|
const inputRef = useRef(null);
|
||
|
const passwordRef = useRef(null);
|
||
|
|
||
|
async function tryDecrypt(file, password) {
|
||
|
try {
|
||
|
const arrayBuffer = await file.arrayBuffer();
|
||
|
if (isMountStore.getItem()) {
|
||
|
setStatus({
|
||
|
isOngoing: true,
|
||
|
msg: 'Decrypting file...',
|
||
|
type: cons.status.IN_FLIGHT,
|
||
|
});
|
||
|
}
|
||
|
|
||
|
const keys = await decryptMegolmKeyFile(arrayBuffer, password);
|
||
|
if (isMountStore.getItem()) {
|
||
|
setStatus({
|
||
|
isOngoing: true,
|
||
|
msg: 'Decrypting messages...',
|
||
|
type: cons.status.IN_FLIGHT,
|
||
|
});
|
||
|
}
|
||
|
await initMatrix.matrixClient.importRoomKeys(JSON.parse(keys));
|
||
|
if (isMountStore.getItem()) {
|
||
|
setStatus({
|
||
|
isOngoing: false,
|
||
|
msg: 'Successfully imported all keys.',
|
||
|
type: cons.status.SUCCESS,
|
||
|
});
|
||
|
inputRef.current.value = null;
|
||
|
passwordRef.current.value = null;
|
||
|
}
|
||
|
} catch (e) {
|
||
|
if (isMountStore.getItem()) {
|
||
|
setStatus({
|
||
|
isOngoing: false,
|
||
|
msg: e.friendlyText || 'Failed to decrypt keys. Please try again.',
|
||
|
type: cons.status.ERROR,
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const importE2ERoomKeys = () => {
|
||
|
const password = passwordRef.current.value;
|
||
|
if (password === '' || keyFile === null) return;
|
||
|
if (status.isOngoing) return;
|
||
|
|
||
|
tryDecrypt(keyFile, password);
|
||
|
};
|
||
|
|
||
|
const handleFileChange = (e) => {
|
||
|
const file = e.target.files.item(0);
|
||
|
passwordRef.current.value = '';
|
||
|
setKeyFile(file);
|
||
|
setStatus({
|
||
|
isOngoing: false,
|
||
|
msg: null,
|
||
|
type: cons.status.PRE_FLIGHT,
|
||
|
});
|
||
|
};
|
||
|
const removeImportKeysFile = () => {
|
||
|
if (status.isOngoing) return;
|
||
|
inputRef.current.value = null;
|
||
|
passwordRef.current.value = null;
|
||
|
setKeyFile(null);
|
||
|
setStatus({
|
||
|
isOngoing: false,
|
||
|
msg: null,
|
||
|
type: cons.status.PRE_FLIGHT,
|
||
|
});
|
||
|
};
|
||
|
|
||
|
useEffect(() => {
|
||
|
isMountStore.setItem(true);
|
||
|
return () => {
|
||
|
isMountStore.setItem(false);
|
||
|
};
|
||
|
}, []);
|
||
|
|
||
|
return (
|
||
|
<div className="import-e2e-room-keys">
|
||
|
<input ref={inputRef} onChange={handleFileChange} style={{ display: 'none' }} type="file" />
|
||
|
|
||
|
<form className="import-e2e-room-keys__form" onSubmit={(e) => { e.preventDefault(); importE2ERoomKeys(); }}>
|
||
|
{ keyFile !== null && (
|
||
|
<div className="import-e2e-room-keys__file">
|
||
|
<IconButton onClick={removeImportKeysFile} src={CirclePlusIC} tooltip="Remove file" />
|
||
|
<Text>{keyFile.name}</Text>
|
||
|
</div>
|
||
|
)}
|
||
|
{keyFile === null && <Button onClick={() => inputRef.current.click()}>Import keys</Button>}
|
||
|
<Input forwardRef={passwordRef} type="password" placeholder="Password" required />
|
||
|
<Button disabled={status.isOngoing} variant="primary" type="submit">Decrypt</Button>
|
||
|
</form>
|
||
|
{ status.type === cons.status.IN_FLIGHT && (
|
||
|
<div className="import-e2e-room-keys__process">
|
||
|
<Spinner size="small" />
|
||
|
<Text variant="b2">{status.msg}</Text>
|
||
|
</div>
|
||
|
)}
|
||
|
{status.type === cons.status.SUCCESS && <Text className="import-e2e-room-keys__success" variant="b2">{status.msg}</Text>}
|
||
|
{status.type === cons.status.ERROR && <Text className="import-e2e-room-keys__error" variant="b2">{status.msg}</Text>}
|
||
|
</div>
|
||
|
);
|
||
|
}
|
||
|
|
||
|
export default ImportE2ERoomKeys;
|