Skip to content

Commit

Permalink
EthereumJS-Wallet (Part 2) (#310)
Browse files Browse the repository at this point in the history
* Progress commit -- ethereumjs-wallet typings

* Add hdkey module + better wallet typing

* Add provider-engine typings

* Add jsdoc descriptions for hdkey constructor methods

* Fix missing return type

* Fix another missing return

* Make provider engine options optional

* Add priv/pubkey members to wallet instance

* Turn into SFC + Use ethereumjs-lib

* Use proper interface naming for V3Wallet

* Switch to ethereumjs-wallet

* Switch to ethereumjs-wallet and refactor using NewTabLink

* Use proper interface naming for V3Wallet

* Use proper interface naming for PublicKeyOnlyWallet

* Fix broken test, re-add scryptsy to make this PR pass

* Fix definition module for thirdparty wallets

* Decrease n-factor to 1024, checksum address of keystore

* Update typedef for react-dom from 15 to 16

* Lock react-dom, set typescript to 2.5.2
  • Loading branch information
HenryNguyen5 authored and dternyak committed Nov 7, 2017
1 parent cb130a9 commit 3bea632
Show file tree
Hide file tree
Showing 12 changed files with 3,308 additions and 3,777 deletions.
4 changes: 2 additions & 2 deletions common/actions/generateWallet/actionCreators.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PrivKeyWallet } from 'libs/wallet';
import { generate } from 'ethereumjs-wallet';
import * as interfaces from './actionTypes';
import { TypeKeys } from './constants';

Expand All @@ -8,7 +8,7 @@ export function generateNewWallet(
): interfaces.GenerateNewWalletAction {
return {
type: TypeKeys.GENERATE_WALLET_GENERATE_WALLET,
wallet: PrivKeyWallet.generate(),
wallet: generate(),
password
};
}
Expand Down
4 changes: 2 additions & 2 deletions common/actions/generateWallet/actionTypes.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { PrivKeyWallet } from 'libs/wallet';
import { IFullWallet } from 'ethereumjs-wallet';
import { TypeKeys } from './constants';

/*** Generate Wallet File ***/
export interface GenerateNewWalletAction {
type: TypeKeys.GENERATE_WALLET_GENERATE_WALLET;
wallet: PrivKeyWallet;
wallet: IFullWallet;
password: string;
}

Expand Down
110 changes: 46 additions & 64 deletions common/components/PrintableWallet/index.tsx
Original file line number Diff line number Diff line change
@@ -1,71 +1,53 @@
import { PaperWallet } from 'components';
import PrivKeyWallet from 'libs/wallet/privkey';
import React, { Component } from 'react';
import { IFullWallet } from 'ethereumjs-wallet';
import React from 'react';
import translate from 'translations';
import printElement from 'utils/printElement';

interface Props {
wallet: PrivKeyWallet;
}

interface State {
address: string | null;
privateKey: string | null;
}

const initialState = {
address: null,
privateKey: null
};

