Backup.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // Copyright 2017-2019 @polkadot/app-accounts authors & contributors
  2. // This software may be modified and distributed under the terms
  3. // of the Apache-2.0 license. See the LICENSE file for details.
  4. import { I18nProps } from '@polkadot/react-components/types';
  5. import FileSaver from 'file-saver';
  6. import React from 'react';
  7. import { AddressRow, Button, Modal, Password, TxComponent } from '@polkadot/react-components';
  8. import { ActionStatus } from '@polkadot/react-components/Status/types';
  9. import keyring from '@polkadot/ui-keyring';
  10. import { isPasswordValid } from '@polkadot/joy-utils/accounts';
  11. import translate from '../translate';
  12. interface Props extends I18nProps {
  13. onClose: () => void;
  14. address: string;
  15. }
  16. interface State {
  17. isPassValid: boolean;
  18. password: string;
  19. }
  20. class Backup extends TxComponent<Props, State> {
  21. public state: State = {
  22. isPassValid: true,
  23. password: ''
  24. };
  25. public render (): React.ReactNode {
  26. const { t } = this.props;
  27. return (
  28. <Modal
  29. className='app--accounts-Modal'
  30. dimmer='inverted'
  31. open
  32. >
  33. <Modal.Header>{t('Backup account')}</Modal.Header>
  34. {this.renderContent()}
  35. {this.renderButtons()}
  36. </Modal>
  37. );
  38. }
  39. private renderButtons (): React.ReactNode {
  40. const { onClose, t } = this.props;
  41. const { isPassValid } = this.state;
  42. return (
  43. <Modal.Actions>
  44. <Button.Group>
  45. <Button
  46. icon='cancel'
  47. isNegative
  48. label={t('Cancel')}
  49. onClick={onClose}
  50. />
  51. <Button.Or />
  52. <Button
  53. icon='download'
  54. isDisabled={!isPassValid}
  55. label={t('Download')}
  56. onClick={this.doBackup}
  57. ref={this.button}
  58. />
  59. </Button.Group>
  60. </Modal.Actions>
  61. );
  62. }
  63. private renderContent (): React.ReactNode {
  64. const { address, t } = this.props;
  65. const { isPassValid, password } = this.state;
  66. return (
  67. <Modal.Content>
  68. <AddressRow
  69. isInline
  70. value={address}
  71. >
  72. <p>{t('An encrypted backup file will be created once you have pressed the "Download" button. This can be used to re-import your account on any other machine.')}</p>
  73. <p>{t('Save this backup file in a secure location. Additionally, the password associated with this account is needed together with this backup file in order to restore your account.')}</p>
  74. <div>
  75. <Password
  76. help={t('The account password as specified when creating the account. This is used to encrypt the backup file and subsequently decrypt it when restoring the account.')}
  77. isError={!isPassValid}
  78. label={t('password')}
  79. onChange={this.onChangePass}
  80. onEnter={this.submit}
  81. tabIndex={0}
  82. value={password}
  83. />
  84. </div>
  85. </AddressRow>
  86. </Modal.Content>
  87. );
  88. }
  89. private doBackup = (): void => {
  90. const { onClose, address, t } = this.props;
  91. const { password } = this.state;
  92. if (!address) {
  93. return;
  94. }
  95. const status: Partial<ActionStatus> = {
  96. action: 'backup'
  97. };
  98. try {
  99. const addressKeyring = address && keyring.getPair(address);
  100. const json = addressKeyring && keyring.backupAccount(addressKeyring, password);
  101. const blob = new Blob([JSON.stringify(json)], { type: 'application/json; charset=utf-8' });
  102. status.account = address;
  103. status.status = blob ? 'success' : 'error';
  104. status.message = t('account backed up');
  105. FileSaver.saveAs(blob, `${address}.json`);
  106. } catch (error) {
  107. this.setState({ isPassValid: true });
  108. console.error(error);
  109. status.status = 'error';
  110. status.message = error.message;
  111. return;
  112. }
  113. onClose();
  114. }
  115. private onChangePass = (password: string): void => {
  116. this.setState({
  117. isPassValid: isPasswordValid(password),
  118. password
  119. });
  120. }
  121. }
  122. export default translate(Backup);