You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/ts/components/settings/section/CategoryRecoveryPassword.tsx

168 lines
5.6 KiB
TypeScript

import { isEmpty } from 'lodash';
import { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import useMount from 'react-use/lib/useMount';
import styled from 'styled-components';
import { usePasswordModal } from '../../../hooks/usePasswordModal';
import { mnDecode } from '../../../session/crypto/mnemonic';
import { ToastUtils } from '../../../session/utils';
import { showSettingsSection } from '../../../state/ducks/section';
import { getTheme } from '../../../state/selectors/theme';
import { THEME_GLOBALS, getThemeValue } from '../../../themes/globals';
import { getCurrentRecoveryPhrase } from '../../../util/storage';
import { SessionQRCode } from '../../SessionQRCode';
import { AnimatedFlex } from '../../basic/Flex';
import { SessionHtmlRenderer } from '../../basic/SessionHTMLRenderer';
import { SpacerMD, SpacerSM } from '../../basic/Text';
import { SessionIconButton } from '../../icon';
import { SessionSettingsItemWrapper } from '../SessionSettingListItem';
const StyledSettingsItemContainer = styled.div`
p {
font-size: var(--font-size-md);
line-height: 30px;
margin: 0;
}
`;
const StyledRecoveryPassword = styled(AnimatedFlex)<{ color: string }>`
font-family: var(--font-mono);
font-size: var(--font-size-sm);
text-align: justify;
user-select: text;
border: 2px solid var(--text-secondary-color);
border-radius: 11px;
padding: var(--margins-sm) var(--margins-sm) var(--margins-sm) var(--margins-md);
margin: 0;
max-width: fit-content;
color: ${props => props.color};
`;
export const SettingsCategoryRecoveryPassword = () => {
const [loadingSeed, setLoadingSeed] = useState(true);
const [recoveryPhrase, setRecoveryPhrase] = useState('');
const [hexEncodedSeed, setHexEncodedSeed] = useState('');
const [isQRVisible, setIsQRVisible] = useState(false);
const dispatch = useDispatch();
const { hasPassword, passwordValid } = usePasswordModal({
title: window.i18n('sessionRecoveryPassword'),
onClose: () => {
dispatch(showSettingsSection('privacy'));
},
});
const theme = useSelector(getTheme);
const copyRecoveryPhrase = (recoveryPhraseToCopy: string) => {
window.clipboard.writeText(recoveryPhraseToCopy);
ToastUtils.pushCopiedToClipBoard();
};
const fetchRecoverPhrase = () => {
const newRecoveryPhrase = getCurrentRecoveryPhrase();
setRecoveryPhrase(newRecoveryPhrase);
if (!isEmpty(newRecoveryPhrase)) {
setHexEncodedSeed(mnDecode(newRecoveryPhrase, 'english'));
}
setLoadingSeed(false);
};
useMount(() => {
if (!hasPassword || (hasPassword && passwordValid)) {
fetchRecoverPhrase();
}
});
if ((hasPassword && !passwordValid) || loadingSeed) {
return null;
}
return (
<StyledSettingsItemContainer>
<SessionSettingsItemWrapper
title={window.i18n('sessionRecoveryPassword')}
icon={{
iconType: 'recoveryPasswordFill',
iconSize: 16,
iconColor: 'var(--text-primary-color)',
}}
description={
<SessionHtmlRenderer tag="p" html={window.i18n('recoveryPasswordDescription')} />
}
inline={false}
>
<SpacerMD />
{isQRVisible ? (
<SessionQRCode
id={'session-recovery-passwod'}
value={hexEncodedSeed}
size={240}
backgroundColor={getThemeValue(
theme.includes('dark') ? '--text-primary-color' : '--background-primary-color'
)}
foregroundColor={getThemeValue(
theme.includes('dark') ? '--background-primary-color' : '--text-primary-color'
)}
logoImage={'./images/session/qr/shield.svg'}
logoWidth={56}
logoHeight={56}
logoIsSVG={true}
theme={theme}
/>
) : (
<StyledRecoveryPassword
container={true}
flexDirection={'row'}
justifyContent={'space-between'}
alignItems={'center'}
width={'100%'}
color={theme.includes('dark') ? 'var(--primary-color)' : 'var(--text-primary-color)'}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: THEME_GLOBALS['--default-duration-seconds'] }}
data-testid="recovery-phrase-seed-modal"
>
{recoveryPhrase}
<SpacerSM />
<SessionIconButton
aria-label={'copy to clipboard button'}
iconType={'copy'}
iconSize={'huge'}
iconColor={'var(--text-primary-color)'}
onClick={() => {
if (isEmpty(recoveryPhrase)) {
return;
}
copyRecoveryPhrase(recoveryPhrase);
}}
/>
</StyledRecoveryPassword>
)}
<SpacerMD />
<SessionIconButton
aria-label={isQRVisible ? 'show password button' : 'show qr code button'}
iconType={isQRVisible ? 'password' : 'qr'}
iconSize={isQRVisible ? 48 : 'huge'}
iconColor={'var(--text-primary-color)'}
onClick={() => {
setIsQRVisible(!isQRVisible);
}}
padding="0"
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
gap: isQRVisible ? undefined : 'var(--margins-xs)',
marginLeft: isQRVisible ? '-8px' : undefined,
}}
>
{isQRVisible ? 'View as Password' : 'View QR'}
</SessionIconButton>
{/* TODO Permenantly hide button */}
</SessionSettingsItemWrapper>
</StyledSettingsItemContainer>
);
};