export default class PrintableWallet extends Component<Props, {}> {
public state: State = initialState;

public async componentDidMount() {
const address = await this.props.wallet.getAddress();
const privateKey = this.props.wallet.getPrivateKey();
this.setState({ address, privateKey });
const print = (address: string, privateKey: string) => () =>
address &&
privateKey &&
printElement(<PaperWallet address={address} privateKey={privateKey} />, {
popupFeatures: {
scrollbars: 'no'
},
styles: `
* {
box-sizing: border-box;
}
body {
font-family: Lato, sans-serif;
font-size: 1rem;
line-height: 1.4;
margin: 0;
}
`
});

const PrintableWallet: React.SFC<{ wallet: IFullWallet }> = ({ wallet }) => {
const address = wallet.getAddressString();
const privateKey = wallet.getPrivateKeyString();

if (!address || !privateKey) {
return null;
}

public print = () => {
const { address, privateKey } = this.state;
if (address && privateKey) {
printElement(<PaperWallet address={address} privateKey={privateKey} />, {
popupFeatures: {
scrollbars: 'no'
},
styles: `
* {
box-sizing: border-box;
}
body {
font-family: Lato, sans-serif;
font-size: 1rem;
line-height: 1.4;
margin: 0;
}
`
});
}
};
return (
<div>
<PaperWallet address={address} privateKey={privateKey} />
<a
role="button"
aria-label={translate('x_Print')}
aria-describedby="x_PrintDesc"
className={'btn btn-lg btn-primary'}
onClick={print(address, privateKey)}
style={{ marginTop: 10 }}
>
{translate('x_Print')}
</a>
</div>
);
};

public render() {
const { address, privateKey } = this.state;
return address && privateKey ? (
<div>
<PaperWallet address={address} privateKey={privateKey} />
<a
role="button"
aria-label={translate('x_Print')}
aria-describedby="x_PrintDesc"
className={'btn btn-lg btn-primary'}
onClick={this.print}
style={{ marginTop: 10 }}
>
{translate('x_Print')}
</a>
</div>
) : null;
}
}
export default PrintableWallet;
7 changes: 4 additions & 3 deletions common/components/ui/NewTabLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ interface AAttributes {
type?: string;
}

interface NewTabLinkProps extends AAttributes {
interface NewTabLinkProps extends AAttributes {
content?: React.ReactElement<any> | string;
children?: React.ReactElement<any> | string;
}

const NewTabLink = ({ content, children, ...rest }: NewTabLinkProps) =>
const NewTabLink = ({ content, children, ...rest }: NewTabLinkProps) => (
<a target="_blank" rel="noopener" {...rest}>
{content || children} {/* Keep content for short-hand text insertion */}
</a>;
</a>
);

export default NewTabLink;
43 changes: 25 additions & 18 deletions common/containers/Tabs/GenerateWallet/components/CryptoWarning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,39 @@ import chromeIcon from 'assets/images/browsers/chrome.svg';
import operaIcon from 'assets/images/browsers/opera.svg';
import './CryptoWarning.scss';

const BROWSERS = [{
name: "Firefox",
href: "https://www.mozilla.org/en-US/firefox/new/",
icon: firefoxIcon,
}, {
name: "Chrome",
href: "https://www.google.com/chrome/browser/desktop/index.html",
icon: chromeIcon,
}, {
name: "Opera",
href: "http://www.opera.com/",
icon: operaIcon,
}];
const BROWSERS = [
{
name: 'Firefox',
href: 'https://www.mozilla.org/en-US/firefox/new/',
icon: firefoxIcon
},
{
name: 'Chrome',
href: 'https://www.google.com/chrome/browser/desktop/index.html',
icon: chromeIcon
},
{
name: 'Opera',
href: 'http://www.opera.com/',
icon: operaIcon
}
];

const CryptoWarning: React.SFC<{}> = () =>
const CryptoWarning: React.SFC<{}> = () => (
<div className="Tab-content-pane">
<div className="CryptoWarning">
<h2 className="CryptoWarning-title">
Your Browser Cannot Generate a Wallet
</h2>
<p className="CryptoWarning-text">
{isMobile ? `
{isMobile
? `
MyEtherWallet requires certain features for secure wallet generation
that your browser doesn't offer. You can still securely use the site
otherwise. To generate a wallet, please use your device's default
browser, or switch to a laptop or desktop computer.
` : `
`
: `
MyEtherWallet requires certain features for secure wallet generation
that your browser doesn't offer. You can still securely use the site
otherwise. To generate a wallet, upgrade to one of the following
Expand All @@ -42,7 +48,7 @@ const CryptoWarning: React.SFC<{}> = () =>
</p>

<div className="CryptoWarning-browsers">
{BROWSERS.map((browser) =>
{BROWSERS.map(browser => (
<NewTabLink
key={browser.href}
href={browser.href}
Expand All @@ -58,9 +64,10 @@ const CryptoWarning: React.SFC<{}> = () =>
</div>
</div>
</NewTabLink>
)}
))}
</div>
</div>
</div>
);

export default CryptoWarning;
79 changes: 28 additions & 51 deletions common/containers/Tabs/GenerateWallet/components/DownloadWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,43 @@
import { ContinueToPaperAction } from 'actions/generateWallet';
import { getV3Filename, UtcKeystore } from 'libs/keystore';
import PrivKeyWallet from 'libs/wallet/privkey';
import { IFullWallet, IV3Wallet } from 'ethereumjs-wallet';
import { toChecksumAddress } from 'ethereumjs-util';
import { NewTabLink } from 'components/ui';
import React, { Component } from 'react';
import translate from 'translations';
import { makeBlob } from 'utils/blob';
import './DownloadWallet.scss';
import Template from './Template';

interface Props {
wallet: PrivKeyWallet;
wallet: IFullWallet;
password: string;
continueToPaper(): ContinueToPaperAction;
}

interface State {
hasDownloadedWallet: boolean;
address: string;
keystore: UtcKeystore | null;
keystore: IV3Wallet | null;
}

export default class DownloadWallet extends Component<Props, State> {
public state: State = {
hasDownloadedWallet: false,
address: '',
keystore: null
};

public componentDidMount() {
this.props.wallet.getAddress().then(address => {
this.setState({ address });
});
}

public componentWillMount() {
this.props.wallet.toKeystore(this.props.password).then(utcKeystore => {
this.setState({ keystore: utcKeystore });
});
this.setWallet(this.props.wallet, this.props.password);
}

public componentWillUpdate(nextProps: Props) {
if (this.props.wallet !== nextProps.wallet) {
nextProps.wallet.toKeystore(nextProps.password).then(utcKeystore => {
this.setState({ keystore: utcKeystore });
});
this.setWallet(nextProps.wallet, nextProps.password);
}
}

public render() {
const { hasDownloadedWallet } = this.state;
const filename = this.getFilename();
const filename = this.props.wallet.getV3Filename();

const content = (
<div className="DlWallet">
Expand Down Expand Up @@ -112,22 +102,14 @@ export default class DownloadWallet extends Component<Props, State> {
<h4>{translate('GEN_Help_4')}</h4>
<ul>
<li>
<a
href="https://myetherwallet.groovehq.com/knowledge_base/topics/how-do-i-save-slash-backup-my-wallet"
target="_blank"
rel="noopener"
>
<NewTabLink href="https://myetherwallet.groovehq.com/knowledge_base/topics/how-do-i-save-slash-backup-my-wallet">
<strong>{translate('GEN_Help_13')}</strong>
</a>
</NewTabLink>
</li>
<li>
<a
href="https://myetherwallet.groovehq.com/knowledge_base/topics/what-are-the-different-formats-of-a-private-key"
target="_blank"
rel="noopener"
>
<NewTabLink href="https://myetherwallet.groovehq.com/knowledge_base/topics/what-are-the-different-formats-of-a-private-key">
<strong>{translate('GEN_Help_14')}</strong>
</a>
</NewTabLink>
</li>
</ul>
</div>
Expand All @@ -136,28 +118,23 @@ export default class DownloadWallet extends Component<Props, State> {
return <Template content={content} help={help} />;
}

public getBlob() {
if (this.state.keystore) {
return makeBlob('text/json;charset=UTF-8', this.state.keystore);
}
}
public getBlob = () =>
(this.state.keystore &&
makeBlob('text/json;charset=UTF-8', this.state.keystore)) ||
undefined;

public getFilename() {
return getV3Filename(this.state.address);
}
private markDownloaded = () => {
if (this.state.keystore) {
this.setState({ hasDownloadedWallet: true });
}
};
private markDownloaded = () =>
this.state.keystore && this.setState({ hasDownloadedWallet: true });

private handleContinue = () => {
if (this.state.hasDownloadedWallet) {
this.props.continueToPaper();
}
};
private handleContinue = () =>
this.state.hasDownloadedWallet && this.props.continueToPaper();

private handleDownloadKeystore = (e): void => {
private setWallet(wallet: IFullWallet, password: string) {
const keystore = wallet.toV3(password, { n: 1024 });
keystore.address = toChecksumAddress(keystore.address);
this.setState({ keystore });
}

private handleDownloadKeystore = e =>
this.state.keystore ? this.markDownloaded() : e.preventDefault();
};
}
Loading

0 comments on commit 3bea632

Please sign in to comment.