ChangePass.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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 React from 'react';
  6. import { AddressRow, Button, Modal, Password, TxComponent } from '@polkadot/react-components';
  7. import { ActionStatus } from '@polkadot/react-components/Status/types';
  8. import keyring from '@polkadot/ui-keyring';
  9. import { isPasswordValid } from '@polkadot/joy-utils/accounts';
  10. import translate from '../translate';
  11. interface Props extends I18nProps {
  12. address: string;
  13. onClose: () => void;
  14. }
  15. interface State {
  16. isNewValid: boolean;
  17. isOldValid: boolean;
  18. newPass: string;
  19. oldPass: string;
  20. }
  21. class ChangePass extends TxComponent<Props, State> {
  22. public state: State = {
  23. isNewValid: false,
  24. isOldValid: false,
  25. newPass: '',
  26. oldPass: ''
  27. };
  28. public render (): React.ReactNode {
  29. const { t } = this.props;
  30. return (
  31. <Modal
  32. className='app--accounts-Modal'
  33. dimmer='inverted'
  34. open
  35. >
  36. <Modal.Header>{t('Change account password')}</Modal.Header>
  37. {this.renderContent()}
  38. {this.renderButtons()}
  39. </Modal>
  40. );
  41. }
  42. private renderButtons (): React.ReactNode {
  43. const { onClose, t } = this.props;
  44. const { isNewValid, isOldValid } = this.state;
  45. return (
  46. <Modal.Actions>
  47. <Button.Group>
  48. <Button
  49. icon='cancel'
  50. isNegative
  51. label={t('Cancel')}
  52. onClick={onClose}
  53. />
  54. <Button.Or />
  55. <Button
  56. icon='sign-in'
  57. isDisabled={!isNewValid || !isOldValid}
  58. isPrimary
  59. label={t('Change')}
  60. onClick={this.doChange}
  61. ref={this.button}
  62. />
  63. </Button.Group>
  64. </Modal.Actions>
  65. );
  66. }
  67. private renderContent (): React.ReactNode {
  68. const { address, t } = this.props;
  69. const { isNewValid, isOldValid, newPass, oldPass } = this.state;
  70. return (
  71. <Modal.Content>
  72. <AddressRow
  73. isInline
  74. value={address}
  75. >
  76. <p>{t('This will apply to any future use of this account as stored on this browser. Ensure that you securely store this new password and that it is strong and unique to the account.')}</p>
  77. <div>
  78. <Password
  79. autoFocus
  80. help={t('The existing account password as specified when this account was created or when it was last changed.')}
  81. isError={!isOldValid}
  82. label={t('your current password')}
  83. onChange={this.onChangeOld}
  84. tabIndex={1}
  85. value={oldPass}
  86. />
  87. <Password
  88. help={t('The new account password. Once set, all future account unlocks will be performed with this new password.')}
  89. isError={!isNewValid}
  90. label={t('your new password')}
  91. onChange={this.onChangeNew}
  92. onEnter={this.submit}
  93. tabIndex={2}
  94. value={newPass}
  95. />
  96. </div>
  97. </AddressRow>
  98. </Modal.Content>
  99. );
  100. }
  101. private doChange = (): void => {
  102. const { address, onClose, t } = this.props;
  103. const { newPass, oldPass } = this.state;
  104. const status: Partial<ActionStatus> = {
  105. action: 'changePassword'
  106. };
  107. try {
  108. const account = address && keyring.getPair(address);
  109. if (!account) {
  110. status.message = t(`No keypair found for this address ${address}`);
  111. return;
  112. }
  113. try {
  114. if (!account.isLocked) {
  115. account.lock();
  116. }
  117. account.decodePkcs8(oldPass);
  118. } catch (error) {
  119. this.setState({ isOldValid: false });
  120. status.message = error.message;
  121. return;
  122. }
  123. try {
  124. keyring.encryptAccount(account, newPass);
  125. status.account = address;
  126. status.status = 'success';
  127. status.message = t('password changed');
  128. } catch (error) {
  129. this.setState({ isNewValid: false });
  130. status.status = 'error';
  131. status.message = error.message;
  132. return;
  133. }
  134. } catch (error) {
  135. status.message = error.message;
  136. return;
  137. }
  138. onClose();
  139. }
  140. private onChangeNew = (newPass: string): void => {
  141. this.setState({
  142. isNewValid: this.validatePass(newPass),
  143. newPass
  144. });
  145. }
  146. private onChangeOld = (oldPass: string): void => {
  147. this.setState({
  148. isOldValid: this.validatePass(oldPass),
  149. oldPass
  150. });
  151. }
  152. private validatePass (password: string): boolean {
  153. return isPasswordValid(password);
  154. }
  155. }
  156. export default translate(ChangePass);