mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-02-02 14:23:42 +00:00
unlock wip
This commit is contained in:
parent
dbb90d0d5c
commit
63e7eb89e4
@ -1,9 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": ["eslint:recommended", "plugin:react/recommended"],
|
"extends": ["eslint:recommended", "plugin:react/recommended"],
|
||||||
"parser": "babel-eslint",
|
"parser": "babel-eslint",
|
||||||
"plugins": [
|
"plugins": ["react"],
|
||||||
"react"
|
|
||||||
],
|
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
"jsx": true,
|
"jsx": true,
|
||||||
@ -19,7 +17,7 @@
|
|||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"comma-dangle": 1,
|
"comma-dangle": 1,
|
||||||
"quotes": [ 1, "single" ],
|
"quotes": [1, "single"],
|
||||||
"no-undef": 1,
|
"no-undef": 1,
|
||||||
"global-strict": 0,
|
"global-strict": 0,
|
||||||
"no-extra-semi": 1,
|
"no-extra-semi": 1,
|
||||||
@ -32,6 +30,7 @@
|
|||||||
"react/jsx-uses-react": 1
|
"react/jsx-uses-react": 1
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"SyntheticInputEvent": false
|
"SyntheticInputEvent": false,
|
||||||
|
"SyntheticKeyboardEvent": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
common/actions/wallet.js
Normal file
29
common/actions/wallet.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// @flow
|
||||||
|
import type { PrivateKeyUnlockParams } from 'libs/wallet/privkey';
|
||||||
|
import BaseWallet from 'libs/wallet/base';
|
||||||
|
|
||||||
|
export type UnlockPrivateKeyAction = {
|
||||||
|
type: 'WALLET_UNLOCK_PRIVATE_KEY',
|
||||||
|
payload: PrivateKeyUnlockParams
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SaveWalletAction = {
|
||||||
|
type: 'WALLET_SAVE',
|
||||||
|
payload: BaseWallet
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WalletAction = UnlockPrivateKeyAction | SaveWalletAction;
|
||||||
|
|
||||||
|
export function unlockPrivateKey(value: PrivateKeyUnlockParams): UnlockPrivateKeyAction {
|
||||||
|
return {
|
||||||
|
type: 'WALLET_UNLOCK_PRIVATE_KEY',
|
||||||
|
payload: value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveWallet(value: BaseWallet): SaveWalletAction {
|
||||||
|
return {
|
||||||
|
type: 'WALLET_SAVE',
|
||||||
|
payload: value
|
||||||
|
};
|
||||||
|
}
|
95
common/components/WalletDecrypt/PrivateKey.jsx
Normal file
95
common/components/WalletDecrypt/PrivateKey.jsx
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// @flow
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import translate from 'translations';
|
||||||
|
import { isValidPrivKey } from 'libs/validators';
|
||||||
|
import type { PrivateKeyUnlockParams } from 'libs/wallet/privkey';
|
||||||
|
|
||||||
|
export type PrivateKeyValue = PrivateKeyUnlockParams & {
|
||||||
|
valid: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
function fixPkey(key) {
|
||||||
|
if (key.indexOf('0x') === 0) {
|
||||||
|
return key.slice(2);
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class PrivateKeyDecrypt extends Component {
|
||||||
|
props: {
|
||||||
|
value: PrivateKeyUnlockParams,
|
||||||
|
onChange: (value: PrivateKeyUnlockParams) => void,
|
||||||
|
onUnlock: () => void
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { key, password } = this.props.value;
|
||||||
|
const fixedPkey = fixPkey(key);
|
||||||
|
const isValid = isValidPrivKey(fixedPkey.length);
|
||||||
|
const isPassRequired = fixedPkey.length > 64;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="col-md-4 col-sm-6">
|
||||||
|
<div id="selectedTypeKey">
|
||||||
|
<h4>
|
||||||
|
{translate('ADD_Radio_3')}
|
||||||
|
</h4>
|
||||||
|
<div className="form-group">
|
||||||
|
<textarea
|
||||||
|
id="aria-private-key"
|
||||||
|
className={`form-control ${isValid ? 'is-valid' : 'is-invalid'}`}
|
||||||
|
value={key}
|
||||||
|
onChange={this.onPkeyChange}
|
||||||
|
onKeyDown={this.onKeyDown}
|
||||||
|
placeholder={translate('x_PrivKey2')}
|
||||||
|
rows="4"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{isValid &&
|
||||||
|
isPassRequired &&
|
||||||
|
<div className="form-group">
|
||||||
|
<p>
|
||||||
|
{translate('ADD_Label_3')}
|
||||||
|
</p>
|
||||||
|
<input
|
||||||
|
className={`form-control ${password.length > 0
|
||||||
|
? 'is-valid'
|
||||||
|
: 'is-invalid'}`}
|
||||||
|
value={password}
|
||||||
|
onChange={this.onPasswordChange}
|
||||||
|
onKeyDown={this.onKeyDown}
|
||||||
|
placeholder={translate('x_Password')}
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onPkeyChange = (e: SyntheticInputEvent) => {
|
||||||
|
const fixedPkey = fixPkey(e.target.value);
|
||||||
|
const isValid = isValidPrivKey(fixedPkey.length);
|
||||||
|
const isPassRequired = fixedPkey.length > 64;
|
||||||
|
const valid = isValid && (isPassRequired ? this.props.value.password.length > 0 : true);
|
||||||
|
|
||||||
|
this.props.onChange({ ...this.props.value, key: e.target.value, valid });
|
||||||
|
};
|
||||||
|
|
||||||
|
onPasswordChange = (e: SyntheticInputEvent) => {
|
||||||
|
const fixedPkey = fixPkey(this.props.value.key);
|
||||||
|
const isValid = isValidPrivKey(fixedPkey.length);
|
||||||
|
const isPassRequired = fixedPkey.length > 64;
|
||||||
|
const valid = isValid && (isPassRequired ? e.target.value.length > 0 : true);
|
||||||
|
|
||||||
|
this.props.onChange({ ...this.props.value, password: e.target.value, valid });
|
||||||
|
};
|
||||||
|
|
||||||
|
onKeyDown = (e: SyntheticKeyboardEvent) => {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
this.props.onUnlock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
161
common/components/WalletDecrypt/index.jsx
Normal file
161
common/components/WalletDecrypt/index.jsx
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
// @flow
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import translate from 'translations';
|
||||||
|
import KeystoreDecrypt from './Keystore';
|
||||||
|
import PrivateKeyDecrypt from './PrivateKey';
|
||||||
|
import type { PrivateKeyValue } from './PrivateKey';
|
||||||
|
import MnemonicDecrypt from './Mnemonic';
|
||||||
|
import LedgerNanoSDecrypt from './LedgerNano';
|
||||||
|
import TrezorDecrypt from './Trezor';
|
||||||
|
import ViewOnlyDecrypt from './ViewOnly';
|
||||||
|
import map from 'lodash/map';
|
||||||
|
import { unlockPrivateKey } from 'actions/wallet';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
const WALLETS = {
|
||||||
|
'keystore-file': {
|
||||||
|
lid: 'x_Keystore2',
|
||||||
|
component: KeystoreDecrypt,
|
||||||
|
initialParams: {}
|
||||||
|
},
|
||||||
|
'private-key': {
|
||||||
|
lid: 'x_PrivKey2',
|
||||||
|
component: PrivateKeyDecrypt,
|
||||||
|
initialParams: {
|
||||||
|
key: '',
|
||||||
|
password: ''
|
||||||
|
},
|
||||||
|
unlock: unlockPrivateKey
|
||||||
|
},
|
||||||
|
'mnemonic-phrase': {
|
||||||
|
lid: 'x_Mnemonic',
|
||||||
|
component: MnemonicDecrypt
|
||||||
|
},
|
||||||
|
'ledger-nano-s': {
|
||||||
|
lid: 'x_Ledger',
|
||||||
|
component: LedgerNanoSDecrypt
|
||||||
|
},
|
||||||
|
trezor: {
|
||||||
|
lid: 'x_Trezor',
|
||||||
|
component: TrezorDecrypt
|
||||||
|
},
|
||||||
|
'view-only': {
|
||||||
|
lid: 'View with Address Only',
|
||||||
|
component: ViewOnlyDecrypt
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
type UnlockParams = {} | PrivateKeyValue;
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
selectedWalletKey: string,
|
||||||
|
value: UnlockParams
|
||||||
|
};
|
||||||
|
|
||||||
|
export class WalletDecrypt extends Component {
|
||||||
|
props: {
|
||||||
|
// FIXME
|
||||||
|
dispatch: (action: any) => void
|
||||||
|
};
|
||||||
|
state: State = {
|
||||||
|
selectedWalletKey: 'keystore-file',
|
||||||
|
value: WALLETS['keystore-file'].initialParams
|
||||||
|
};
|
||||||
|
|
||||||
|
getDecryptionComponent() {
|
||||||
|
const { selectedWalletKey, value } = this.state;
|
||||||
|
const selectedWallet = WALLETS[selectedWalletKey];
|
||||||
|
|
||||||
|
if (!selectedWallet) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<selectedWallet.component
|
||||||
|
value={value}
|
||||||
|
onChange={this.onChange}
|
||||||
|
onUnlock={this.onUnlock}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
buildWalletOptions() {
|
||||||
|
return map(WALLETS, (wallet, key) => {
|
||||||
|
const isSelected = this.state.selectedWalletKey === key;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<label className="radio" key={key}>
|
||||||
|
<input
|
||||||
|
aria-flowto={`aria-${key}`}
|
||||||
|
aria-labelledby={`${key}-label`}
|
||||||
|
type="radio"
|
||||||
|
name="decryption-choice-radio-group"
|
||||||
|
value={key}
|
||||||
|
checked={isSelected}
|
||||||
|
onChange={this.handleDecryptionChoiceChange}
|
||||||
|
/>
|
||||||
|
<span id={`${key}-label`}>
|
||||||
|
{translate(wallet.lid)}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDecryptionChoiceChange = (event: SyntheticInputEvent) => {
|
||||||
|
const wallet = WALLETS[event.target.value];
|
||||||
|
|
||||||
|
if (!wallet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
selectedWalletKey: event.target.value,
|
||||||
|
value: wallet.initialParams
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const decryptionComponent = this.getDecryptionComponent();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<article className="well decrypt-drtv row">
|
||||||
|
<section className="col-md-4 col-sm-6">
|
||||||
|
<h4>
|
||||||
|
{translate('decrypt_Access')}
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
{this.buildWalletOptions()}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{decryptionComponent}
|
||||||
|
{!!this.state.value.valid &&
|
||||||
|
<section className="col-md-4 col-sm-6">
|
||||||
|
<h4 id="uploadbtntxt-wallet">
|
||||||
|
{translate('ADD_Label_6')}
|
||||||
|
</h4>
|
||||||
|
<div className="form-group">
|
||||||
|
<a
|
||||||
|
tabIndex="0"
|
||||||
|
role="button"
|
||||||
|
className="btn btn-primary btn-block"
|
||||||
|
onClick={this.onUnlock}
|
||||||
|
>
|
||||||
|
{translate('ADD_Label_6_short')}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>}
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange = (value: UnlockParams) => {
|
||||||
|
this.setState({ value });
|
||||||
|
};
|
||||||
|
|
||||||
|
onUnlock = () => {
|
||||||
|
this.props.dispatch(WALLETS[this.state.selectedWalletKey].unlock(this.state.value));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect()(WalletDecrypt);
|
@ -2,11 +2,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import translate from 'translations';
|
import translate from 'translations';
|
||||||
|
import WalletDecrypt from 'components/WalletDecrypt';
|
||||||
|
import BaseWallet from 'libs/wallet/base';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import type { State } from 'reducers';
|
||||||
|
|
||||||
export default class UnlockHeader extends React.Component {
|
type Props = {
|
||||||
props: {
|
title: string,
|
||||||
title: string
|
wallet: BaseWallet
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export class UnlockHeader extends React.Component {
|
||||||
|
props: Props;
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
title: PropTypes.string.isRequired
|
title: PropTypes.string.isRequired
|
||||||
};
|
};
|
||||||
@ -17,17 +24,33 @@ export default class UnlockHeader extends React.Component {
|
|||||||
expanded: true
|
expanded: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: Props) {
|
||||||
|
if (this.props.wallet && this.props.wallet !== prevProps.wallet) {
|
||||||
|
this.setState({ expanded: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
// not sure if could happen
|
||||||
|
if (!this.props.wallet && this.props.wallet !== prevProps.wallet) {
|
||||||
|
this.setState({ expanded: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<article className="collapse-container">
|
<article className="collapse-container">
|
||||||
<div onClick={this.toggleExpanded}>
|
<div onClick={this.toggleExpanded}>
|
||||||
<a className="collapse-button">
|
<a className="collapse-button">
|
||||||
<span>{this.state.expanded ? '-' : '+'}</span>
|
<span>
|
||||||
|
{this.state.expanded ? '-' : '+'}
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<h1>{translate(this.props.title)}</h1>
|
<h1>
|
||||||
|
{translate(this.props.title)}
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
{this.state.expanded &&
|
{this.state.expanded &&
|
||||||
<div>
|
<div>
|
||||||
|
<WalletDecrypt />
|
||||||
{/* @@if (site === 'cx' ) { <cx-wallet-decrypt-drtv></cx-wallet-decrypt-drtv> }
|
{/* @@if (site === 'cx' ) { <cx-wallet-decrypt-drtv></cx-wallet-decrypt-drtv> }
|
||||||
@@if (site === 'mew' ) { <wallet-decrypt-drtv></wallet-decrypt-drtv> } */}
|
@@if (site === 'mew' ) { <wallet-decrypt-drtv></wallet-decrypt-drtv> } */}
|
||||||
</div>}
|
</div>}
|
||||||
@ -43,3 +66,11 @@ export default class UnlockHeader extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state: State) {
|
||||||
|
return {
|
||||||
|
wallet: state.wallet
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(UnlockHeader);
|
||||||
|
@ -13,6 +13,9 @@ import {
|
|||||||
AddressField
|
AddressField
|
||||||
} from './components';
|
} from './components';
|
||||||
import pickBy from 'lodash/pickBy';
|
import pickBy from 'lodash/pickBy';
|
||||||
|
import type { State as AppState } from 'reducers';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import BaseWallet from 'libs/wallet/base';
|
||||||
// import type { Transaction } from './types';
|
// import type { Transaction } from './types';
|
||||||
import customMessages from './messages';
|
import customMessages from './messages';
|
||||||
|
|
||||||
@ -49,7 +52,8 @@ export class SendTransaction extends React.Component {
|
|||||||
query: {
|
query: {
|
||||||
[string]: string
|
[string]: string
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
wallet: BaseWallet
|
||||||
};
|
};
|
||||||
state: State = {
|
state: State = {
|
||||||
hasQueryString: false,
|
hasQueryString: false,
|
||||||
@ -73,7 +77,7 @@ export class SendTransaction extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const unlocked = true; //wallet != null
|
const unlocked = !!this.props.wallet;
|
||||||
const unitReadable = 'UNITREADABLE';
|
const unitReadable = 'UNITREADABLE';
|
||||||
const nodeUnit = 'NODEUNIT';
|
const nodeUnit = 'NODEUNIT';
|
||||||
const hasEnoughBalance = false;
|
const hasEnoughBalance = false;
|
||||||
@ -87,7 +91,6 @@ export class SendTransaction extends React.Component {
|
|||||||
<section className="container" style={{ minHeight: '50%' }}>
|
<section className="container" style={{ minHeight: '50%' }}>
|
||||||
<div className="tab-content">
|
<div className="tab-content">
|
||||||
<main className="tab-pane active" ng-controller="sendTxCtrl">
|
<main className="tab-pane active" ng-controller="sendTxCtrl">
|
||||||
|
|
||||||
{hasQueryString &&
|
{hasQueryString &&
|
||||||
<div className="alert alert-info">
|
<div className="alert alert-info">
|
||||||
<p>
|
<p>
|
||||||
@ -116,8 +119,7 @@ export class SendTransaction extends React.Component {
|
|||||||
<strong>
|
<strong>
|
||||||
Warning! You do not have enough funds to
|
Warning! You do not have enough funds to
|
||||||
complete this swap.
|
complete this swap.
|
||||||
</strong>
|
</strong>{' '}
|
||||||
{' '}
|
|
||||||
<br />
|
<br />
|
||||||
Please add more funds or access a different wallet.
|
Please add more funds or access a different wallet.
|
||||||
</div>
|
</div>
|
||||||
@ -187,7 +189,6 @@ export class SendTransaction extends React.Component {
|
|||||||
{' '}Send Transaction{' '}
|
{' '}Send Transaction{' '}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
{'' /* <!-- / Content --> */}
|
{'' /* <!-- / Content --> */}
|
||||||
{
|
{
|
||||||
@ -266,5 +267,11 @@ export class SendTransaction extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// export connected version
|
|
||||||
export default SendTransaction;
|
function mapStateToProps(state: AppState) {
|
||||||
|
return {
|
||||||
|
wallet: state.wallet
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(SendTransaction);
|
||||||
|
26
common/containers/Tabs/ViewWallet/index.jsx
Normal file
26
common/containers/Tabs/ViewWallet/index.jsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// @flow
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import translate from 'translations';
|
||||||
|
|
||||||
|
export default class ViewWallet extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<section className="container">
|
||||||
|
<div className="tab-content">
|
||||||
|
<article className="tab-pane active">
|
||||||
|
<article className="collapse-container">
|
||||||
|
<div>
|
||||||
|
<h1>View Wallet Info</h1>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
{translate('VIEWWALLET_Subtitle')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +0,0 @@
|
|||||||
import React, {Component} from 'react';
|
|
||||||
import translate from 'translations';
|
|
||||||
|
|
||||||
|
|
||||||
export default class PrivateKeyDecrypt extends Component {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<section className="col-md-4 col-sm-6">
|
|
||||||
<div id="selectedUploadKey">
|
|
||||||
<h4>{translate('ADD_Radio_2_alt')}</h4>
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<input type="file" id="fselector" />
|
|
||||||
|
|
||||||
<a className="btn-file marg-v-sm" id="aria1" tabIndex="0" role="button">{translate('ADD_Radio_2_short')}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,129 +0,0 @@
|
|||||||
import React, {Component} from 'react';
|
|
||||||
import translate from 'translations';
|
|
||||||
import KeystoreDecrypt from './KeystoreDecrypt';
|
|
||||||
import PrivateKeyDecrypt from './PrivateKeyDecrypt';
|
|
||||||
import MnemonicDecrypt from './MnemonicDecrypt';
|
|
||||||
import LedgerNanoSDecrypt from './LedgerNanoSDecrypt';
|
|
||||||
import TrezorDecrypt from './TrezorDecrypt';
|
|
||||||
import ViewOnlyDecrypt from './ViewOnlyDecrypt';
|
|
||||||
|
|
||||||
export default class WalletDecrypt extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.decryptionChoices = [
|
|
||||||
{
|
|
||||||
name: 'keystore-file',
|
|
||||||
lid: 'x_Keystore2',
|
|
||||||
component: KeystoreDecrypt
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'private-key',
|
|
||||||
lid: 'x_PrivKey2',
|
|
||||||
component: PrivateKeyDecrypt
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'mnemonic-phrase',
|
|
||||||
lid: 'x_Mnemonic',
|
|
||||||
component: MnemonicDecrypt
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ledger-nano-s',
|
|
||||||
lid: 'x_Ledger',
|
|
||||||
component: LedgerNanoSDecrypt
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'trezor',
|
|
||||||
lid: 'x_Trezor',
|
|
||||||
component: TrezorDecrypt
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'view-only',
|
|
||||||
lid: 'View with Address Only',
|
|
||||||
component: ViewOnlyDecrypt
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
decryptionChoice: this.decryptionChoices[0].name // auto-select first option.
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
getDecryptionComponent() {
|
|
||||||
const selectedDecryptionChoice = this.decryptionChoices.find((decryptionChoice) => {
|
|
||||||
return this.state.decryptionChoice === decryptionChoice.name;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!selectedDecryptionChoice) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <selectedDecryptionChoice.component />;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildDecryptionChoices() {
|
|
||||||
return this.decryptionChoices.map((decryptionChoice, idx) => {
|
|
||||||
const isSelected = this.state.decryptionChoice === decryptionChoice.name;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<label className="radio" key={decryptionChoice.name}>
|
|
||||||
<input
|
|
||||||
aria-flowto={`aria${idx}`}
|
|
||||||
aria-labelledby={`${decryptionChoice.name}-label`}
|
|
||||||
type="radio"
|
|
||||||
name="decryption-choice-radio-group"
|
|
||||||
value={decryptionChoice.name}
|
|
||||||
checked={isSelected}
|
|
||||||
onChange={this.handleDecryptionChoiceChange}
|
|
||||||
/>
|
|
||||||
<span id={`${decryptionChoice.name}-label`}>
|
|
||||||
{translate(decryptionChoice.lid)}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDecryptionChoiceChange = (event) => {
|
|
||||||
const choiceObject = this.decryptionChoices.find(decryptionChoice => {
|
|
||||||
return (decryptionChoice.name === event.target.value) ? decryptionChoice.component : false;
|
|
||||||
});
|
|
||||||
|
|
||||||
const decryptionChoice = choiceObject.name;
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
decryptionChoice
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const decryptionComponent = this.getDecryptionComponent();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section className="container">
|
|
||||||
<div className="tab-content">
|
|
||||||
<article className="tab-pane active">
|
|
||||||
<article className="collapse-container">
|
|
||||||
<div>
|
|
||||||
<h1>View Wallet Info</h1>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p>{translate('VIEWWALLET_Subtitle')}</p>
|
|
||||||
<article className="well decrypt-drtv row">
|
|
||||||
<section className="col-md-4 col-sm-6">
|
|
||||||
<h4>{translate('decrypt_Access')}</h4>
|
|
||||||
|
|
||||||
{this.buildDecryptionChoices()}
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{decryptionComponent}
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,31 +11,32 @@ import { createLogger } from 'redux-logger';
|
|||||||
import createSagaMiddleware from 'redux-saga';
|
import createSagaMiddleware from 'redux-saga';
|
||||||
import notificationsSaga from './sagas/notifications';
|
import notificationsSaga from './sagas/notifications';
|
||||||
import ensSaga from './sagas/ens';
|
import ensSaga from './sagas/ens';
|
||||||
|
import walletSaga from './sagas/wallet';
|
||||||
|
|
||||||
// application styles
|
// application styles
|
||||||
import 'assets/styles/etherwallet-master.less';
|
import 'assets/styles/etherwallet-master.less';
|
||||||
|
|
||||||
const sagaMiddleware = createSagaMiddleware();
|
|
||||||
|
|
||||||
const configureStore = () => {
|
const configureStore = () => {
|
||||||
let sagaApplied = applyMiddleware(sagaMiddleware);
|
const logger = createLogger({
|
||||||
|
collapsed: true
|
||||||
|
});
|
||||||
|
const sagaMiddleware = createSagaMiddleware();
|
||||||
let store;
|
let store;
|
||||||
let middleware;
|
let middleware;
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
window.Perf = Perf;
|
window.Perf = Perf;
|
||||||
sagaApplied = composeWithDevTools(sagaApplied);
|
middleware = composeWithDevTools(
|
||||||
const logger = createLogger({
|
applyMiddleware(sagaMiddleware, logger, routerMiddleware(history))
|
||||||
collapsed: true
|
);
|
||||||
});
|
|
||||||
middleware = applyMiddleware(routerMiddleware(history), logger);
|
|
||||||
} else {
|
} else {
|
||||||
middleware = applyMiddleware(routerMiddleware(history));
|
middleware = applyMiddleware(sagaMiddleware, routerMiddleware(history));
|
||||||
}
|
}
|
||||||
|
|
||||||
store = createStore(RootReducer, sagaApplied, middleware);
|
store = createStore(RootReducer, void 0, middleware);
|
||||||
sagaMiddleware.run(notificationsSaga);
|
sagaMiddleware.run(notificationsSaga);
|
||||||
sagaMiddleware.run(ensSaga);
|
sagaMiddleware.run(ensSaga);
|
||||||
|
sagaMiddleware.run(walletSaga);
|
||||||
return store;
|
return store;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,3 +65,7 @@ function validateEtherAddress(address: string): boolean {
|
|||||||
return true;
|
return true;
|
||||||
else return isChecksumAddress(address);
|
else return isChecksumAddress(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isValidPrivKey(length: number): boolean {
|
||||||
|
return length === 64 || length === 128 || length === 132;
|
||||||
|
}
|
||||||
|
7
common/libs/wallet/base.js
Normal file
7
common/libs/wallet/base.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
export default class BaseWallet {
|
||||||
|
getAddress(): string {
|
||||||
|
throw 'Implement me';
|
||||||
|
}
|
||||||
|
}
|
24
common/libs/wallet/privkey.js
Normal file
24
common/libs/wallet/privkey.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// @flow
|
||||||
|
import BaseWallet from './base';
|
||||||
|
import { privateToPublic, publicToAddress, toChecksumAddress } from 'ethereumjs-util';
|
||||||
|
|
||||||
|
export type PrivateKeyUnlockParams = {
|
||||||
|
key: string,
|
||||||
|
password: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class PrivKeyWallet extends BaseWallet {
|
||||||
|
privKey: Buffer;
|
||||||
|
pubKey: Buffer;
|
||||||
|
address: Buffer;
|
||||||
|
constructor(params: PrivateKeyUnlockParams) {
|
||||||
|
super();
|
||||||
|
this.privKey = Buffer.from(params.key, 'hex');
|
||||||
|
this.pubKey = privateToPublic(this.privKey);
|
||||||
|
this.address = publicToAddress(this.pubKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAddress() {
|
||||||
|
return toChecksumAddress(`0x${this.address.toString('hex')}`);
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,9 @@ import type { State as NotificationsState } from './notifications';
|
|||||||
import * as ens from './ens';
|
import * as ens from './ens';
|
||||||
import type { State as EnsState } from './ens';
|
import type { State as EnsState } from './ens';
|
||||||
|
|
||||||
|
import * as wallet from './wallet';
|
||||||
|
import type { State as WalletState } from './wallet';
|
||||||
|
|
||||||
import { reducer as formReducer } from 'redux-form';
|
import { reducer as formReducer } from 'redux-form';
|
||||||
import { combineReducers } from 'redux';
|
import { combineReducers } from 'redux';
|
||||||
import { routerReducer } from 'react-router-redux';
|
import { routerReducer } from 'react-router-redux';
|
||||||
@ -21,7 +24,8 @@ export type State = {
|
|||||||
generateWallet: GenerateWalletState,
|
generateWallet: GenerateWalletState,
|
||||||
conig: ConfigState,
|
conig: ConfigState,
|
||||||
notifications: NotificationsState,
|
notifications: NotificationsState,
|
||||||
ens: EnsState
|
ens: EnsState,
|
||||||
|
wallet: WalletState
|
||||||
};
|
};
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
@ -30,6 +34,7 @@ export default combineReducers({
|
|||||||
...swap,
|
...swap,
|
||||||
...notifications,
|
...notifications,
|
||||||
...ens,
|
...ens,
|
||||||
|
...wallet,
|
||||||
form: formReducer,
|
form: formReducer,
|
||||||
routing: routerReducer
|
routing: routerReducer
|
||||||
});
|
});
|
||||||
|
20
common/reducers/wallet.js
Normal file
20
common/reducers/wallet.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// @flow
|
||||||
|
import type { WalletAction, SaveWalletAction } from 'actions/wallet';
|
||||||
|
import BaseWallet from 'libs/wallet/base';
|
||||||
|
|
||||||
|
export type State = ?BaseWallet;
|
||||||
|
|
||||||
|
const initialState: State = null;
|
||||||
|
|
||||||
|
function saveWallet(state: State, action: SaveWalletAction): State {
|
||||||
|
return action.payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function wallet(state: State = initialState, action: WalletAction): State {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'WALLET_SAVE':
|
||||||
|
return saveWallet(state, action);
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ import { browserHistory, Redirect, Route } from 'react-router';
|
|||||||
import { useBasename } from 'history';
|
import { useBasename } from 'history';
|
||||||
import { App } from 'containers';
|
import { App } from 'containers';
|
||||||
import GenerateWallet from 'containers/Tabs/GenerateWallet';
|
import GenerateWallet from 'containers/Tabs/GenerateWallet';
|
||||||
import WalletDecrypt from 'containers/Tabs/WalletDecrypt';
|
|
||||||
import ViewWallet from 'containers/Tabs/ViewWallet';
|
import ViewWallet from 'containers/Tabs/ViewWallet';
|
||||||
import Help from 'containers/Tabs/Help';
|
import Help from 'containers/Tabs/Help';
|
||||||
import Swap from 'containers/Tabs/Swap';
|
import Swap from 'containers/Tabs/Swap';
|
||||||
@ -13,7 +12,7 @@ export const history = getHistory();
|
|||||||
export const Routing = () =>
|
export const Routing = () =>
|
||||||
<Route name="App" path="" component={App}>
|
<Route name="App" path="" component={App}>
|
||||||
<Route name="GenerateWallet" path="/" component={GenerateWallet} />
|
<Route name="GenerateWallet" path="/" component={GenerateWallet} />
|
||||||
<Route name="ViewWallet" path="/view-wallet" component={WalletDecrypt} />
|
<Route name="ViewWallet" path="/view-wallet" component={ViewWallet} />
|
||||||
<Route name="Help" path="/help" component={Help} />
|
<Route name="Help" path="/help" component={Help} />
|
||||||
<Route name="Swap" path="/swap" component={Swap} />
|
<Route name="Swap" path="/swap" component={Swap} />
|
||||||
<Route name="Send" path="/send-transaction" component={SendTransaction} />
|
<Route name="Send" path="/send-transaction" component={SendTransaction} />
|
||||||
|
14
common/sagas/wallet.js
Normal file
14
common/sagas/wallet.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// @flow
|
||||||
|
import { takeEvery, call, put, select } from 'redux-saga/effects';
|
||||||
|
import { delay } from 'redux-saga';
|
||||||
|
import { saveWallet } from 'actions/wallet';
|
||||||
|
import type { UnlockPrivateKeyAction } from 'actions/wallet';
|
||||||
|
import PrivKeyWallet from 'libs/wallet/privkey';
|
||||||
|
|
||||||
|
function* unlockPrivateKey(action: UnlockPrivateKeyAction) {
|
||||||
|
yield put(saveWallet(new PrivKeyWallet(action.payload)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function* notificationsSaga() {
|
||||||
|
yield takeEvery('WALLET_UNLOCK_PRIVATE_KEY', unlockPrivateKey);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user