diff --git a/package.json b/package.json index 8eb59eb26..2ad28e7e3 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "@reach/tabs": "^0.1.5", "@reach/tooltip": "^0.2.1", "@types/three": "^0.93.1", + "adm-zip": "^0.4.13", "async-exit-hook": "^2.0.1", "babel-eslint": "^10.0.1", "babel-loader": "^8.0.5", diff --git a/src/ui/component/walletBackup/view.jsx b/src/ui/component/walletBackup/view.jsx index 322cf0dec..c37a3160f 100644 --- a/src/ui/component/walletBackup/view.jsx +++ b/src/ui/component/walletBackup/view.jsx @@ -1,6 +1,10 @@ // @flow import * as React from 'react'; +import { shell, remote } from 'electron'; import Button from 'component/button'; +import CopyableText from 'component/copyableText'; +import AdmZip from 'adm-zip'; +import path from 'path'; type Props = { daemonSettings: { @@ -8,7 +12,78 @@ type Props = { }, }; -class WalletBackup extends React.PureComponent { +type State = { + errorMessage: ?string, + successMessage: ?string, +}; + +class WalletBackup extends React.PureComponent { + constructor(props: Props) { + super(props); + + this.state = { + errorMessage: null, + successMessage: null, + }; + } + + showErrorMessage(message: string) { + this.setState({ errorMessage: message }); + } + + showSuccessMessage(message: string) { + this.setState({ successMessage: message }); + } + + clearMessages() { + this.setState({ errorMessage: null, successMessage: null }); + } + + backupWalletDir(lbryumWalletDir: ?string) { + this.clearMessages(); + + if (!lbryumWalletDir) { + this.showErrorMessage(__('No wallet folder was found.')); + return; + } + + // Colon fails on Windows. Backups should be portable, so replace it on other platforms, too. + const filenameTime = new Date().toISOString().replace(/:/g, '-'); + + const outputFilename = [path.basename(lbryumWalletDir), '-', filenameTime, '.zip'].join(''); + + // Prefer placing backup in user's Downloads folder, then their home folder, and finally + // right next to the lbryum folder itself. + let outputDir = path.dirname(lbryumWalletDir); + if (remote && remote.app) { + outputDir = remote.app.getPath('downloads') || remote.app.getPath('home') || outputDir; + } + + const outputPath = path.join(outputDir, outputFilename); + + const zip = new AdmZip(); + + try { + zip.addLocalFolder(lbryumWalletDir); + } catch (err) { + console.error(err); + this.showErrorMessage(__('The wallet folder could not be added to the zip archive.')); + return; + } + + try { + zip.writeZip(outputPath); + } catch (err) { + console.error(err); + this.showErrorMessage(__('There was a problem writing the zip archive to disk.')); + return; + } + + this.showSuccessMessage(__('Saved zip archive to ' + outputPath)); + + shell.showItemInFolder(outputPath); + } + render() { const { daemonSettings } = this.props; const { wallet_dir: lbryumWalletDir } = daemonSettings; @@ -44,7 +119,7 @@ class WalletBackup extends React.PureComponent { 'However, it is fairly easy to back up manually. To backup your wallet, make a copy of the folder listed below:' )}

-

{lbryumWalletDir}

+

{__( 'Access to these files are equivalent to having access to your credits. Keep any copies you make of your wallet in a secure place.' @@ -55,6 +130,20 @@ class WalletBackup extends React.PureComponent {