Skip to content

Commit a001d53

Browse files
committed
Unlock wallet screen is added to unlock with spending password
1 parent aaf6601 commit a001d53

File tree

11 files changed

+258
-76
lines changed

11 files changed

+258
-76
lines changed

examples/wallet/app/Routes.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import ChooseRestoreOrImport from './containers/ChooseRestoreOrImport';
1010
import Delegate from './pages/Delegate';
1111
import Index from './containers/Index';
1212
import InputKeys from './containers/InputKeys';
13+
import UnlockWallet from './containers/UnlockWallet';
1314

1415
export default () => (
1516
<App>
@@ -19,6 +20,7 @@ export default () => (
1920
<Route path={routes.STAKING} component={Delegate} />
2021
<Route path={routes.SETTINGS} component={Settings} />
2122
<Route path={routes.INPUT_KEYS} component={InputKeys} />
23+
<Route path={routes.UNLOCK_WALLET} component={UnlockWallet} />
2224
<Route
2325
path={routes.CHOOSE_RESTORE_OR_IMPORT}
2426
component={ChooseRestoreOrImport}

examples/wallet/app/actions/account.js

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import type {
66
AppState,
77
Thunk,
88
AccountKeys,
9-
AccountState
9+
AccountState,
10+
SpendingPassword
1011
} from '../reducers/types';
1112
import type {
1213
Amount,
@@ -30,12 +31,20 @@ import {
3031
getTransactions
3132
} from '../utils/nodeConnection';
3233
import { isValidMnemonic, createSeedFromMnemonic } from '../utils/mnemonic';
33-
import { saveAccountInfoInDEN, saveSpendingPassword } from '../utils/storage';
34+
import {
35+
saveAccountInfoInDEN,
36+
saveSpendingPassword,
37+
readAccountKeysFromDEN
38+
} from '../utils/storage';
3439

3540
import routes from '../constants/routes.json';
3641

3742
export type SetKeysAction = { type: 'SET_KEYS' } & AccountKeys;
43+
export type SetKeysWithSpendingPasswordAction = {
44+
type: 'SET_SPENDING_PASSWORD'
45+
} & SpendingPassword;
3846
export const SET_KEYS = 'SET_KEYS';
47+
export const SET_SPENDING_PASSWORD = 'SET_SPENDING_PASSWORD';
3948

4049
export function setAccount(
4150
privateKey: string,
@@ -48,6 +57,29 @@ export function setAccount(
4857
};
4958
}
5059

60+
export function setKeysWithSpendingPassword(
61+
spendingPassword: ?string = ''
62+
): Thunk<SetKeysAction> {
63+
return function setKeysWithSpendingPasswordThunk(dispatch) {
64+
const accountKeys = readAccountKeysFromDEN(spendingPassword);
65+
if (accountKeys) {
66+
const spendingPasswordKeys = {
67+
walletId: 'wallet01',
68+
spendingPassword
69+
};
70+
dispatch({
71+
type: SET_SPENDING_PASSWORD,
72+
...spendingPasswordKeys
73+
});
74+
75+
return getAccountFromPrivateKey(accountKeys.privateKey).then(keys =>
76+
curry(initializeKeysAndRedirect)(dispatch, keys, spendingPassword)
77+
);
78+
}
79+
throw new Error('Invalid password');
80+
};
81+
}
82+
5183
export function setAccountFromPrivateKey(
5284
privateKey: string
5385
): Thunk<SetKeysAction> {

examples/wallet/app/actions/router.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@ import type { Address } from '../models';
55
import routes from '../constants/routes';
66
import { setAccountFromPrivateKey } from './account';
77

8-
import { readAccountKeysFromDEN } from '../utils/storage';
8+
import {
9+
isSpedingPasswordCreated,
10+
readAccountKeysFromDEN
11+
} from '../utils/storage';
912

1013
// eslint-disable-next-line import/prefer-default-export
1114
export const redirectToFirstAppPage = () => {
1215
return (dispatch: Dispatch, getState: GetState) => {
16+
if (isSpedingPasswordCreated()) return dispatch(push(routes.UNLOCK_WALLET));
17+
1318
const accountKeys = readAccountKeysFromDEN('manteca');
1419
if (accountKeys !== undefined) {
1520
return dispatch(setAccountFromPrivateKey(accountKeys.privateKey));

examples/wallet/app/components/RestoreWalletFromMnemonic.js

Lines changed: 65 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,41 @@ export default ({ setAccountFromMnemonic }: Props) => {
2020

2121
const handleSubmitMnemonic = function handleSubmitMnemonic(event) {
2222
event.preventDefault();
23-
if (
24-
isValidMnemonic(newMnemonicPhrase) &&
25-
checkValidPassword(password, confirmPassword)
26-
) {
23+
if (mustCreateSpendingPassword) {
24+
if (
25+
isValidMnemonic(newMnemonicPhrase) &&
26+
checkValidPassword(password, confirmPassword)
27+
) {
28+
return Promise.all([
29+
setAccountFromMnemonic(
30+
newMnemonicPhrase,
31+
newMnemonicPassword,
32+
password
33+
)
34+
]);
35+
}
36+
}
37+
if (isValidMnemonic(newMnemonicPhrase)) {
2738
return Promise.all([
28-
setAccountFromMnemonic(newMnemonicPhrase, newMnemonicPassword, password)
39+
setAccountFromMnemonic(newMnemonicPhrase, newMnemonicPassword, '')
2940
]);
3041
}
42+
3143
setIsMnemonicValid(false);
3244
};
3345

46+
const handleCheckCreateSpendingPassword = function handleCheckCreateSpendingPassword(
47+
evt
48+
) {
49+
setMustCreateSpendingPassword(evt.target.checked);
50+
setHiddenSpendingPassword(!evt.target.checked);
51+
};
52+
3453
const [isMnemonicValid, setIsMnemonicValid] = useState(true);
54+
const [hiddenSpendingPassword, setHiddenSpendingPassword] = useState(false);
55+
const [mustCreateSpendingPassword, setMustCreateSpendingPassword] = useState(
56+
true
57+
);
3558

3659
const [newMnemonicPhrase, setNewMnemonicPhrase] = useState('');
3760

@@ -97,37 +120,43 @@ export default ({ setAccountFromMnemonic }: Props) => {
97120
onChange={event => setNewMnemonicPassword(event.target.value)}
98121
className="mt-3"
99122
/>
100-
<Form.Label>
101-
Create a password to store your settings securely in an encrypted
102-
storage
103-
</Form.Label>
104-
<Form.Control
105-
type="password"
106-
id="password"
107-
name="password"
108-
placeholder="New password (min 8 chars)"
109-
value={password}
110-
isInvalid={!isValidPassword}
111-
onChange={event => setPassword(event.target.value)}
112-
/>
113-
<Form.Label className="text-danger" hidden={isValidPassword}>
114-
<code>The password must have at least 8 chars.</code>
115-
</Form.Label>
116-
<Form.Control
117-
type="password"
118-
name="confirmPassword"
119-
id="confirmPassword"
120-
placeholder="Confirm password"
121-
value={confirmPassword}
122-
onChange={event => setConfirmPassword(event.target.value)}
123-
className="mt-3"
124-
/>
125-
<Form.Label
126-
className="text-danger"
127-
hidden={arePasswordAndConfirmationEqual}
128-
>
129-
<code>password and confirmation must be the same.</code>
130-
</Form.Label>
123+
<Form.Group controlId="formCreateSpendingPassword" className="mt-4">
124+
<Form.Check
125+
type="switch"
126+
label="Create a password to store your settings securely in an encrypted
127+
storage"
128+
onChange={event => handleCheckCreateSpendingPassword(event)}
129+
/>
130+
</Form.Group>
131+
<Form.Group hidden={hiddenSpendingPassword}>
132+
<Form.Control
133+
type="password"
134+
id="password"
135+
name="password"
136+
placeholder="New password (min 8 chars)"
137+
value={password}
138+
isInvalid={!isValidPassword}
139+
onChange={event => setPassword(event.target.value)}
140+
/>
141+
<Form.Label className="text-danger" hidden={isValidPassword}>
142+
<code>The password must have at least 8 chars.</code>
143+
</Form.Label>
144+
<Form.Control
145+
type="password"
146+
name="confirmPassword"
147+
id="confirmPassword"
148+
placeholder="Confirm password"
149+
value={confirmPassword}
150+
onChange={event => setConfirmPassword(event.target.value)}
151+
className="mt-3"
152+
/>
153+
<Form.Label
154+
className="text-danger"
155+
hidden={arePasswordAndConfirmationEqual}
156+
>
157+
<code>password and confirmation must be the same.</code>
158+
</Form.Label>
159+
</Form.Group>
131160
</Form.Group>
132161
<Row className="justify-content-between">
133162
<Button variant="secondary" type="button">

examples/wallet/app/components/RestoreWalletFromPrivateKey.js

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,22 @@ export default ({ setAccount }: Props) => {
1717
event
1818
) {
1919
event.preventDefault();
20-
if (checkValidPassword(password, confirmPassword)) {
21-
setAccount(newPrivateKey, password);
20+
if (mustCreateSpendingPassword) {
21+
if (checkValidPassword(password, confirmPassword)) {
22+
setAccount(newPrivateKey, password);
23+
}
24+
} else {
25+
setAccount(newPrivateKey, '');
2226
}
2327
};
2428

29+
const handleCheckCreateSpendingPassword = function handleCheckCreateSpendingPassword(
30+
evt
31+
) {
32+
setMustCreateSpendingPassword(evt.target.checked);
33+
setHiddenSpendingPassword(!evt.target.checked);
34+
};
35+
2536
const checkValidPassword = function checkValidPassword(pass, confirmation) {
2637
if (!pass && !confirmation) return true;
2738
if (pass.length < 8) {
@@ -40,6 +51,10 @@ export default ({ setAccount }: Props) => {
4051

4152
const [isValidPassword, setIsValidPassword] = useState(true);
4253
const [newPrivateKey, setNewPrivateKey] = useState('');
54+
const [mustCreateSpendingPassword, setMustCreateSpendingPassword] = useState(
55+
true
56+
);
57+
const [hiddenSpendingPassword, setHiddenSpendingPassword] = useState(false);
4358

4459
const [
4560
arePasswordAndConfirmationEqual,
@@ -69,37 +84,46 @@ export default ({ setAccount }: Props) => {
6984
ed25519e_sk15psr45hyqnpwcl8xd4lv0m32prenhh8kcltgte2305h5jgynndxect9274j0am0qmmd0snjuadnm6xkgssnkn2njvkg8et8qg0vevsgnwvmpl
7085
</code>
7186
</Form.Text>
72-
<Form.Label>
73-
Create a password to store your settings securely in an encrypted
74-
storage
75-
</Form.Label>
76-
<Form.Control
77-
type="password"
78-
id="password"
79-
name="password"
80-
placeholder="New password (min 8 chars)"
81-
value={password}
82-
isInvalid={!isValidPassword}
83-
onChange={event => setPassword(event.target.value)}
84-
/>
85-
<Form.Label className="text-danger" hidden={isValidPassword}>
86-
<code>The password must have at least 8 chars.</code>
87-
</Form.Label>
88-
<Form.Control
89-
type="password"
90-
name="confirmPassword"
91-
id="confirmPassword"
92-
placeholder="Confirm password"
93-
value={confirmPassword}
94-
onChange={event => setConfirmPassword(event.target.value)}
95-
className="mt-3"
96-
/>
97-
<Form.Label
98-
className="text-danger"
99-
hidden={arePasswordAndConfirmationEqual}
87+
<Form.Group
88+
controlId="formCreateSpendingPasswordCheck"
89+
className="mt-4"
10090
>
101-
<code>Password and confirmation must be the same.</code>
102-
</Form.Label>
91+
<Form.Check
92+
type="switch"
93+
label="Create a password to store your settings securely in an encrypted
94+
storage"
95+
onChange={event => handleCheckCreateSpendingPassword(event)}
96+
/>
97+
</Form.Group>
98+
<Form.Group hidden={hiddenSpendingPassword}>
99+
<Form.Control
100+
type="password"
101+
id="password"
102+
name="password"
103+
placeholder="New password (min 8 chars)"
104+
value={password}
105+
isInvalid={!isValidPassword}
106+
onChange={event => setPassword(event.target.value)}
107+
/>
108+
<Form.Label className="text-danger" hidden={isValidPassword}>
109+
<code>The password must have at least 8 chars.</code>
110+
</Form.Label>
111+
<Form.Control
112+
type="password"
113+
name="confirmPassword"
114+
id="confirmPassword"
115+
placeholder="Confirm password"
116+
value={confirmPassword}
117+
onChange={event => setConfirmPassword(event.target.value)}
118+
className="mt-3"
119+
/>
120+
<Form.Label
121+
className="text-danger"
122+
hidden={arePasswordAndConfirmationEqual}
123+
>
124+
<code>Password and confirmation must be the same.</code>
125+
</Form.Label>
126+
</Form.Group>
103127
</Form.Group>
104128
<Row className="justify-content-center">
105129
<Button variant="primary" type="submit">

examples/wallet/app/constants/routes.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
"INPUT_KEYS": "/input_keys",
66
"SEND": "/send",
77
"STAKING": "/staking",
8-
"SETTINGS": "/settings"
8+
"SETTINGS": "/settings",
9+
"UNLOCK_WALLET": "/unlock"
910
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// @flow
2+
import { bindActionCreators } from 'redux';
3+
import { connect } from 'react-redux';
4+
import UnlockWallet from '../pages/UnlockWallet';
5+
import { setKeysWithSpendingPassword } from '../actions/account';
6+
7+
function mapDispatchToProps(dispatch) {
8+
return bindActionCreators({ setKeysWithSpendingPassword }, dispatch);
9+
}
10+
11+
export default connect(
12+
undefined,
13+
mapDispatchToProps
14+
)(UnlockWallet);

0 commit comments

Comments
 (0)