// @flow /* eslint-disable import/no-extraneous-dependencies */ import fs from 'fs'; import { promisify } from 'util'; import React, { PureComponent } from 'react'; import styled from 'styled-components'; import electron from 'electron'; import isDev from 'electron-is-dev'; import dateFns from 'date-fns'; import eres from 'eres'; import { Button } from '../components/button'; import { ConfirmDialogComponent } from '../components/confirm-dialog'; import { TextComponent } from '../components/text'; import { InputComponent } from '../components/input'; import { InputLabelComponent } from '../components/input-label'; import { RowComponent } from '../components/row'; import { Clipboard } from '../components/clipboard'; import rpc from '../../services/api'; const HOME_DIR = electron.remote.app.getPath('home'); const Wrapper = styled.div` margin-top: ${props => props.theme.layoutContentPaddingTop}; `; const ModalContent = styled.div` padding: 20px; width: 100%; max-height: 600px; overflow-y: auto; p { word-break: break-all; } `; const Btn = styled(Button)` margin-bottom: 10px; `; const ClipboardButton = styled(Clipboard)` width: 50px; border-radius: ${props => props.theme.boxBorderRadius}; height: 45px; margin-left: 5px; `; const SettingsWrapper = styled.div` margin-bottom: 45px; min-width: 200px; width: 37%; `; const SettingsTitle = styled(TextComponent)` text-transform: uppercase; color: ${props => props.theme.colors.transactionsDate}; font-size: ${props => `${props.theme.fontSize.regular * 0.9}em`}; font-weight: ${props => String(props.theme.fontWeight.bold)}; margin-bottom: 5px; `; const SettingsContent = styled(TextComponent)` margin-bottom: 20px; margin-top: 10px; `; type Key = { zAddress: string, key: string, }; type Props = { addresses: string[], }; type State = { viewKeys: Key[], privateKeys: Key[], importedPrivateKeys: string, successExportViewKeys: boolean, successExportPrivateKeys: boolean, successImportPrivateKeys: boolean, isLoading: boolean, error: string | null, }; export class SettingsView extends PureComponent { state = { viewKeys: [], privateKeys: [], importedPrivateKeys: '', isLoading: false, successExportViewKeys: false, successExportPrivateKeys: false, successImportPrivateKeys: false, error: null, }; exportViewKeys = () => { const { addresses } = this.props; const zAddresses = addresses.filter(addr => addr.startsWith('z')); this.setState({ isLoading: true }); Promise.all( zAddresses.map(async (zAddr) => { const viewKey = await rpc.z_exportviewingkey(zAddr); return { zAddress: zAddr, key: viewKey }; }), ).then((viewKeys) => { this.setState({ viewKeys, successExportViewKeys: true, isLoading: false, }); }); }; exportPrivateKeys = () => { const { addresses } = this.props; const zAddresses = addresses.filter(addr => addr.startsWith('z')); this.setState({ isLoading: true }); Promise.all( zAddresses.map(async (zAddr) => { const privateKey = await rpc.z_exportkey(zAddr); return { zAddress: zAddr, key: privateKey }; }), ).then((privateKeys) => { this.setState({ privateKeys, successExportPrivateKeys: true, isLoading: false, }); }); }; importPrivateKeys = () => { const { importedPrivateKeys } = this.state; if (!importedPrivateKeys) return; const keys = importedPrivateKeys .split('\n') .map(key => key.trim()) .filter(key => !!key); this.setState({ isLoading: true, error: null }); Promise.all(keys.map(key => rpc.z_importkey(key))) .then(() => { this.setState({ successImportPrivateKeys: true, isLoading: false, }); }) .catch((error) => { this.setState({ isLoading: false, error: error.message }); }); }; backupWalletDat = async () => { const backupFileName = `zcash-wallet-backup-${dateFns.format( new Date(), 'YYYY-MM-DD-mm-ss', )}.dat`; electron.remote.dialog.showSaveDialog( undefined, { defaultPath: backupFileName }, async (pathToSave: string) => { if (!pathToSave) return; const zcashDir = isDev ? `${HOME_DIR}/.zcash/testnet3` : HOME_DIR; const walletDatPath = `${zcashDir}/wallet.dat`; const [cannotAccess] = await eres(promisify(fs.access)(walletDatPath)); /* eslint-disable no-alert */ if (cannotAccess) { alert("Couldn't backup the wallet.dat file. You need to back it up manually."); } const [error] = await eres(promisify(fs.copyFile)(walletDatPath, pathToSave)); if (error) { alert("Couldn't backup the wallet.dat file. You need to back it up manually."); } }, ); }; render = () => { const { viewKeys, privateKeys, importedPrivateKeys, successExportViewKeys, successExportPrivateKeys, successImportPrivateKeys, isLoading, error, } = this.state; return ( ( )} onConfirm={this.exportViewKeys} showButtons={!successExportViewKeys} width={750} > {() => ( {successExportViewKeys ? ( viewKeys.map(({ zAddress, key }) => ( <> { event.currentTarget.select(); }} /> )) ) : ( )} )} ( )} onConfirm={this.exportPrivateKeys} showButtons={!successExportPrivateKeys} width={750} > {() => ( {successExportPrivateKeys ? ( privateKeys.map(({ zAddress, key }) => ( <> { event.currentTarget.select(); }} /> )) ) : ( )} )} ( )} onConfirm={this.importPrivateKeys} showButtons={!successImportPrivateKeys} width={900} isLoading={isLoading} > {() => ( this.setState({ importedPrivateKeys: value })} inputType='textarea' rows={10} /> {successImportPrivateKeys && ( )} {error && } )} ); }; }