Only allow ed25519 session keys in modal (#1132)
* Only allow ed25519 session keys * Add session === stash warnings
This commit is contained in:
parent
1efcd95df5
commit
fbbe56e0bd
@ -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
|
||||
};
|
||||
|
||||
@ -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>
|
||||
};
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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')}
|
||||
/>
|
||||
|
||||
71
packages/app-staking/src/Account/ValidateSession.tsx
Normal file
71
packages/app-staking/src/Account/ValidateSession.tsx
Normal 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);
|
||||
@ -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 = {
|
||||
|
||||
@ -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',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user