-
Notifications
You must be signed in to change notification settings - Fork 96
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5595 from LiskHQ/5593-add-private-key
Add private key import feature
- Loading branch information
Showing
22 changed files
with
1,093 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
src/modules/account/components/AddAccountByPrivateKey/AddAccountByPrivateKey.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
@import '../../../../../setup/react/app/mixins.css'; | ||
|
||
.addAccount { | ||
align-items: center; | ||
display: flex; | ||
flex-grow: 1; | ||
margin: 0; | ||
min-height: 100%; | ||
justify-content: center; | ||
text-align: center; | ||
width: 100%; | ||
} | ||
|
||
.wrapper { | ||
align-items: center; | ||
display: flex; | ||
flex-direction: column; | ||
padding: 20px 24px; | ||
} |
55 changes: 55 additions & 0 deletions
55
src/modules/account/components/AddAccountByPrivateKey/AddAccountByPrivateKey.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* eslint-disable max-statements */ | ||
import React, { useRef, useState } from 'react'; | ||
import { useHistory, useLocation } from 'react-router-dom'; | ||
import grid from 'flexboxgrid/dist/flexboxgrid.css'; | ||
import MultiStep from 'src/modules/common/components/MultiStep'; | ||
import SetPasswordSuccess from 'src/modules/auth/components/SetPasswordSuccess'; | ||
import PrivateKeyForm from '@auth/components/PrivateKeyForm'; | ||
import routes from 'src/routes/routes'; | ||
import { useCurrentAccount, useAccounts } from '@account/hooks'; | ||
import ImportPrivateKeyForm from '../ImportPrivateKeyForm'; | ||
import styles from './AddAccountByPrivateKey.css'; | ||
|
||
const AddAccountByPrivateKey = () => { | ||
const history = useHistory(); | ||
const { search } = useLocation(); | ||
const multiStepRef = useRef(null); | ||
const [privateKey, setPrivateKey] = useState(null); | ||
const [currentAccount, setCurrentAccount] = useCurrentAccount(); | ||
const { setAccount } = useAccounts(); | ||
|
||
const queryParams = new URLSearchParams(search); | ||
const referrer = queryParams.get('referrer'); | ||
|
||
const onAddAccount = (privateKeyData) => { | ||
setPrivateKey(privateKeyData); | ||
multiStepRef?.current?.next(); | ||
}; | ||
|
||
/* istanbul ignore next */ | ||
const onSetPassword = (account) => { | ||
setCurrentAccount(account, null, false); | ||
setAccount(account); | ||
multiStepRef?.current?.next(); | ||
}; | ||
|
||
/* istanbul ignore next */ | ||
const onPasswordSetComplete = () => { | ||
history.push(referrer || routes.wallet.path); | ||
}; | ||
|
||
return ( | ||
<div className={`${styles.addAccount} ${grid.row}`}> | ||
<MultiStep navStyles={{ multiStepWrapper: styles.wrapper }} ref={multiStepRef}> | ||
<ImportPrivateKeyForm onAddAccount={onAddAccount} /> | ||
<PrivateKeyForm | ||
privateKey={privateKey} | ||
onSubmit={onSetPassword} | ||
/> | ||
<SetPasswordSuccess encryptedPhrase={currentAccount} onClose={onPasswordSetComplete} /> | ||
</MultiStep> | ||
</div> | ||
); | ||
}; | ||
|
||
export default AddAccountByPrivateKey; |
85 changes: 85 additions & 0 deletions
85
src/modules/account/components/AddAccountByPrivateKey/AddAccountByPrivateKey.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { createEvent, fireEvent, screen, waitFor } from '@testing-library/react'; | ||
import mockSavedAccounts from '@tests/fixtures/accounts'; | ||
import { mockOnMessage } from '@setup/config/setupJest'; | ||
import * as reactRedux from 'react-redux'; | ||
import { renderWithCustomRouter } from 'src/utils/testHelpers'; | ||
import AddAccountByPrivateKey from './AddAccountByPrivateKey'; | ||
|
||
const privateKey = | ||
'e005805e731d324ec6f083f7ec31967e60cda674cd09f51c323fce63a933e0dadd2df9b2b007bd8a2387f4e652517d6e094cdb54edf0c67b06d4786f5ecf964d'; | ||
const accountPassword = 'Password1$'; | ||
const userName = 'user1'; | ||
const mockSetAccount = jest.fn(); | ||
|
||
jest.mock('react-i18next'); | ||
jest.mock('@account/hooks', () => ({ | ||
useAccounts: jest.fn(() => ({ | ||
accounts: mockSavedAccounts, | ||
setAccount: jest.fn(), | ||
})), | ||
useCurrentAccount: jest.fn(() => [mockSavedAccounts[0], mockSetAccount]), | ||
useEncryptAccount: jest.fn().mockReturnValue({ | ||
encryptAccount: jest.fn().mockResolvedValue({ | ||
privateKey, | ||
}), | ||
}), | ||
})); | ||
|
||
reactRedux.useSelector = jest.fn().mockReturnValue(mockSavedAccounts[0]); | ||
|
||
const props = { | ||
history: { push: jest.fn() }, | ||
login: jest.fn(), | ||
}; | ||
|
||
beforeEach(() => { | ||
renderWithCustomRouter(AddAccountByPrivateKey, props); | ||
}); | ||
|
||
describe('Add account by private key flow', () => { | ||
it('Should successfully go though the flow', async () => { | ||
expect(screen.getByText('Add your account')).toBeTruthy(); | ||
expect( | ||
screen.getByText('Enter your private key to manage your account.') | ||
).toBeTruthy(); | ||
expect(screen.getByText('Continue to set password')).toBeTruthy(); | ||
expect(screen.getByText('Go back')).toBeTruthy(); | ||
|
||
const inputField = screen.getByTestId('recovery-1'); | ||
const pasteEvent = createEvent.paste(inputField, { | ||
clipboardData: { | ||
getData: () => | ||
'e005805e731d324ec6f083f7ec31967e60cda674cd09f51c323fce63a933e0dadd2df9b2b007bd8a2387f4e652517d6e094cdb54edf0c67b06d4786f5ecf964d', | ||
}, | ||
}); | ||
|
||
fireEvent(inputField, pasteEvent); | ||
fireEvent.click(screen.getByText('Continue to set password')); | ||
|
||
const password = screen.getByTestId('password'); | ||
const cPassword = screen.getByTestId('cPassword'); | ||
const accountName = screen.getByTestId('accountName'); | ||
const hasAgreed = screen.getByTestId('hasAgreed'); | ||
|
||
fireEvent.change(password, { target: { value: accountPassword } }); | ||
fireEvent.change(cPassword, { target: { value: accountPassword } }); | ||
fireEvent.change(accountName, { target: { value: userName } }); | ||
fireEvent.click(hasAgreed); | ||
fireEvent.click(screen.getByText('Save Account')); | ||
|
||
await waitFor(() => { | ||
expect(mockOnMessage).toHaveBeenCalledWith({ | ||
accountName: 'user1', | ||
cPassword: 'Password1$', | ||
customDerivationPath: "m/44'/134'/0'", | ||
enableAccessToLegacyAccounts: undefined, | ||
hasAgreed: true, | ||
password: 'Password1$', | ||
privateKey: { | ||
isValid: true, | ||
value: 'e005805e731d324ec6f083f7ec31967e60cda674cd09f51c323fce63a933e0dadd2df9b2b007bd8a2387f4e652517d6e094cdb54edf0c67b06d4786f5ecf964d', | ||
}, | ||
}); | ||
}); | ||
}); | ||
}); |
4 changes: 4 additions & 0 deletions
4
src/modules/account/components/AddAccountByPrivateKey/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/* istanbul ignore file */ | ||
import AddAccountByPrivateKey from './AddAccountByPrivateKey'; | ||
|
||
export default AddAccountByPrivateKey; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 162 additions & 0 deletions
162
src/modules/account/components/ImportPrivateKeyForm/ImportPrivateKeyForm.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
@import '../../../../../setup/react/app/mixins.css'; | ||
|
||
:root { | ||
--login-title-font-size: 24px; | ||
} | ||
|
||
.wrapper { | ||
width: 100%; | ||
} | ||
|
||
.addAccount { | ||
align-items: center; | ||
display: flex; | ||
flex-grow: 1; | ||
margin: 0; | ||
min-height: 100%; | ||
justify-content: center; | ||
text-align: center; | ||
width: 100%; | ||
flex-direction: column; | ||
} | ||
|
||
.titleHolder { | ||
text-align: center; | ||
|
||
& > .stepsLabel { | ||
@mixin contentSmallest; | ||
|
||
color: var(--color-slate-gray); | ||
display: block; | ||
margin-bottom: 10px; | ||
text-transform: uppercase; | ||
} | ||
|
||
& > h1 { | ||
@mixin headingLarge; | ||
|
||
display: flex; | ||
justify-content: center; | ||
margin: 0 0 16px; | ||
font-size: var(--font-size-h3); | ||
line-height: var(--font-size-h3); | ||
} | ||
|
||
& > p { | ||
@mixin contentLargest; | ||
|
||
color: var(--color-slate-gray); | ||
margin: 0; | ||
letter-spacing: 1px; | ||
} | ||
} | ||
|
||
.buttonsHolder { | ||
align-items: center; | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
margin: 30px auto 0; | ||
max-width: 430px; | ||
width: 100%; | ||
|
||
& a { | ||
width: 100%; | ||
} | ||
} | ||
|
||
.inputFields { | ||
& > fieldset { | ||
align-items: flex-start; | ||
display: flex; | ||
flex-direction: column; | ||
width: 100%; | ||
border: none; | ||
text-align: left; | ||
|
||
& > label { | ||
margin-bottom: 7px; | ||
color: var(--color-content); | ||
font-size: var(--font-size-small-secondary); | ||
|
||
& .notice { | ||
color: var(--color-primary); | ||
} | ||
} | ||
} | ||
|
||
& > * { | ||
max-width: 665px; | ||
margin: 30px auto 0px; | ||
} | ||
} | ||
|
||
.link { | ||
@mixin contentLarge bold; | ||
|
||
color: var(--color-link); | ||
cursor: pointer; | ||
display: inline-block; | ||
margin-bottom: 20px; | ||
text-align: center; | ||
text-decoration: none; | ||
|
||
&:hover { | ||
text-decoration: underline; | ||
} | ||
} | ||
|
||
form { | ||
& .button, | ||
& .backLink { | ||
@mixin contentLargest bold; | ||
|
||
width: 100%; | ||
display: flex; | ||
flex-direction: row; | ||
justify-content: center; | ||
align-items: center; | ||
} | ||
|
||
& .backLink { | ||
margin-top: 24px; | ||
} | ||
} | ||
|
||
.labelWrapper { | ||
display: flex; | ||
|
||
& .fieldGroup { | ||
font-size: 16px; | ||
color: var(--color-colecti-dark-blue); | ||
|
||
&:last-child { | ||
margin-left: 10px; | ||
} | ||
|
||
&.checkboxField { | ||
align-items: flex-start; | ||
display: flex; | ||
|
||
& > div:last-child { | ||
flex-basis: calc(100% - 25px); | ||
margin-left: auto; | ||
} | ||
|
||
& .checkmark { | ||
margin-top: 3px; | ||
} | ||
|
||
& .checkbox { | ||
margin-right: 10px; | ||
} | ||
} | ||
} | ||
|
||
& .discreetMode { | ||
& span { | ||
font-size: 16px; | ||
color: var(--color-colecti-dark-blue); | ||
} | ||
} | ||
} |
Oops, something went wrong.