Files
notesnook/apps/mobile/src/components/RecoveryKeyDialog/index.js

326 lines
8.5 KiB
JavaScript
Raw Normal View History

2021-03-09 10:48:50 +05:00
import React, {createRef} from 'react';
import {Platform, View} from 'react-native';
2020-09-24 17:39:53 +05:00
import QRCode from 'react-native-qrcode-svg';
2021-02-17 15:35:47 +05:00
import Share from 'react-native-share';
2021-03-09 10:48:50 +05:00
import {LOGO_BASE64} from '../../assets/images/assets';
2021-10-23 11:59:15 +05:00
import Clipboard from '@react-native-clipboard/clipboard';
2020-10-28 11:26:58 +05:00
import {
2020-10-28 15:15:35 +05:00
eSendEvent,
2020-10-28 11:26:58 +05:00
eSubscribeEvent,
eUnSubscribeEvent,
2021-10-23 11:59:15 +05:00
ToastEvent
2020-10-28 11:26:58 +05:00
} from '../../services/EventManager';
2021-10-02 10:26:29 +05:00
import {db} from '../../utils/database';
2021-03-09 10:48:50 +05:00
import {eOpenRecoveryKeyDialog, eOpenResultDialog} from '../../utils/Events';
import {sanitizeFilename} from '../../utils/filename';
import {SIZE} from '../../utils/SizeUtils';
2020-11-23 12:32:33 +05:00
import Storage from '../../utils/storage';
2021-03-09 10:48:50 +05:00
import {sleep} from '../../utils/TimeUtils';
2021-12-25 11:16:33 +05:00
import SheetWrapper from '../sheet';
2021-03-09 10:48:50 +05:00
import {Button} from '../Button';
2021-02-10 13:02:57 +05:00
import DialogHeader from '../Dialog/dialog-header';
2020-09-24 17:39:53 +05:00
import Seperator from '../Seperator';
2020-11-20 01:23:05 +05:00
import Paragraph from '../Typography/Paragraph';
2021-10-28 11:32:05 +05:00
import FileViewer from 'react-native-file-viewer';
2021-02-10 21:57:08 +05:00
2021-10-23 11:59:15 +05:00
import * as ScopedStorage from 'react-native-scoped-storage';
2021-02-10 21:57:08 +05:00
let RNFetchBlob;
2020-09-24 17:39:53 +05:00
class RecoveryKeyDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
key: null,
2021-10-23 11:59:15 +05:00
visible: false
2020-09-24 17:39:53 +05:00
};
this.actionSheetRef = createRef();
this.svg = createRef();
2020-10-28 11:26:58 +05:00
this.user;
2020-10-28 15:15:35 +05:00
this.signup = false;
2021-02-10 13:02:57 +05:00
this.tapCount = 0;
2020-09-24 17:39:53 +05:00
}
2021-10-23 11:59:15 +05:00
open = signup => {
2020-10-28 15:15:35 +05:00
if (signup) {
this.signup = true;
}
2020-11-23 12:32:33 +05:00
this.setState(
{
2021-10-23 11:59:15 +05:00
visible: true
2020-11-23 12:32:33 +05:00
},
() => {
2020-12-29 11:25:12 +05:00
this.actionSheetRef.current?.setModalVisible(true);
2021-10-23 11:59:15 +05:00
}
2020-11-23 12:32:33 +05:00
);
2020-09-24 17:39:53 +05:00
};
close = () => {
2021-02-10 13:02:57 +05:00
if (this.tapCount === 0) {
2021-02-20 15:03:02 +05:00
ToastEvent.show({
heading: 'Did you save recovery key?',
message: 'Tap one more time to confirm.',
type: 'success',
2021-10-23 11:59:15 +05:00
context: 'local'
2021-02-20 15:03:02 +05:00
});
2021-02-10 13:02:57 +05:00
this.tapCount++;
return;
}
this.tapCount = 0;
2020-12-29 11:25:12 +05:00
this.actionSheetRef.current?.setModalVisible(false);
2020-11-23 12:32:33 +05:00
sleep(200).then(() => {
this.setState({
2021-10-23 11:59:15 +05:00
visible: false
2020-11-23 12:32:33 +05:00
});
});
2020-10-28 15:52:15 +05:00
if (this.signup) {
this.signup = false;
2020-10-28 15:15:35 +05:00
setTimeout(() => {
eSendEvent(eOpenResultDialog);
2020-10-28 15:15:35 +05:00
}, 500);
}
2020-09-24 17:39:53 +05:00
};
async componentDidMount() {
eSubscribeEvent(eOpenRecoveryKeyDialog, this.open);
}
async componentWillUnmount() {
eUnSubscribeEvent(eOpenRecoveryKeyDialog, this.open);
}
2020-10-28 11:26:58 +05:00
saveQRCODE = async () => {
2021-10-23 11:59:15 +05:00
this.svg.current?.toDataURL(async data => {
2021-02-24 11:00:26 +05:00
try {
let path = await Storage.checkAndCreateDir('/');
RNFetchBlob = require('rn-fetch-blob').default;
2021-03-09 10:48:50 +05:00
let fileName = 'nn_' + this.user.email + '_recovery_key_qrcode';
fileName = sanitizeFilename(fileName, {replacement: '_'});
fileName = fileName + '.png';
2021-02-24 11:00:26 +05:00
if (Platform.OS === 'android') {
2021-10-23 11:59:15 +05:00
await ScopedStorage.createDocument(
fileName,
'image/png',
data,
'base64'
);
} else {
await RNFetchBlob.fs.writeFile(path + fileName, data, 'base64');
2021-02-24 11:00:26 +05:00
}
ToastEvent.show({
heading: 'Recovery key QR-Code saved',
message:
'QR-Code image has been saved to Gallery at ' + path + fileName,
type: 'success',
2021-10-23 11:59:15 +05:00
context: 'local'
2021-02-24 11:00:26 +05:00
});
} catch (e) {}
2020-09-24 17:39:53 +05:00
});
};
2020-10-28 11:26:58 +05:00
saveToTextFile = async () => {
2021-02-17 15:35:47 +05:00
try {
let path = await Storage.checkAndCreateDir('/');
let fileName = 'nn_' + this.user?.email + '_recovery_key';
2021-03-09 10:48:50 +05:00
fileName = sanitizeFilename(fileName, {replacement: '_'});
fileName = fileName + '.txt';
2021-02-20 15:03:02 +05:00
RNFetchBlob = require('rn-fetch-blob').default;
2021-10-23 11:59:15 +05:00
if (Platform.OS === 'android') {
2021-10-28 11:32:05 +05:00
let file = await ScopedStorage.createDocument(
2021-10-23 11:59:15 +05:00
fileName,
'text/plain',
this.state.key,
'utf8'
);
2021-10-28 11:32:05 +05:00
if (!file) return;
path = file.uri;
2021-10-23 11:59:15 +05:00
} else {
await RNFetchBlob.fs.writeFile(path + fileName, this.state.key, 'utf8');
2021-10-28 11:32:05 +05:00
path = path + fileName;
2021-10-23 11:59:15 +05:00
}
2021-02-20 15:03:02 +05:00
ToastEvent.show({
heading: 'Recovery key text file saved',
2021-10-28 11:32:05 +05:00
message: 'Recovery key saved in text file.',
2021-02-20 15:03:02 +05:00
type: 'success',
2021-10-23 11:59:15 +05:00
context: 'local'
2021-02-20 15:03:02 +05:00
});
2021-10-28 11:32:05 +05:00
return path;
2021-02-17 15:35:47 +05:00
} catch (e) {
2021-02-20 15:03:02 +05:00
alert(e.message);
2021-02-17 15:35:47 +05:00
}
2020-10-28 11:26:58 +05:00
};
onOpen = async () => {
2021-02-22 12:02:25 +05:00
let k = await db.user.getEncryptionKey();
this.user = await db.user.getUser();
if (k) {
this.setState({
2021-10-23 11:59:15 +05:00
key: k.key
2021-02-22 12:02:25 +05:00
});
}
2021-02-17 15:35:47 +05:00
};
2020-11-20 02:43:07 +05:00
2021-02-17 15:35:47 +05:00
shareFile = async () => {
let path = await this.saveToTextFile();
if (!path) return;
2021-02-23 16:21:46 +05:00
try {
2021-10-28 11:32:05 +05:00
if (Platform.OS === 'ios') {
Share.open({
url: 'file:/' + result.filePath,
failOnCancel: false
}).catch(console.log);
} else {
FileViewer.open(path, {
showOpenWithDialog: true,
showAppsSuggestions: true,
shareFile: true
}).catch(console.log);
}
2021-02-23 16:21:46 +05:00
} catch (e) {}
2020-10-28 11:26:58 +05:00
};
2020-09-24 17:39:53 +05:00
render() {
const {colors} = this.props;
2020-11-23 12:32:33 +05:00
if (!this.state.visible) return null;
2020-09-24 17:39:53 +05:00
return (
2021-12-25 11:16:33 +05:00
<SheetWrapper
2020-10-28 15:15:35 +05:00
closeOnTouchBackdrop={false}
2020-12-28 12:50:02 +05:00
gestureEnabled={false}
2020-10-28 11:26:58 +05:00
onOpen={this.onOpen}
2020-12-28 12:50:02 +05:00
fwdRef={this.actionSheetRef}>
2020-09-24 17:39:53 +05:00
<View
style={{
2021-02-10 13:02:57 +05:00
width: '100%',
2020-09-24 17:39:53 +05:00
backgroundColor: colors.bg,
justifyContent: 'space-between',
paddingHorizontal: 12,
borderRadius: 10,
2021-10-23 11:59:15 +05:00
paddingTop: 10
2020-09-24 17:39:53 +05:00
}}>
2021-02-10 13:02:57 +05:00
<DialogHeader
2021-02-16 16:11:10 +05:00
title="Your data recovery key"
2021-02-10 13:02:57 +05:00
paragraph="If you forget your password, you can recover your
2021-02-23 16:21:46 +05:00
data and reset your password only using this recovery key."
2021-02-10 13:02:57 +05:00
/>
2020-09-24 23:01:35 +05:00
2020-09-24 17:39:53 +05:00
<View
style={{
2020-09-24 23:01:35 +05:00
backgroundColor: colors.nav,
2020-09-24 17:39:53 +05:00
borderRadius: 5,
2020-09-24 23:01:35 +05:00
padding: 10,
2021-10-23 11:59:15 +05:00
marginTop: 10
2020-09-24 17:39:53 +05:00
}}>
2020-11-20 01:23:05 +05:00
<Paragraph
color={colors.icon}
2021-03-09 10:48:50 +05:00
size={SIZE.sm}
2020-09-24 17:39:53 +05:00
numberOfLines={2}
style={{
width: '100%',
maxWidth: '100%',
paddingRight: 10,
2021-02-20 15:03:02 +05:00
marginBottom: 10,
2021-10-23 11:59:15 +05:00
textAlign: 'center'
2020-09-24 17:39:53 +05:00
}}>
{this.state.key}
2020-11-20 01:23:05 +05:00
</Paragraph>
2021-02-10 13:02:57 +05:00
<Button
onPress={() => {
Clipboard.setString(this.state.key);
2021-02-20 15:03:02 +05:00
ToastEvent.show({
heading: 'Recovery key copied!',
type: 'success',
2021-10-23 11:59:15 +05:00
context: 'local'
2021-02-20 15:03:02 +05:00
});
2021-02-10 13:02:57 +05:00
}}
icon="content-copy"
2021-02-16 16:11:10 +05:00
title="Copy to clipboard"
2021-02-10 13:02:57 +05:00
width="100%"
type="gray"
fontSize={SIZE.md}
height={50}
/>
2020-09-24 23:01:35 +05:00
</View>
<Seperator />
<View
style={{
alignSelf: 'center',
marginBottom: 15,
flexDirection: 'row',
width: '100%',
2021-02-10 13:02:57 +05:00
justifyContent: 'center',
position: 'absolute',
opacity: 0,
2021-10-23 11:59:15 +05:00
zIndex: -1
2020-09-24 23:01:35 +05:00
}}>
{this.state.key ? (
<QRCode
getRef={this.svg}
2021-02-10 13:02:57 +05:00
size={500}
value={this.state.key}
logo={{uri: LOGO_BASE64}}
logoBorderRadius={10}
/>
) : null}
2020-09-24 17:39:53 +05:00
</View>
2021-02-10 13:02:57 +05:00
<Button
2021-02-16 16:11:10 +05:00
title="Save QR-Code to gallery"
2021-02-10 13:02:57 +05:00
onPress={this.saveQRCODE}
width="100%"
type="accent"
fontSize={SIZE.md}
height={50}
/>
2020-09-24 17:39:53 +05:00
<Seperator />
2021-02-10 13:02:57 +05:00
<Button
onPress={this.saveToTextFile}
2021-02-16 16:11:10 +05:00
title="Save to text file"
2021-02-10 13:02:57 +05:00
width="100%"
type="accent"
fontSize={SIZE.md}
height={50}
/>
2020-10-28 15:15:35 +05:00
<Seperator />
2021-02-17 15:35:47 +05:00
<Button
onPress={this.shareFile}
2021-02-22 12:02:25 +05:00
title="Share to Cloud"
2021-02-17 15:35:47 +05:00
width="100%"
type="accent"
fontSize={SIZE.md}
height={50}
/>
<Seperator />
<Paragraph
color={colors.icon}
size={SIZE.sm}
numberOfLines={2}
style={{
width: '100%',
maxWidth: '100%',
marginBottom: 5,
2021-10-23 11:59:15 +05:00
textAlign: 'center'
}}>
Tap twice to confirm you have saved the recovery key.
</Paragraph>
2020-10-28 15:15:35 +05:00
<Button
2021-02-16 16:11:10 +05:00
title="I have saved the key."
2020-10-28 15:15:35 +05:00
width="100%"
height={50}
2021-02-10 13:02:57 +05:00
type="error"
fontSize={SIZE.md}
2020-10-28 15:15:35 +05:00
onPress={this.close}
/>
2020-09-24 17:39:53 +05:00
</View>
2021-12-25 11:16:33 +05:00
</SheetWrapper>
2020-09-24 17:39:53 +05:00
);
}
}
export default RecoveryKeyDialog;