diff --git a/src/app/molecules/import-e2e-room-keys/ImportE2ERoomKeys.jsx b/src/app/molecules/import-e2e-room-keys/ImportE2ERoomKeys.jsx new file mode 100644 index 00000000..3542c01d --- /dev/null +++ b/src/app/molecules/import-e2e-room-keys/ImportE2ERoomKeys.jsx @@ -0,0 +1,108 @@ +import React, { useState, useEffect, useRef } from 'react'; +import './ImportE2ERoomKeys.scss'; +import EventEmitter from 'events'; + +import initMatrix from '../../../client/initMatrix'; +import decryptMegolmKeyFile from '../../../util/decryptE2ERoomKeys'; + +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'; + +const viewEvent = new EventEmitter(); + +async function tryDecrypt(file, password) { + try { + const arrayBuffer = await file.arrayBuffer(); + viewEvent.emit('importing', true); + viewEvent.emit('status', 'Decrypting file...'); + const keys = await decryptMegolmKeyFile(arrayBuffer, password); + + viewEvent.emit('status', 'Decrypting messages...'); + await initMatrix.matrixClient.importRoomKeys(JSON.parse(keys)); + + viewEvent.emit('status', null); + viewEvent.emit('importing', false); + } catch (e) { + viewEvent.emit('status', e.friendlyText || 'Something went wrong!'); + viewEvent.emit('importing', false); + } +} + +function ImportE2ERoomKeys() { + const [keyFile, setKeyFile] = useState(null); + const [status, setStatus] = useState(null); + const [isImporting, setIsImporting] = useState(false); + const inputRef = useRef(null); + const passwordRef = useRef(null); + + useEffect(() => { + const handleIsImporting = (isImp) => setIsImporting(isImp); + const handleStatus = (msg) => setStatus(msg); + viewEvent.on('importing', handleIsImporting); + viewEvent.on('status', handleStatus); + + return () => { + viewEvent.removeListener('importing', handleIsImporting); + viewEvent.removeListener('status', handleStatus); + } + }, []); + + function importE2ERoomKeys() { + const password = passwordRef.current.value; + if (password === '' || keyFile === null) return; + if (isImporting) return; + + tryDecrypt(keyFile, password); + } + + function handleFileChange(e) { + const file = e.target.files.item(0); + passwordRef.current.value = ''; + setKeyFile(file); + setStatus(null); + } + function removeImportKeysFile() { + inputRef.current.value = null; + passwordRef.current.value = null; + setKeyFile(null); + setStatus(null); + } + + useEffect(() => { + if (!isImporting && status === null) { + removeImportKeysFile(); + } + }, [isImporting, status]); + + return ( +
+ + +
{ e.preventDefault(); importE2ERoomKeys(); }}> + { keyFile !== null && ( +
+ + {keyFile.name} +
+ )} + {keyFile === null && } + + +
+ { isImporting && status !== null && ( +
+ + {status} +
+ )} + {!isImporting && status !== null && {status}} +
+ ); +} + +export default ImportE2ERoomKeys; diff --git a/src/app/molecules/import-e2e-room-keys/ImportE2ERoomKeys.scss b/src/app/molecules/import-e2e-room-keys/ImportE2ERoomKeys.scss new file mode 100644 index 00000000..2c9e6312 --- /dev/null +++ b/src/app/molecules/import-e2e-room-keys/ImportE2ERoomKeys.scss @@ -0,0 +1,63 @@ + +.import-e2e-room-keys { + &__file { + display: inline-flex; + align-items: center; + background: var(--bg-surface-low); + border-radius: var(--bo-radius); + box-shadow: var(--bs-surface-border); + + & button { + --parent-height: 46px; + width: var(--parent-height); + height: 100%; + display: flex; + justify-content: center; + align-items: center; + } + + & .ic-raw { + background-color: var(--bg-caution); + transform: rotate(45deg); + } + + & .text { + margin-left: var(--sp-tight); + margin-right: var(--sp-loose); + max-width: 86px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + [dir=rtl] { + margin-right: var(--sp-tight); + margin-left: var(--sp-loose); + } + } + } + + &__form { + display: flex; + margin-top: var(--sp-extra-tight); + + + & .input-container { + flex: 1; + margin: 0 var(--sp-tight); + } + } + + &__process { + margin-top: var(--sp-tight); + display: flex; + justify-content: center; + align-items: center; + & .text { + margin: 0 var(--sp-tight); + } + } + &__error { + margin-top: var(--sp-tight); + color: var(--bg-danger); + } +} \ No newline at end of file