Only allow ed25519 session keys in modal (#1132)

* Only allow ed25519 session keys

* Add session === stash warnings
This commit is contained in:
Jaco Greeff 2019-05-13 10:44:34 +02:00 committed by GitHub
parent 1efcd95df5
commit fbbe56e0bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 121 additions and 28 deletions

View File

@ -6,7 +6,6 @@ import { I18nProps } from '@polkadot/ui-app/types';
import BN from 'bn.js';
import React from 'react';
import { AccountId } from '@polkadot/types';
import { Button, InputAddress, InputBalance, Modal, TxButton, Dropdown } from '@polkadot/ui-app';
import translate from '../translate';
@ -14,7 +13,7 @@ import ValidateController from './ValidateController';
type Props = I18nProps & {
accountId: string,
controllerId?: AccountId | null,
controllerId?: string | null,
isOpen: boolean,
onClose: () => void
};

View File

@ -6,7 +6,6 @@ import { I18nProps } from '@polkadot/ui-app/types';
import { KeyringSectionOption } from '@polkadot/ui-keyring/options/types';
import React from 'react';
import { AccountId } from '@polkadot/types';
import { Button, InputAddress, Modal, TxButton } from '@polkadot/ui-app';
import translate from '../translate';
@ -15,7 +14,7 @@ type Props = I18nProps & {
accountId: string,
isOpen: boolean,
onClose: () => void,
stashId: AccountId,
stashId: string,
stashOptions: Array<KeyringSectionOption>
};

View File

@ -7,15 +7,18 @@ import { I18nProps } from '@polkadot/ui-app/types';
import React from 'react';
import { Button, InputAddress, Modal, TxButton } from '@polkadot/ui-app';
import ValidateSession from './ValidateSession';
import translate from '../translate';
type Props = I18nProps & {
accountId: string,
isOpen: boolean,
onClose: () => void
onClose: () => void,
stashId: string
};
type State = {
sessionError: string | null,
sessionId: string
};
@ -26,13 +29,14 @@ class Key extends React.PureComponent<Props, State> {
super(props);
this.state = {
sessionError: null,
sessionId: props.accountId
};
}
render () {
const { accountId, isOpen, onClose, t } = this.props;
const { sessionId } = this.state;
const { sessionError, sessionId } = this.state;
if (!isOpen) {
return null;
@ -56,7 +60,7 @@ class Key extends React.PureComponent<Props, State> {
<Button.Or />
<TxButton
accountId={accountId}
isDisabled={!sessionId}
isDisabled={!sessionId || !!sessionError}
isPrimary
label={t('Set Session Key')}
onClick={onClose}
@ -70,7 +74,7 @@ class Key extends React.PureComponent<Props, State> {
}
private renderContent () {
const { accountId, t } = this.props;
const { accountId, stashId, t } = this.props;
const { sessionId } = this.state;
return (
@ -93,6 +97,12 @@ class Key extends React.PureComponent<Props, State> {
value={sessionId}
type='account'
/>
<ValidateSession
controllerId={accountId}
onError={this.onSessionError}
sessionId={sessionId}
stashId={stashId}
/>
</Modal.Content>
</>
);
@ -101,6 +111,10 @@ class Key extends React.PureComponent<Props, State> {
private onChangeSession = (sessionId: string) => {
this.setState({ sessionId });
}
private onSessionError = (sessionError: string | null) => {
this.setState({ sessionError });
}
}
export default translate(Key);

View File

@ -2,7 +2,6 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId } from '@polkadot/types';
import BN from 'bn.js';
import { Button, InputAddress, InputBalance, Modal, TxButton } from '@polkadot/ui-app';
import { I18nProps } from '@polkadot/ui-app/types';
@ -11,7 +10,7 @@ import React from 'react';
import translate from '../translate';
type Props = I18nProps & {
controllerId?: AccountId | null,
controllerId?: string | null,
isOpen: boolean,
onClose: () => void
};
@ -49,7 +48,7 @@ class Unbond extends React.PureComponent<Props, State> {
/>
<Button.Or />
<TxButton
accountId={controllerId && controllerId.toString()}
accountId={controllerId}
isDisabled={!canSubmit}
isPrimary
label={t('Unbond')}
@ -74,7 +73,7 @@ class Unbond extends React.PureComponent<Props, State> {
<Modal.Content className='ui--signer-Signer-Content'>
<InputAddress
className='medium'
defaultValue={controllerId && controllerId.toString()}
defaultValue={controllerId}
isDisabled
label={t('controler account')}
/>

View File

@ -0,0 +1,71 @@
// Copyright 2017-2019 @polkadot/ui-staking authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { I18nProps } from '@polkadot/ui-app/types';
import React from 'react';
import { Icon } from '@polkadot/ui-app';
import keyring from '@polkadot/ui-keyring';
import translate from '../translate';
type Props = I18nProps & {
controllerId: string,
onError: (error: string | null) => void,
sessionId: string,
stashId: string
};
type State = {
error: string | null
};
class ValidateSession extends React.PureComponent<Props, State> {
state: State = {
error: null
};
static getDerivedStateFromProps ({ onError, sessionId, stashId, t }: Props, prevState: State): State | null {
let error = null;
try {
const pair = keyring.getPair(sessionId);
if (pair.type !== 'ed25519') {
error = t('The selected account is not an ed25519 (Edwards) account as required for validation');
} else if (sessionId === stashId) {
error = t('For fund security, your session key should not match your stash key.');
} else {
error = null;
}
} catch (e) {
// this _should_ never happen...
error = t('The account {{sessionId}} is not a valid account', { replace: { sessionId } });
}
if (error === prevState.error) {
return null;
}
onError(error);
return { error };
}
render () {
const { error } = this.state;
if (!error) {
return null;
}
return (
<article className='warning'>
<div><Icon name='warning sign' />{error}</div>
</article>
);
}
}
export default translate(ValidateSession);

View File

@ -6,7 +6,7 @@ import { I18nProps } from '@polkadot/ui-app/types';
import BN from 'bn.js';
import React from 'react';
import { AccountId, ValidatorPrefs } from '@polkadot/types';
import { ValidatorPrefs } from '@polkadot/types';
import { Button, InputAddress, InputBalance, InputNumber, Modal, TxButton } from '@polkadot/ui-app';
import translate from '../translate';
@ -16,7 +16,7 @@ type Props = I18nProps & {
isOpen: boolean,
onClose: () => void,
preferences: ValidatorPrefs,
stashId: AccountId
stashId: string
};
type State = {

View File

@ -23,13 +23,13 @@ import Validating from './Validating';
type Props = ApiProps & I18nProps & {
accountId: string,
balances: DerivedBalancesMap,
controllerId?: AccountId | null,
controllerId?: string | null,
filter: AccountFilter,
isValidator: boolean,
name: string,
recentlyOffline: RecentlyOfflineMap,
sessionId?: AccountId | null,
stashId?: AccountId | null,
sessionId?: string | null,
stashId?: string | null,
freeBalance?: Balance,
staking_stakers?: Exposure,
staking_nominators?: [Array<AccountId>],
@ -132,11 +132,11 @@ class Account extends React.PureComponent<Props, State> {
const { isUnbondOpen } = this.state;
return (
<Unbond
controllerId={controllerId}
isOpen={isUnbondOpen}
onClose={this.toggleUnbond}
/>
<Unbond
controllerId={controllerId}
isOpen={isUnbondOpen}
onClose={this.toggleUnbond}
/>
);
}
@ -160,14 +160,19 @@ class Account extends React.PureComponent<Props, State> {
}
private renderSessionKey () {
const { accountId } = this.props;
const { accountId, stashId } = this.props;
const { isSessionKeyOpen } = this.state;
if (!stashId) {
return null;
}
return (
<SessionKey
accountId={accountId}
isOpen={isSessionKeyOpen}
onClose={this.toggleSessionKey}
stashId={stashId}
/>
);
}
@ -209,7 +214,7 @@ class Account extends React.PureComponent<Props, State> {
<label className='staking--label'>{t('controller')}</label>
<AddressMini
value={controllerId}
offlineStatus={recentlyOffline[controllerId.toString()]}
offlineStatus={recentlyOffline[controllerId]}
/>
</div>
);
@ -242,7 +247,7 @@ class Account extends React.PureComponent<Props, State> {
<label className='staking--label'>{t('stash')}</label>
<AddressMini
value={stashId}
offlineStatus={recentlyOffline[stashId.toString()]}
offlineStatus={recentlyOffline[stashId]}
withBalance={false}
withBonded
/>
@ -404,6 +409,12 @@ class Account extends React.PureComponent<Props, State> {
}
}
function toIdString (id: AccountId | null): string | null {
return id
? id.toString()
: null;
}
export default translate(
withCalls<Props>(
'query.staking.recentlyOffline',
@ -411,19 +422,19 @@ export default translate(
paramName: 'accountId',
propName: 'sessionId',
transform: (session: Option<AccountId>) =>
session.unwrapOr(null)
toIdString(session.unwrapOr(null))
}],
['query.staking.bonded', {
paramName: 'accountId',
propName: 'controllerId',
transform: (bonded: Option<AccountId>) =>
bonded.unwrapOr(null)
toIdString(bonded.unwrapOr(null))
}],
['query.staking.ledger', {
paramName: 'accountId',
propName: 'stashId',
transform: (ledger: Option<StakingLedger>) =>
ledger.unwrapOr({ stash: null }).stash
toIdString(ledger.unwrapOr({ stash: null }).stash)
}],
['query.staking.ledger', {
paramName: 'controllerId',