Allow for creation via QR seed (#918)

This commit is contained in:
Jaco 2021-12-10 09:19:29 +01:00 committed by GitHub
parent 4e98ce540e
commit 9e9911dc8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 74 additions and 32 deletions

View File

@ -304,8 +304,8 @@ export default class Extension {
} }
} }
private seedCreate ({ length = SEED_DEFAULT_LENGTH, type }: RequestSeedCreate): ResponseSeedCreate { private seedCreate ({ length = SEED_DEFAULT_LENGTH, seed: _seed, type }: RequestSeedCreate): ResponseSeedCreate {
const seed = mnemonicGenerate(length); const seed = _seed || mnemonicGenerate(length);
return { return {
address: keyring.createFromUri(getSuri(seed, type), {}, type).address, address: keyring.createFromUri(getSuri(seed, type), {}, type).address,

View File

@ -297,6 +297,7 @@ export type RequestSigningSubscribe = null;
export interface RequestSeedCreate { export interface RequestSeedCreate {
length?: SeedLengths; length?: SeedLengths;
seed?: string;
type?: KeypairType; type?: KeypairType;
} }

View File

@ -6,13 +6,15 @@ import React, { useCallback, useContext, useState } from 'react';
import { QrScanAddress } from '@polkadot/react-qr'; import { QrScanAddress } from '@polkadot/react-qr';
import { ActionContext, Address, ButtonArea, NextStepButton, VerticalSpace } from '../components'; import { ActionContext, Address, ButtonArea, NextStepButton, VerticalSpace } from '../components';
import AccountNamePasswordCreation from '../components/AccountNamePasswordCreation';
import useTranslation from '../hooks/useTranslation'; import useTranslation from '../hooks/useTranslation';
import { createAccountExternal } from '../messaging'; import { createAccountExternal, createAccountSuri, createSeed } from '../messaging';
import { Header, Name } from '../partials'; import { Header, Name } from '../partials';
interface QrAccount { interface QrAccount {
content: string; content: string;
genesisHash: string; genesisHash: string;
isAddress: boolean;
name?: string; name?: string;
} }
@ -20,12 +22,22 @@ export default function ImportQr (): React.ReactElement {
const { t } = useTranslation(); const { t } = useTranslation();
const onAction = useContext(ActionContext); const onAction = useContext(ActionContext);
const [account, setAccount] = useState<QrAccount | null>(null); const [account, setAccount] = useState<QrAccount | null>(null);
const [address, setAddress] = useState<string | null>(null);
const [name, setName] = useState<string | null>(null); const [name, setName] = useState<string | null>(null);
const [password, setPassword] = useState<string | null>(null);
const _setAccount = useCallback( const _setAccount = useCallback(
(qrAccount: QrAccount) => { (qrAccount: QrAccount) => {
setAccount(qrAccount); setAccount(qrAccount);
setName(qrAccount?.name || null); setName(qrAccount?.name || null);
if (qrAccount.isAddress) {
setAddress(qrAccount.content);
} else {
createSeed(undefined, qrAccount.content)
.then(({ address }) => setAddress(address))
.catch(console.error);
}
}, },
[] []
); );
@ -33,12 +45,18 @@ export default function ImportQr (): React.ReactElement {
const _onCreate = useCallback( const _onCreate = useCallback(
(): void => { (): void => {
if (account && name) { if (account && name) {
createAccountExternal(name, account.content, account.genesisHash) if (account.isAddress) {
.then(() => onAction('/')) createAccountExternal(name, account.content, account.genesisHash)
.catch((error: Error) => console.error(error)); .then(() => onAction('/'))
.catch((error: Error) => console.error(error));
} else if (password) {
createAccountSuri(name, password, account.content, 'sr25519', account.genesisHash)
.then(() => onAction('/'))
.catch((error: Error) => console.error(error));
}
} }
}, },
[account, name, onAction] [account, name, onAction, password]
); );
return ( return (
@ -57,20 +75,32 @@ export default function ImportQr (): React.ReactElement {
<div> <div>
<Address <Address
{...account} {...account}
address={account.content} address={address}
isExternal={true} isExternal={true}
name={name} name={name}
/> />
</div> </div>
<Name {account.isAddress
isFocused ? (
onChange={setName} <Name
value={name || ''} isFocused
/> onChange={setName}
value={name || ''}
/>
)
: (
<AccountNamePasswordCreation
isBusy={false}
onCreate={_onCreate}
onNameChange={setName}
onPasswordChange={setPassword}
/>
)
}
<VerticalSpace /> <VerticalSpace />
<ButtonArea> <ButtonArea>
<NextStepButton <NextStepButton
isDisabled={!name} isDisabled={!name || (!account.isAddress && !password)}
onClick={_onCreate} onClick={_onCreate}
> >
{t<string>('Add the account with identified address')} {t<string>('Add the account with identified address')}

View File

@ -7,14 +7,15 @@ import { Name, Password } from '../partials';
import { BackButton, ButtonArea, NextStepButton, VerticalSpace } from '.'; import { BackButton, ButtonArea, NextStepButton, VerticalSpace } from '.';
interface Props { interface Props {
buttonLabel: string; buttonLabel?: string;
isBusy: boolean; isBusy: boolean;
onBackClick: () => void; onBackClick?: () => void;
onCreate: (name: string, password: string) => void | Promise<void | boolean>; onCreate: (name: string, password: string) => void | Promise<void | boolean>;
onNameChange: (name: string) => void; onNameChange: (name: string) => void;
onPasswordChange?: (password: string) => void;
} }
function AccountNamePasswordCreation ({ buttonLabel, isBusy, onBackClick, onCreate, onNameChange }: Props): React.ReactElement<Props> { function AccountNamePasswordCreation ({ buttonLabel, isBusy, onBackClick, onCreate, onNameChange, onPasswordChange }: Props): React.ReactElement<Props> {
const [name, setName] = useState<string | null>(null); const [name, setName] = useState<string | null>(null);
const [password, setPassword] = useState<string | null>(null); const [password, setPassword] = useState<string | null>(null);
@ -31,11 +32,19 @@ function AccountNamePasswordCreation ({ buttonLabel, isBusy, onBackClick, onCrea
[onNameChange] [onNameChange]
); );
const _onPasswordChange = useCallback(
(password: string | null) => {
onPasswordChange && onPasswordChange(password || '');
setPassword(password);
},
[onPasswordChange]
);
const _onBackClick = useCallback( const _onBackClick = useCallback(
() => { () => {
_onNameChange(null); _onNameChange(null);
setPassword(null); setPassword(null);
onBackClick(); onBackClick && onBackClick();
}, },
[_onNameChange, onBackClick] [_onNameChange, onBackClick]
); );
@ -46,19 +55,21 @@ function AccountNamePasswordCreation ({ buttonLabel, isBusy, onBackClick, onCrea
isFocused isFocused
onChange={_onNameChange} onChange={_onNameChange}
/> />
<Password onChange={setPassword} /> <Password onChange={_onPasswordChange} />
<VerticalSpace /> <VerticalSpace />
<ButtonArea> {onBackClick && buttonLabel && (
<BackButton onClick={_onBackClick} /> <ButtonArea>
<NextStepButton <BackButton onClick={_onBackClick} />
data-button-action='add new root' <NextStepButton
isBusy={isBusy} data-button-action='add new root'
isDisabled={!password || !name} isBusy={isBusy}
onClick={_onCreate} isDisabled={!password || !name}
> onClick={_onCreate}
{buttonLabel} >
</NextStepButton> {buttonLabel}
</ButtonArea> </NextStepButton>
</ButtonArea>
)}
</> </>
); );
} }

View File

@ -132,8 +132,8 @@ export async function createAccountSuri (name: string, password: string, suri: s
return sendMessage('pri(accounts.create.suri)', { genesisHash, name, password, suri, type }); return sendMessage('pri(accounts.create.suri)', { genesisHash, name, password, suri, type });
} }
export async function createSeed (length?: SeedLengths, type?: KeypairType): Promise<{ address: string; seed: string }> { export async function createSeed (length?: SeedLengths, seed?: string, type?: KeypairType): Promise<{ address: string; seed: string }> {
return sendMessage('pri(seed.create)', { length, type }); return sendMessage('pri(seed.create)', { length, seed, type });
} }
export async function getAllMetatdata (): Promise<MetadataDef[]> { export async function getAllMetatdata (): Promise<MetadataDef[]> {