Block invalid account name creation (#5784)

* Additional non-empty phrase check (fromNew)

* Explicit canCreate check in create (not only on UI)

* BN instance check (fixes Geth imports)

* Fixup tests after better checks

* PR comments (Thanks @tomusdrw )

* Typo
This commit is contained in:
Jaco Greeff 2017-06-07 16:27:01 +02:00 committed by Arkadiy Paronyan
parent 9773aa4c76
commit 882f963e6b
5 changed files with 63 additions and 20 deletions

View File

@ -329,17 +329,13 @@ class CreateAccount extends Component {
} }
onCreate = () => { onCreate = () => {
this.createStore.setBusy(true);
return this.createStore return this.createStore
.createAccount(this.vaultStore) .createAccount(this.vaultStore)
.then(() => { .then(() => {
this.createStore.setBusy(false);
this.createStore.nextStage(); this.createStore.nextStage();
this.props.onUpdate && this.props.onUpdate(); this.props.onUpdate && this.props.onUpdate();
}) })
.catch((error) => { .catch((error) => {
this.createStore.setBusy(false);
this.props.newError(error); this.props.newError(error);
}); });
} }

View File

@ -17,6 +17,7 @@
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import sinon from 'sinon'; import sinon from 'sinon';
import Api from '~/api';
import Store from './store'; import Store from './store';
const ADDRESS = '0x00000123456789abcdef123456789abcdef123456789abcdef'; const ADDRESS = '0x00000123456789abcdef123456789abcdef123456789abcdef';
@ -45,7 +46,8 @@ function createApi () {
setAccountName: sinon.stub().resolves(), setAccountName: sinon.stub().resolves(),
listVaults: sinon.stub().resolves([]), listVaults: sinon.stub().resolves([]),
listOpenedVaults: sinon.stub().resolves([]) listOpenedVaults: sinon.stub().resolves([])
} },
util: Api.util
}; };
} }

View File

