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 {
const seed = mnemonicGenerate(length);
private seedCreate ({ length = SEED_DEFAULT_LENGTH, seed: _seed, type }: RequestSeedCreate): ResponseSeedCreate {
const seed = _seed || mnemonicGenerate(length);
return {
address: keyring.createFromUri(getSuri(seed, type), {}, type).address,

View File

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

View File

@ -6,13 +6,15 @@ import React, { useCallback, useContext, useState } from 'react';
import { QrScanAddress } from '@polkadot/react-qr';
import { ActionContext, Address, ButtonArea, NextStepButton, VerticalSpace } from '../components';
import AccountNamePasswordCreation from '../components/AccountNamePasswordCreation';
import useTranslation from '../hooks/useTranslation';
import { createAccountExternal } from '../messaging';
import { createAccountExternal, createAccountSuri, createSeed } from '../messaging';
import { Header, Name } from '../partials';
interface QrAccount {
content: string;
genesisHash: string;
isAddress: boolean;
name?: string;
}
@ -20,12 +22,22 @@ export default function ImportQr (): React.ReactElement {
const { t } = useTranslation();
const onAction = useContext(ActionContext);
const [account, setAccount] = useState<QrAccount | null>(null);
const [address, setAddress] = useState<string | null>(null);
const [name, setName] = useState<string | null>(null);
const [password, setPassword] = useState<string | null>(null);
const _setAccount = useCallback(
(qrAccount: QrAccount) => {
setAccount(qrAccount);
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(
(): void => {
if (account && name) {
createAccountExternal(name, account.content, account.genesisHash)
.then(() => onAction('/'))
.catch((error: Error) => console.error(error));
if (account.isAddress) {
createAccountExternal(name, account.content, account.genesisHash)
.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 (
@ -57,20 +75,32 @@ export default function ImportQr (): React.ReactElement {
<div>
<Address
{...account}
address={account.content}
address={address}
isExternal={true}
name={name}
/>
</div>
<Name
isFocused
onChange={setName}
value={name || ''}
/>
{account.isAddress
? (
<Name
isFocused
onChange={setName}
value={name || ''}
/>
)
: (
<AccountNamePasswordCreation
isBusy={false}
onCreate={_onCreate}
onNameChange={setName}
onPasswordChange={setPassword}
/>
)
}
<VerticalSpace />
<ButtonArea>
<NextStepButton
isDisabled={!name}
isDisabled={!name || (!account.isAddress && !password)}
onClick={_onCreate}
>
{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 '.';
interface Props {
buttonLabel: string;
buttonLabel?: string;
isBusy: boolean;
onBackClick: () => void;
onBackClick?: () => void;
onCreate: (name: string, password: string) => void | Promise<void | boolean>;
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 [password, setPassword] = useState<string | null>(null);
@ -31,11 +32,19 @@ function AccountNamePasswordCreation ({ buttonLabel, isBusy, onBackClick, onCrea
[onNameChange]
);
const _onPasswordChange = useCallback(
(password: string | null) => {
onPasswordChange && onPasswordChange(password || '');
setPassword(password);
},
[onPasswordChange]
);
const _onBackClick = useCallback(
() => {
_onNameChange(null);
setPassword(null);
onBackClick();
onBackClick && onBackClick();
},
[_onNameChange, onBackClick]
);
@ -46,19 +55,21 @@ function AccountNamePasswordCreation ({ buttonLabel, isBusy, onBackClick, onCrea
isFocused
onChange={_onNameChange}
/>
<Password onChange={setPassword} />
<Password onChange={_onPasswordChange} />
<VerticalSpace />
<ButtonArea>
<BackButton onClick={_onBackClick} />
<NextStepButton
data-button-action='add new root'
isBusy={isBusy}
isDisabled={!password || !name}
onClick={_onCreate}
>
{buttonLabel}
</NextStepButton>
</ButtonArea>
{onBackClick && buttonLabel && (
<ButtonArea>
<BackButton onClick={_onBackClick} />
<NextStepButton
data-button-action='add new root'
isBusy={isBusy}
isDisabled={!password || !name}
onClick={_onCreate}
>
{buttonLabel}
</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 });
}
export async function createSeed (length?: SeedLengths, type?: KeypairType): Promise<{ address: string; seed: string }> {
return sendMessage('pri(seed.create)', { length, type });
export async function createSeed (length?: SeedLengths, seed?: string, type?: KeypairType): Promise<{ address: string; seed: string }> {
return sendMessage('pri(seed.create)', { length, seed, type });
}
export async function getAllMetatdata (): Promise<MetadataDef[]> {