Skip to content
This repository has been archived by the owner on May 24, 2022. It is now read-only.

Integrate Parity Signer into Fether #336

Merged
merged 15 commits into from
Jan 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions packages/fether-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,18 @@
},
"dependencies": {
"@craco/craco": "^3.2.3",
"@parity/api": "^3.0.11",
"@parity/contracts": "^3.0.11",
"@parity/light.js": "^3.0.11",
"@parity/light.js-react": "^3.0.11",
"@parity/abi": "^3.0.25",
"@parity/api": "^3.0.25",
"@parity/contracts": "^3.0.25",
"@parity/light.js": "^3.0.25",
"@parity/light.js-react": "^3.0.25",
"@parity/qr-signer": "^0.3.2",
"bignumber.js": "^8.0.1",
"bip39": "^2.5.0",
"debounce-promise": "^3.1.0",
"debug": "^4.1.0",
"ethereumjs-tx": "^1.3.7",
"ethereumjs-util": "^6.0.0",
"ethereumjs-wallet": "^0.6.2",
"fether-ui": "^0.2.0",
"file-saver": "^2.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/fether-react/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="Content-Security-Policy" content="default-src 'self';script-src file: http: 'unsafe-inline'; connect-src file: http: https: ws: wss:;img-src 'self' 'unsafe-inline' file: data: blob: http: https:;style-src 'unsafe-inline' file:;">
<meta http-equiv="Content-Security-Policy" content="default-src 'self';script-src file: http: blob: 'unsafe-inline'; connect-src file: http: https: ws: wss:;img-src 'self' 'unsafe-inline' file: data: blob: http: https:;style-src 'unsafe-inline' file:;">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
Expand Down
25 changes: 13 additions & 12 deletions packages/fether-react/src/Accounts/AccountsList/AccountsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@

import React, { Component } from 'react';
import { AccountCard, Clickable, Header } from 'fether-ui';
import { accountsInfo$, withoutLoading } from '@parity/light.js';
import { chainId$, withoutLoading } from '@parity/light.js';
import { inject, observer } from 'mobx-react';
import light from '@parity/light.js-react';

import Health from '../../Health';
import Feedback from './Feedback';
import withAccountsInfo from '../../utils/withAccountsInfo';

@withAccountsInfo
@inject('createAccountStore', 'parityStore')
@light({
accountsInfo: () => accountsInfo$().pipe(withoutLoading())
chainId: () => chainId$().pipe(withoutLoading())
})
@inject('createAccountStore', 'parityStore')
@observer
class AccountsList extends Component {
handleClick = ({
Expand All @@ -34,9 +36,13 @@ class AccountsList extends Component {
};

render () {
const { accountsInfo } = this.props;
const { accountsInfo, chainId } = this.props;

const accountsList = Object.keys(accountsInfo);
const accountsList = Object.keys(accountsInfo).filter(
key =>
!accountsInfo[key].chainId ||
accountsInfo[key].chainId === parseInt(chainId, 10)
);
const accountsListLength = accountsList && accountsList.length;

return (
Expand Down Expand Up @@ -64,13 +70,8 @@ class AccountsList extends Component {
<AccountCard
address={address}
className='-clickable'
name={
accountsInfo &&
accountsInfo[address] &&
(accountsInfo[address].name
? accountsInfo[address].name
: '(No name)')
}
type={accountsInfo[address].type}
name={accountsInfo[address].name || '(no name)'}
shortAddress
/>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@

import React, { Component } from 'react';
import { addressShort, Card, Form as FetherForm } from 'fether-ui';
import { accounts$, withoutLoading } from '@parity/light.js';
import light from '@parity/light.js-react';
import { inject, observer } from 'mobx-react';

@light({
accounts: () => accounts$().pipe(withoutLoading())
})
import Scanner from '../../../Scanner';
import withAccountsInfo from '../../../utils/withAccountsInfo';

@withAccountsInfo
@inject('createAccountStore')
@observer
class AccountImportOptions extends Component {
state = {
error: '',
isLoading: false,
phrase: ''
phrase: '',
importingFromSigner: false
};

handleNextStep = async () => {
Expand Down Expand Up @@ -87,11 +87,42 @@ class AccountImportOptions extends Component {
}
};

hasExistingAddressForImport = addressForImport => {
const { accounts } = this.props;
const isExistingAddress = accounts
.map(address => address && address.toLowerCase())
.includes(addressForImport.toLowerCase());
handleSignerImported = async ({ address, chainId: chainIdString }) => {
const {
createAccountStore: { importFromSigner }
} = this.props;

if (!address || !chainIdString) {
this.setState({ error: 'Invalid QR code.' });
return;
}

const chainId = parseInt(chainIdString);

if (this.hasExistingAddressForImport(address, chainId)) {
return;
}

await importFromSigner({ address, chainId });

this.handleNextStep();
};

handleSignerImport = () => {
this.setState({
importingFromSigner: true
});
};

hasExistingAddressForImport = (addressForImport, chainId) => {
const { accountsInfo } = this.props;
const isExistingAddress = Object.keys(accountsInfo).some(
key =>
key.toLowerCase() === addressForImport.toLowerCase() &&
(!accountsInfo[key].chainId ||
!chainId ||
accountsInfo[key].chainId === chainId)
);

if (isExistingAddress) {
this.setState({
Expand All @@ -108,46 +139,76 @@ class AccountImportOptions extends Component {
history,
location: { pathname }
} = this.props;
const { error, phrase } = this.state;
const { error, importingFromSigner, phrase } = this.state;
const currentStep = pathname.slice(-1);

const jsonCard = (
<div key='createAccount'>
<div className='text -centered'>
<p> Recover from JSON Keyfile </p>

<FetherForm.InputFile
label='JSON Backup Keyfile'
onChangeFile={this.handleChangeFile}
required
/>
<Card>
<div key='createAccount'>
<div className='text -centered'>
<p>Recover from JSON Keyfile</p>

<FetherForm.InputFile
label='JSON Backup Keyfile'
onChangeFile={this.handleChangeFile}
required
/>
</div>
</div>
</div>
</Card>
);

const signerCard = (
<Card>
<div key='createAccount'>
<div className='text -centered'>
<p>Recover from Parity Signer</p>

{importingFromSigner ? (
<Scanner
onScan={this.handleSignerImported}
label='Please show the QR code of the account on the webcam.'
/>
) : (
<button
className='button -footer'
onClick={this.handleSignerImport}
>
Scan QR code
</button>
)}
</div>
</div>
</Card>
);

const phraseCard = (
<div key='importBackup'>
<div className='text -centered'>
<p>Recover from Seed Phrase</p>

<FetherForm.Field
as='textarea'
label='Recovery phrase'
onChange={this.handlePhraseChange}
required
phrase={phrase}
/>

{this.renderButton()}
<Card>
<div key='importBackup'>
<div className='text -centered'>
<p>Recover from Seed Phrase</p>

<FetherForm.Field
as='textarea'
label='Recovery phrase'
onChange={this.handlePhraseChange}
required
phrase={phrase}
/>

{this.renderButton()}
</div>
</div>
</div>
</Card>
);

return (
<div className='center-md'>
<Card> {jsonCard} </Card>
{!importingFromSigner && jsonCard}
<br />
{signerCard}
<br />
<Card> {phraseCard} </Card>
{!importingFromSigner && phraseCard}
<br />
<p>{error}</p>
<nav className='form-nav -space-around'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,32 @@ class AccountName extends Component {

handleSubmit = () => {
const {
createAccountStore,
history,
location: { pathname }
} = this.props;

const currentStep = pathname.slice(-1);

history.push(`/accounts/new/${+currentStep + 1}`);
if (createAccountStore.noPrivateKey) {
// Save Signer account to Parity without asking for a password
createAccountStore
.saveAccountToParity()
.then(res => {
createAccountStore.clear();
history.push('/accounts');
})
.catch(err => {
console.error(err);

this.setState({
error: err.text
});
});
} else {
// Ask for a password otherwise
history.push(`/accounts/new/${+currentStep + 1}`);
}
};

render () {
Expand All @@ -45,12 +64,13 @@ class AccountName extends Component {

renderCardWhenImported = () => {
const {
createAccountStore: { address, name }
createAccountStore: { address, name, noPrivateKey }
} = this.props;

return (
<AccountCard
address={address}
type={noPrivateKey ? 'signer' : 'node'}
drawers={[this.renderDrawer()]}
name={name || '(no name)'}
/>
Expand Down Expand Up @@ -89,6 +109,7 @@ class AccountName extends Component {
renderDrawer = () => {
const {
createAccountStore: { address, name },
error,
history,
location: { pathname }
} = this.props;
Expand All @@ -107,6 +128,7 @@ class AccountName extends Component {
type='text'
value={name}
/>
{error && <p>{error}</p>}
<nav className='form-nav -space-around'>
{currentStep > 1 && (
<button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AccountPassword extends Component {
const { createAccountStore, history } = this.props;
const { confirm, password } = this.state;

event && event.preventDefault();
event.preventDefault();

if (!createAccountStore.jsonString && confirm !== password) {
this.setState({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
// SPDX-License-Identifier: BSD-3-Clause

import React, { Component } from 'react';
import { accountsInfo$ } from '@parity/light.js';
import { Header } from 'fether-ui';
import { inject, observer } from 'mobx-react';
import light from '@parity/light.js-react';
import { Link, Route } from 'react-router-dom';

import AccountCopyPhrase from './AccountCopyPhrase';
Expand All @@ -16,9 +14,10 @@ import AccountRewritePhrase from './AccountRewritePhrase';
import AccountName from './AccountName';
import AccountPassword from './AccountPassword';
import Health from '../../Health';
import withAccountsInfo from '../../utils/withAccountsInfo';

@light({ accountsInfo: accountsInfo$ })
@inject('createAccountStore')
@withAccountsInfo
@observer
class CreateAccount extends Component {
constructor (props) {
Expand All @@ -45,7 +44,6 @@ class CreateAccount extends Component {
} = this.props;
createAccountStore.clear();
createAccountStore.setIsImport(!createAccountStore.isImport);

// If we were further in the account creation, go back to step 1
if (step > 1) {
history.push('/accounts/new/1');
Expand Down
Loading