@ -70,7 +70,7 @@ export default class Store {
return !(this.nameError || this.walletFileError); return !(this.nameError || this.walletFileError);
case 'fromNew': case 'fromNew':
return !(this.nameError || this.passwordRepeatError) && this.hasAddress; return !(this.nameError || this.passwordRepeatError) && this.hasAddress && this.hasPhrase;
case 'fromPhrase': case 'fromPhrase':
return !(this.nameError || this.passwordRepeatError || this.passPhraseError); return !(this.nameError || this.passwordRepeatError || this.passPhraseError);
@ -94,6 +94,10 @@ export default class Store {
return !!(this.address); return !!(this.address);
} }
@computed get hasPhrase () {
return this.phrase.length !== 0;
}
@computed get passwordRepeatError () { @computed get passwordRepeatError () {
return this.password === this.passwordRepeat return this.password === this.passwordRepeat
? null ? null
@ -112,7 +116,7 @@ export default class Store {
this.passwordRepeat = ''; this.passwordRepeat = '';
this.phrase = ''; this.phrase = '';
this.name = ''; this.name = '';
this.nameError = null; this.nameError = ERRORS.noName;
this.qrAddress = null; this.qrAddress = null;
this.rawKey = ''; this.rawKey = '';
this.rawKeyError = null; this.rawKeyError = null;
@ -250,6 +254,10 @@ export default class Store {
} }
@action nextStage = () => { @action nextStage = () => {
if (this.stage === 0) {
this.clearErrors();
}
this.stage++; this.stage++;
} }
@ -258,6 +266,10 @@ export default class Store {
} }
createAccount = (vaultStore) => { createAccount = (vaultStore) => {
if (!this.canCreate) {
return false;
}
this.setBusy(true); this.setBusy(true);
return this return this

View File

@ -90,7 +90,7 @@ describe('modals/CreateAccount/Store', () => {
store.clearErrors(); store.clearErrors();
expect(store.name).to.equal(''); expect(store.name).to.equal('');
expect(store.nameError).to.be.null; expect(store.nameError).not.to.be.null;
expect(store.password).to.equal(''); expect(store.password).to.equal('');
expect(store.passwordRepeatError).to.be.null; expect(store.passwordRepeatError).to.be.null;
expect(store.qrAddress).to.be.null; expect(store.qrAddress).to.be.null;
@ -309,6 +309,7 @@ describe('modals/CreateAccount/Store', () => {
describe('createType === fromJSON/fromPresale', () => { describe('createType === fromJSON/fromPresale', () => {
beforeEach(() => { beforeEach(() => {
store.setCreateType('fromJSON'); store.setCreateType('fromJSON');
store.setName('blah');
}); });
it('returns true on no errors', () => { it('returns true on no errors', () => {
@ -330,6 +331,8 @@ describe('modals/CreateAccount/Store', () => {
beforeEach(() => { beforeEach(() => {
store.setCreateType('fromNew'); store.setCreateType('fromNew');
store.setAddress('0x0000000000000000000000000000000000000000'); store.setAddress('0x0000000000000000000000000000000000000000');
store.setName('blah');
store.setPhrase('testing');
}); });
it('returns true on no errors', () => { it('returns true on no errors', () => {
@ -342,6 +345,12 @@ describe('modals/CreateAccount/Store', () => {
expect(store.canCreate).to.be.false; expect(store.canCreate).to.be.false;
}); });
it('returns false on no phrase', () => {
store.setPhrase('');
expect(store.canCreate).to.be.false;
});
it('returns false on passwordRepeatError', () => { it('returns false on passwordRepeatError', () => {
store.setPassword('testing'); store.setPassword('testing');
@ -352,6 +361,7 @@ describe('modals/CreateAccount/Store', () => {
describe('createType === fromPhrase', () => { describe('createType === fromPhrase', () => {
beforeEach(() => { beforeEach(() => {
store.setCreateType('fromPhrase'); store.setCreateType('fromPhrase');
store.setName('name');
}); });
it('returns true on no errors', () => { it('returns true on no errors', () => {
@ -372,6 +382,8 @@ describe('modals/CreateAccount/Store', () => {
describe('createType === fromRaw', () => { describe('createType === fromRaw', () => {
beforeEach(() => { beforeEach(() => {
store.setCreateType('fromRaw'); store.setCreateType('fromRaw');
store.setName('name');
store.setRawKey('0x1000000000000000000000000000000000000000000000000000000000000000');
}); });
it('returns true on no errors', () => { it('returns true on no errors', () => {
@ -389,7 +401,7 @@ describe('modals/CreateAccount/Store', () => {
}); });
it('returns false on rawKeyError', () => { it('returns false on rawKeyError', () => {
store.setRawKey('testing'); store.setRawKey('0x1');
expect(store.canCreate).to.be.false; expect(store.canCreate).to.be.false;
}); });
}); });
@ -459,6 +471,9 @@ describe('modals/CreateAccount/Store', () => {
createAccountFromQrSpy = sinon.spy(store, 'createAccountFromQr'); createAccountFromQrSpy = sinon.spy(store, 'createAccountFromQr');
createAccountFromRawSpy = sinon.spy(store, 'createAccountFromRaw'); createAccountFromRawSpy = sinon.spy(store, 'createAccountFromRaw');
busySpy = sinon.spy(store, 'setBusy'); busySpy = sinon.spy(store, 'setBusy');
store.setName('name');
store.setPhrase('testing');
}); });
afterEach(() => { afterEach(() => {
@ -477,6 +492,8 @@ describe('modals/CreateAccount/Store', () => {
it('calls createAccountFromGeth on createType === fromGeth', () => { it('calls createAccountFromGeth on createType === fromGeth', () => {
store.setCreateType('fromGeth'); store.setCreateType('fromGeth');
store.setGethAccountsAvailable(GETH_ADDRESSES);
store.selectGethAccount(GETH_ADDRESSES[0]);
return store.createAccount().then(() => { return store.createAccount().then(() => {
expect(createAccountFromGethSpy).to.have.been.called; expect(createAccountFromGethSpy).to.have.been.called;
@ -485,6 +502,8 @@ describe('modals/CreateAccount/Store', () => {
it('calls createAccountFromWallet on createType === fromJSON', () => { it('calls createAccountFromWallet on createType === fromJSON', () => {
store.setCreateType('fromJSON'); store.setCreateType('fromJSON');
store.setName('name');
store.setWalletJson('{}');
return store.createAccount().then(() => { return store.createAccount().then(() => {
expect(createAccountFromWalletSpy).to.have.been.called; expect(createAccountFromWalletSpy).to.have.been.called;
@ -493,6 +512,9 @@ describe('modals/CreateAccount/Store', () => {
it('calls createAccountFromPhrase on createType === fromNew', () => { it('calls createAccountFromPhrase on createType === fromNew', () => {
store.setCreateType('fromNew'); store.setCreateType('fromNew');
store.setName('name');
store.setPhrase('phrase');
store.setAddress('0x1234567890123456789012345678901234567890');
return store.createAccount().then(() => { return store.createAccount().then(() => {
expect(createAccountFromPhraseSpy).to.have.been.called; expect(createAccountFromPhraseSpy).to.have.been.called;
@ -501,6 +523,9 @@ describe('modals/CreateAccount/Store', () => {
it('calls createAccountFromPhrase on createType === fromPhrase', () => { it('calls createAccountFromPhrase on createType === fromPhrase', () => {
store.setCreateType('fromPhrase'); store.setCreateType('fromPhrase');
store.setName('name');
store.setPhrase('phrase');
store.setAddress('0x1234567890123456789012345678901234567890');
return store.createAccount().then(() => { return store.createAccount().then(() => {
expect(createAccountFromPhraseSpy).to.have.been.called; expect(createAccountFromPhraseSpy).to.have.been.called;
@ -509,6 +534,8 @@ describe('modals/CreateAccount/Store', () => {
it('calls createAccountFromWallet on createType === fromPresale', () => { it('calls createAccountFromWallet on createType === fromPresale', () => {
store.setCreateType('fromPresale'); store.setCreateType('fromPresale');
store.setName('name');
store.setWalletJson('{}');
return store.createAccount().then(() => { return store.createAccount().then(() => {
expect(createAccountFromWalletSpy).to.have.been.called; expect(createAccountFromWalletSpy).to.have.been.called;
@ -517,6 +544,8 @@ describe('modals/CreateAccount/Store', () => {
it('calls createAccountFromQr on createType === fromQr', () => { it('calls createAccountFromQr on createType === fromQr', () => {
store.setCreateType('fromQr'); store.setCreateType('fromQr');
store.setQrAddress('0x1234567890123456789012345678901234567890');
store.setName('name');
return store.createAccount().then(() => { return store.createAccount().then(() => {
expect(createAccountFromQrSpy).to.have.been.called; expect(createAccountFromQrSpy).to.have.been.called;
@ -525,6 +554,8 @@ describe('modals/CreateAccount/Store', () => {
it('calls createAccountFromRaw on createType === fromRaw', () => { it('calls createAccountFromRaw on createType === fromRaw', () => {
store.setCreateType('fromRaw'); store.setCreateType('fromRaw');
store.setName('name');
store.setRawKey('0x1000000000000000000000000000000000000000000000000000000000000000');
return store.createAccount().then(() => { return store.createAccount().then(() => {
expect(createAccountFromRawSpy).to.have.been.called; expect(createAccountFromRawSpy).to.have.been.called;
@ -534,6 +565,9 @@ describe('modals/CreateAccount/Store', () => {
it('moves account to vault when vaultName set', () => { it('moves account to vault when vaultName set', () => {
store.setCreateType('fromNew'); store.setCreateType('fromNew');
store.setVaultName('testing'); store.setVaultName('testing');
store.setName('name');
store.setAddress('0x1234567890123456789012345678901234567890');
store.setPhrase('phrase');
return store.createAccount(vaultStore).then(() => { return store.createAccount(vaultStore).then(() => {
expect(vaultStore.moveAccount).to.have.been.calledWith('testing', ADDRESS); expect(vaultStore.moveAccount).to.have.been.calledWith('testing', ADDRESS);
@ -542,6 +576,9 @@ describe('modals/CreateAccount/Store', () => {
it('sets and rests the busy flag', () => { it('sets and rests the busy flag', () => {
store.setCreateType('fromNew'); store.setCreateType('fromNew');
store.setName('name');
store.setAddress('0x1234567890123456789012345678901234567890');
store.setPhrase('phrase');
return store.createAccount().then(() => { return store.createAccount().then(() => {
expect(busySpy).to.have.been.calledWith(true); expect(busySpy).to.have.been.calledWith(true);
@ -634,22 +671,18 @@ describe('modals/CreateAccount/Store', () => {
beforeEach(() => { beforeEach(() => {
store.setName('some name'); store.setName('some name');
store.setDescription('some desc'); store.setDescription('some desc');
store.setQrAddress('0x123'); store.setQrAddress('0x1234567890123456789012345678901234567890');
sinon.spy(store, 'setupMeta');
return store.createAccountFromQr(-1); return store.createAccountFromQr(-1);
}); });
it('sets the accountInfo name', () => { afterEach(() => {
expect(api.parity.setAccountName).to.have.been.calledWith('0x123', 'some name'); store.setupMeta.restore();
}); });
it('sets the meta (with extrenal flag)', () => { it('sets the meta', () => {
expect(api.parity.setAccountMeta).to.have.been.calledWith('0x123', { expect(store.setupMeta).to.have.been.called;
description: 'some desc',
passwordHint: '',
timestamp: -1,
external: true
});
}); });
}); });

View File

@ -56,7 +56,7 @@ export class Balance extends Component {
const isEthToken = token.native; const isEthToken = token.native;
const isFullToken = !showOnlyEth || isEthToken; const isFullToken = !showOnlyEth || isEthToken;
const hasBalance = balanceValue.gt(0); const hasBalance = (balanceValue instanceof BigNumber) && balanceValue.gt(0);
if (!hasBalance && !isEthToken) { if (!hasBalance && !isEthToken) {
return null; return null;