Split messages into pub/pri (#139)
* Split messages into pub/pri * Cleanup types for contexts * genesisHash to edit/create * (Auth|Sign)Request to record (not tuple) * Align naming with messages * Pass account with SignRequest * Ordering * Ordering
This commit is contained in:
parent
251417b50e
commit
e20b6e0f16
@ -22,9 +22,9 @@ function throwError (method: string): never {
|
||||
|
||||
// internal helper to map from Array<InjectedAccount> -> Array<InjectedAccountWithMeta>
|
||||
function mapAccounts (source: string, list: InjectedAccount[]): InjectedAccountWithMeta[] {
|
||||
return list.map(({ address, name }): InjectedAccountWithMeta => ({
|
||||
return list.map(({ address, genesisHash, name }): InjectedAccountWithMeta => ({
|
||||
address,
|
||||
meta: { name, source }
|
||||
meta: { genesisHash, name, source }
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@ -11,12 +11,14 @@ export type Unsubcall = () => void;
|
||||
|
||||
export interface InjectedAccount {
|
||||
address: string;
|
||||
genesisHash?: string | null;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface InjectedAccountWithMeta {
|
||||
address: string;
|
||||
meta: {
|
||||
genesisHash?: string | null;
|
||||
name?: string;
|
||||
source: string;
|
||||
};
|
||||
|
||||
@ -13,7 +13,7 @@ export default function Authorize (): React.ReactElement<{}> {
|
||||
return (
|
||||
<div>
|
||||
<Header label='authorize' />
|
||||
{requests.map(([id, request, url], index): React.ReactNode => (
|
||||
{requests.map(({ id, request, url }, index): React.ReactNode => (
|
||||
<Request
|
||||
authId={id}
|
||||
isFirst={index === 0}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
|
||||
import { ActionContext, Address, Button, Header, Loading, TextArea } from '../components';
|
||||
import { createAccount, createSeed } from '../messaging';
|
||||
import { createAccountSuri, createSeed } from '../messaging';
|
||||
import { Back, Name, Password } from '../partials';
|
||||
|
||||
type Props = {}
|
||||
@ -26,7 +26,7 @@ export default function Create (): React.ReactElement<Props> {
|
||||
const onCreate = (): void => {
|
||||
// this should always be the case
|
||||
if (name && password && account) {
|
||||
createAccount(name, password, account.seed)
|
||||
createAccountSuri(name, password, account.seed)
|
||||
.then((): void => onAction('/'))
|
||||
.catch((error: Error) => console.error(error));
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
import React, { useContext, useState } from 'react';
|
||||
|
||||
import { ActionContext, Address, Button, Header, TextArea } from '../components';
|
||||
import { createAccount, validateSeed } from '../messaging';
|
||||
import { createAccountSuri, validateSeed } from '../messaging';
|
||||
import { Back, Name, Password } from '../partials';
|
||||
|
||||
type Props = {};
|
||||
@ -25,7 +25,7 @@ export default function Import (): React.ReactElement<Props> {
|
||||
const onCreate = (): void => {
|
||||
// this should always be the case
|
||||
if (name && password && account) {
|
||||
createAccount(name, password, account.suri)
|
||||
createAccountSuri(name, password, account.suri)
|
||||
.then((): void => onAction('/'))
|
||||
.catch((error: Error) => console.error(error));
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ import React, { useContext } from 'react';
|
||||
import { createType } from '@polkadot/types';
|
||||
|
||||
import { ActionBar, ActionContext, Address, Link } from '../../components';
|
||||
import { approveSignRequest, cancelSignRequest } from '../../messaging';
|
||||
import { approveSignPassword, cancelSignRequest } from '../../messaging';
|
||||
import Details from './Details';
|
||||
import Unlock from './Unlock';
|
||||
|
||||
@ -26,7 +26,7 @@ export default function Request ({ isFirst, request, signId, url }: Props): Reac
|
||||
.then((): void => onAction())
|
||||
.catch((error: Error) => console.error(error));
|
||||
const onSign = (password: string): Promise<void> =>
|
||||
approveSignRequest(signId, password)
|
||||
approveSignPassword(signId, password)
|
||||
.then((): void => onAction());
|
||||
const blockNumber = createType('BlockNumber', request.blockNumber);
|
||||
const payload = createType('ExtrinsicPayload', request, { version: request.version });
|
||||
|
||||
@ -13,7 +13,7 @@ export default function Signing (): React.ReactElement<{}> {
|
||||
return (
|
||||
<div>
|
||||
<Header label='transactions' />
|
||||
{requests.map(([id, request, url], index): React.ReactNode => (
|
||||
{requests.map(({ id, request, url }, index): React.ReactNode => (
|
||||
<Request
|
||||
isFirst={index === 0}
|
||||
key={id}
|
||||
|
||||
@ -2,8 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AuthorizeRequest, SigningRequest } from '@polkadot/extension/background/types';
|
||||
import { InjectedAccount } from '@polkadot/extension-inject/types';
|
||||
import { AccountJson, AuthorizeRequest, SigningRequest } from '@polkadot/extension/background/types';
|
||||
import { Prefix } from '@polkadot/util-crypto/address/types';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
@ -31,7 +30,7 @@ const { prefix } = settings.get();
|
||||
setAddressPrefix((prefix === -1 ? 42 : prefix) as Prefix);
|
||||
|
||||
export default function Popup (): React.ReactElement<{}> {
|
||||
const [accounts, setAccounts] = useState<null | InjectedAccount[]>(null);
|
||||
const [accounts, setAccounts] = useState<null | AccountJson[]>(null);
|
||||
const [authRequests, setAuthRequests] = useState<null | AuthorizeRequest[]>(null);
|
||||
const [signRequests, setSignRequests] = useState<null | SigningRequest[]>(null);
|
||||
const [isWelcomeDone, setWelcomeDone] = useState(false);
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { InjectedAccount } from '@polkadot/extension-inject/types';
|
||||
import { AccountJson } from '@polkadot/extension/background/types';
|
||||
import { Prefix } from '@polkadot/util-crypto/address/types';
|
||||
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
@ -24,7 +24,7 @@ interface Props {
|
||||
|
||||
function Address ({ address, children, className, name, theme = 'polkadot' }: Props): React.ReactElement<Props> {
|
||||
const accounts = useContext(AccountContext);
|
||||
const [account, setAccount] = useState<InjectedAccount | null>(null);
|
||||
const [account, setAccount] = useState<AccountJson | null>(null);
|
||||
const [formatted, setFormatted] = useState<string | null>(null);
|
||||
|
||||
useEffect((): void => {
|
||||
|
||||
@ -2,19 +2,17 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AccountsFromCtx, OnActionFromCtx, AuthRequestsFromCtx, SignRequestsFromCtx } from './types';
|
||||
import { AccountJson, AuthorizeRequest, SigningRequest } from '@polkadot/extension/background/types';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const noop = (to?: string): void => {
|
||||
// do nothing
|
||||
};
|
||||
const noop = (to?: string): void => {};
|
||||
|
||||
const AccountContext = React.createContext<AccountsFromCtx>([]);
|
||||
const ActionContext = React.createContext<OnActionFromCtx>(noop);
|
||||
const AuthorizeContext = React.createContext<AuthRequestsFromCtx>([]);
|
||||
const SigningContext = React.createContext<SignRequestsFromCtx>([]);
|
||||
const AccountContext = React.createContext<AccountJson[]>([]);
|
||||
const ActionContext = React.createContext<(to?: string) => void>(noop);
|
||||
const AuthorizeContext = React.createContext<AuthorizeRequest[]>([]);
|
||||
const SigningContext = React.createContext<SigningRequest[]>([]);
|
||||
|
||||
export {
|
||||
AccountContext,
|
||||
|
||||
@ -2,13 +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 { AuthorizeRequest, SigningRequest } from '@polkadot/extension/background/types';
|
||||
import { InjectedAccount } from '@polkadot/extension-inject/types';
|
||||
|
||||
export type OmitProps<T, K> = Pick<T, Exclude<keyof T, K>>;
|
||||
export type SubtractProps<T, K> = OmitProps<T, keyof K>;
|
||||
|
||||
export type AccountsFromCtx = InjectedAccount[];
|
||||
export type OnActionFromCtx = (to?: string) => void;
|
||||
export type AuthRequestsFromCtx = AuthorizeRequest[];
|
||||
export type SignRequestsFromCtx = SigningRequest[];
|
||||
export type SubtractProps<T, K> = OmitProps<T, keyof K>;
|
||||
|
||||
@ -2,12 +2,11 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AuthorizeRequest, SigningRequest, RequestTypes, MessageTypes, ResponseTypes, SeedLengths, SubscriptionMessageTypes, MessageTypesWithNullRequest, MessageTypesWithNoSubscriptions, MessageTypesWithSubscriptions } from '@polkadot/extension/background/types';
|
||||
import { AccountJson, AuthorizeRequest, SigningRequest, RequestTypes, MessageTypes, ResponseTypes, SeedLengths, SubscriptionMessageTypes, MessageTypesWithNullRequest, MessageTypesWithNoSubscriptions, MessageTypesWithSubscriptions } from '@polkadot/extension/background/types';
|
||||
import { KeypairType } from '@polkadot/util-crypto/types';
|
||||
|
||||
import extension from 'extensionizer';
|
||||
import { PORT_POPUP } from '@polkadot/extension/defaults';
|
||||
import { InjectedAccount } from '@polkadot/extension-inject/types';
|
||||
|
||||
interface Handler {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@ -60,61 +59,61 @@ function sendMessage<TMessageType extends MessageTypes> (message: TMessageType,
|
||||
}
|
||||
|
||||
export async function editAccount (address: string, name: string): Promise<boolean> {
|
||||
return sendMessage('accounts.edit', { address, name });
|
||||
return sendMessage('pri(accounts.edit)', { address, name });
|
||||
}
|
||||
|
||||
export async function forgetAccount (address: string): Promise<boolean> {
|
||||
return sendMessage('accounts.forget', { address });
|
||||
return sendMessage('pri(accounts.forget)', { address });
|
||||
}
|
||||
|
||||
export async function getAccounts (): Promise<InjectedAccount[]> {
|
||||
return sendMessage('accounts.list');
|
||||
export async function getAccounts (): Promise<AccountJson[]> {
|
||||
return sendMessage('pri(accounts.list)');
|
||||
}
|
||||
|
||||
export async function getAuthRequests (): Promise<AuthorizeRequest[]> {
|
||||
return sendMessage('authorize.requests');
|
||||
return sendMessage('pri(authorize.requests)');
|
||||
}
|
||||
|
||||
export async function rejectAuthRequest (id: string): Promise<boolean> {
|
||||
return sendMessage('authorize.reject', { id });
|
||||
return sendMessage('pri(authorize.reject)', { id });
|
||||
}
|
||||
|
||||
export async function approveAuthRequest (id: string): Promise<boolean> {
|
||||
return sendMessage('authorize.approve', { id });
|
||||
return sendMessage('pri(authorize.approve)', { id });
|
||||
}
|
||||
|
||||
export async function getSignRequests (): Promise<SigningRequest[]> {
|
||||
return sendMessage('signing.requests');
|
||||
return sendMessage('pri(signing.requests)');
|
||||
}
|
||||
|
||||
export async function cancelSignRequest (id: string): Promise<boolean> {
|
||||
return sendMessage('signing.cancel', { id });
|
||||
return sendMessage('pri(signing.cancel)', { id });
|
||||
}
|
||||
|
||||
export async function approveSignRequest (id: string, password: string): Promise<boolean> {
|
||||
return sendMessage('signing.approve', { id, password });
|
||||
export async function approveSignPassword (id: string, password: string): Promise<boolean> {
|
||||
return sendMessage('pri(signing.approve.password)', { id, password });
|
||||
}
|
||||
|
||||
export async function createAccount (name: string, password: string, suri: string, type?: KeypairType): Promise<boolean> {
|
||||
return sendMessage('accounts.create', { name, password, suri, type });
|
||||
export async function createAccountSuri (name: string, password: string, suri: string, type?: KeypairType): Promise<boolean> {
|
||||
return sendMessage('pri(accounts.create.suri)', { name, password, suri, type });
|
||||
}
|
||||
|
||||
export async function createSeed (length?: SeedLengths, type?: KeypairType): Promise<{ address: string; seed: string }> {
|
||||
return sendMessage('seed.create', { length, type });
|
||||
return sendMessage('pri(seed.create)', { length, type });
|
||||
}
|
||||
|
||||
export async function subscribeAccounts (cb: (accounts: InjectedAccount[]) => void): Promise<boolean> {
|
||||
return sendMessage('accounts.subscribe', null, cb);
|
||||
export async function subscribeAccounts (cb: (accounts: AccountJson[]) => void): Promise<boolean> {
|
||||
return sendMessage('pri(accounts.subscribe)', null, cb);
|
||||
}
|
||||
|
||||
export async function subscribeAuthorize (cb: (accounts: AuthorizeRequest[]) => void): Promise<boolean> {
|
||||
return sendMessage('authorize.subscribe', null, cb);
|
||||
return sendMessage('pri(authorize.subscribe)', null, cb);
|
||||
}
|
||||
|
||||
export async function subscribeSigning (cb: (accounts: SigningRequest[]) => void): Promise<boolean> {
|
||||
return sendMessage('signing.subscribe', null, cb);
|
||||
return sendMessage('pri(signing.subscribe)', null, cb);
|
||||
}
|
||||
|
||||
export async function validateSeed (suri: string, type?: KeypairType): Promise<{ address: string; suri: string }> {
|
||||
return sendMessage('seed.validate', { suri, type });
|
||||
return sendMessage('pri(seed.validate)', { suri, type });
|
||||
}
|
||||
|
||||
@ -3,8 +3,7 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { AuthorizeRequest, RequestAccountCreate, RequestAccountEdit, RequestAuthorizeApprove, RequestAuthorizeReject, RequestSigningApprove, RequestSigningCancel, RequestSeedCreate, ResponseSeedCreate, RequestSeedValidate, ResponseSeedValidate, RequestAccountForget, SigningRequest, RequestTypes, ResponseTypes, MessageTypes } from '../types';
|
||||
import { InjectedAccount } from '@polkadot/extension-inject/types';
|
||||
import { AccountJson, AuthorizeRequest, RequestAccountCreateSuri, RequestAccountEdit, RequestAuthorizeApprove, RequestAuthorizeReject, RequestSigningApprovePassword, RequestSigningCancel, RequestSeedCreate, ResponseSeedCreate, RequestSeedValidate, ResponseSeedValidate, RequestAccountForget, SigningRequest, RequestTypes, ResponseTypes, MessageTypes } from '../types';
|
||||
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
import accountsObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
@ -18,8 +17,8 @@ import { createSubscription, unsubscribe } from './subscriptions';
|
||||
const SEED_DEFAULT_LENGTH = 12;
|
||||
const SEED_LENGTHS = [12, 24];
|
||||
|
||||
function transformAccounts (accounts: SubjectInfo): InjectedAccount[] {
|
||||
return Object.values(accounts).map(({ json }): InjectedAccount => ({ ...json, name: json.meta && json.meta.name }));
|
||||
function transformAccounts (accounts: SubjectInfo): AccountJson[] {
|
||||
return Object.values(accounts).map(({ json }): AccountJson => json);
|
||||
}
|
||||
|
||||
export default class Extension {
|
||||
@ -29,8 +28,8 @@ export default class Extension {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
private accountsCreate ({ name, password, suri, type }: RequestAccountCreate): boolean {
|
||||
keyring.addUri(suri, password, { name }, type);
|
||||
private accountsCreateSuri ({ genesisHash, name, password, suri, type }: RequestAccountCreateSuri): boolean {
|
||||
keyring.addUri(suri, password, { genesisHash, name }, type);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -51,13 +50,13 @@ export default class Extension {
|
||||
return true;
|
||||
}
|
||||
|
||||
private accountsList (): InjectedAccount[] {
|
||||
private accountsList (): AccountJson[] {
|
||||
return transformAccounts(accountsObservable.subject.getValue());
|
||||
}
|
||||
|
||||
// FIXME This looks very much like what we have in Tabs
|
||||
private accountsSubscribe (id: string, port: chrome.runtime.Port): boolean {
|
||||
const cb = createSubscription<'accounts.subscribe'>(id, port);
|
||||
const cb = createSubscription<'pri(accounts.subscribe)'>(id, port);
|
||||
const subscription = accountsObservable.subject.subscribe((accounts: SubjectInfo): void =>
|
||||
cb(transformAccounts(accounts))
|
||||
);
|
||||
@ -100,7 +99,7 @@ export default class Extension {
|
||||
|
||||
// FIXME This looks very much like what we have in accounts
|
||||
private authorizeSubscribe (id: string, port: chrome.runtime.Port): boolean {
|
||||
const cb = createSubscription<'authorize.subscribe'>(id, port);
|
||||
const cb = createSubscription<'pri(authorize.subscribe)'>(id, port);
|
||||
const subscription = this.state.authSubject.subscribe((requests: AuthorizeRequest[]): void =>
|
||||
cb(requests)
|
||||
);
|
||||
@ -134,7 +133,7 @@ export default class Extension {
|
||||
};
|
||||
}
|
||||
|
||||
private signingApprove ({ id, password }: RequestSigningApprove): boolean {
|
||||
private signingApprovePassword ({ id, password }: RequestSigningApprovePassword): boolean {
|
||||
const queued = this.state.getSignRequest(id);
|
||||
|
||||
assert(queued, 'Unable to find request');
|
||||
@ -181,7 +180,7 @@ export default class Extension {
|
||||
|
||||
// FIXME This looks very much like what we have in authorization
|
||||
private signingSubscribe (id: string, port: chrome.runtime.Port): boolean {
|
||||
const cb = createSubscription<'signing.subscribe'>(id, port);
|
||||
const cb = createSubscription<'pri(signing.subscribe)'>(id, port);
|
||||
const subscription = this.state.signSubject.subscribe((requests: SigningRequest[]): void =>
|
||||
cb(requests)
|
||||
);
|
||||
@ -194,57 +193,57 @@ export default class Extension {
|
||||
return true;
|
||||
}
|
||||
|
||||
public handle<TMessageType extends MessageTypes> (id: string, type: TMessageType, request: RequestTypes[TMessageType], port: chrome.runtime.Port): Promise<ResponseTypes[keyof ResponseTypes]> {
|
||||
return new Promise((resolve, reject): void => {
|
||||
switch (type) {
|
||||
case 'authorize.approve':
|
||||
return resolve(this.authorizeApprove(request as RequestAuthorizeApprove));
|
||||
// Weird thought, the eslint override is not needed in Tabs
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
public async handle<TMessageType extends MessageTypes> (id: string, type: TMessageType, request: RequestTypes[TMessageType], port: chrome.runtime.Port): Promise<ResponseTypes[keyof ResponseTypes]> {
|
||||
switch (type) {
|
||||
case 'pri(authorize.approve)':
|
||||
return this.authorizeApprove(request as RequestAuthorizeApprove);
|
||||
|
||||
case 'authorize.reject':
|
||||
return resolve(this.authorizeReject(request as RequestAuthorizeApprove));
|
||||
case 'pri(authorize.reject)':
|
||||
return this.authorizeReject(request as RequestAuthorizeApprove);
|
||||
|
||||
case 'authorize.requests':
|
||||
return resolve(this.authorizeRequests());
|
||||
case 'pri(authorize.requests)':
|
||||
return this.authorizeRequests();
|
||||
|
||||
case 'authorize.subscribe':
|
||||
return resolve(this.authorizeSubscribe(id, port));
|
||||
case 'pri(authorize.subscribe)':
|
||||
return this.authorizeSubscribe(id, port);
|
||||
|
||||
case 'accounts.create':
|
||||
return resolve(this.accountsCreate(request as RequestAccountCreate));
|
||||
case 'pri(accounts.create.suri)':
|
||||
return this.accountsCreateSuri(request as RequestAccountCreateSuri);
|
||||
|
||||
case 'accounts.forget':
|
||||
return resolve(this.accountsForget(request as RequestAccountForget));
|
||||
case 'pri(accounts.forget)':
|
||||
return this.accountsForget(request as RequestAccountForget);
|
||||
|
||||
case 'accounts.edit':
|
||||
return resolve(this.accountsEdit(request as RequestAccountEdit));
|
||||
case 'pri(accounts.edit)':
|
||||
return this.accountsEdit(request as RequestAccountEdit);
|
||||
|
||||
case 'accounts.list':
|
||||
return resolve(this.accountsList());
|
||||
case 'pri(accounts.list)':
|
||||
return this.accountsList();
|
||||
|
||||
case 'accounts.subscribe':
|
||||
return resolve(this.accountsSubscribe(id, port));
|
||||
case 'pri(accounts.subscribe)':
|
||||
return this.accountsSubscribe(id, port);
|
||||
|
||||
case 'seed.create':
|
||||
return resolve(this.seedCreate(request as RequestSeedCreate));
|
||||
case 'pri(seed.create)':
|
||||
return this.seedCreate(request as RequestSeedCreate);
|
||||
|
||||
case 'seed.validate':
|
||||
return resolve(this.seedValidate(request as RequestSeedValidate));
|
||||
case 'pri(seed.validate)':
|
||||
return this.seedValidate(request as RequestSeedValidate);
|
||||
|
||||
case 'signing.approve':
|
||||
return resolve(this.signingApprove(request as RequestSigningApprove));
|
||||
case 'pri(signing.approve.password)':
|
||||
return this.signingApprovePassword(request as RequestSigningApprovePassword);
|
||||
|
||||
case 'signing.cancel':
|
||||
return resolve(this.signingCancel(request as RequestSigningCancel));
|
||||
case 'pri(signing.cancel)':
|
||||
return this.signingCancel(request as RequestSigningCancel);
|
||||
|
||||
case 'signing.requests':
|
||||
return resolve(this.signingRequests());
|
||||
case 'pri(signing.requests)':
|
||||
return this.signingRequests();
|
||||
|
||||
case 'signing.subscribe':
|
||||
return resolve(this.signingSubscribe(id, port));
|
||||
case 'pri(signing.subscribe)':
|
||||
return this.signingSubscribe(id, port);
|
||||
|
||||
default:
|
||||
return reject(new Error(`Unable to handle message of type ${type}`));
|
||||
}
|
||||
});
|
||||
default:
|
||||
throw new Error(`Unable to handle message of type ${type}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { AuthorizeRequest, RequestAuthorizeTab, RequestExtrinsicSign, ResponseExtrinsicSign, SigningRequest } from '../types';
|
||||
import { AccountJson, AuthorizeRequest, RequestAuthorizeTab, RequestExtrinsicSign, ResponseExtrinsicSign, SigningRequest } from '../types';
|
||||
|
||||
import extension from 'extensionizer';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
@ -26,6 +26,7 @@ type AuthUrls = Record<string, {
|
||||
}>;
|
||||
|
||||
interface SignRequest {
|
||||
account: AccountJson;
|
||||
id: string;
|
||||
request: RequestExtrinsicSign;
|
||||
resolve: (result: ResponseExtrinsicSign) => void;
|
||||
@ -71,13 +72,13 @@ export default class State {
|
||||
public get allAuthRequests (): AuthorizeRequest[] {
|
||||
return Object
|
||||
.values(this._authRequests)
|
||||
.map(({ id, request, url }): AuthorizeRequest => [id, request, url]);
|
||||
.map(({ id, request, url }): AuthorizeRequest => ({ id, request, url }));
|
||||
}
|
||||
|
||||
public get allSignRequests (): SigningRequest[] {
|
||||
return Object
|
||||
.values(this._signRequests)
|
||||
.map(({ id, request, url }): SigningRequest => [id, request, url]);
|
||||
.map(({ account, id, request, url }): SigningRequest => ({ account, id, request, url }));
|
||||
}
|
||||
|
||||
private popupClose (): void {
|
||||
@ -210,11 +211,12 @@ export default class State {
|
||||
return this._signRequests[id];
|
||||
}
|
||||
|
||||
public signQueue (url: string, request: RequestExtrinsicSign): Promise<ResponseExtrinsicSign> {
|
||||
public signQueue (url: string, request: RequestExtrinsicSign, account: AccountJson): Promise<ResponseExtrinsicSign> {
|
||||
const id = getId();
|
||||
|
||||
return new Promise((resolve, reject): void => {
|
||||
this._signRequests[id] = {
|
||||
account,
|
||||
id,
|
||||
request,
|
||||
resolve: this.signComplete(id, resolve),
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { InjectedAccount } from '@polkadot/extension-inject/types';
|
||||
import { RequestAuthorizeTab, RequestExtrinsicSign, ResponseExtrinsicSign, RequestTypes, ResponseTypes, MessageTypes } from '../types';
|
||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||
import { RequestAuthorizeTab, RequestExtrinsicSign, ResponseExtrinsicSign, RequestTypes, ResponseTypes, MessageTypes } from '../types';
|
||||
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
import accountsObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||
@ -14,8 +14,8 @@ import State from './State';
|
||||
import { createSubscription, unsubscribe } from './subscriptions';
|
||||
|
||||
function transformAccounts (accounts: SubjectInfo): InjectedAccount[] {
|
||||
return Object.values(accounts).map(({ json: { address, meta: { name } } }): InjectedAccount => ({
|
||||
address, name
|
||||
return Object.values(accounts).map(({ json: { address, meta: { genesisHash, name } } }): InjectedAccount => ({
|
||||
address, genesisHash, name
|
||||
}));
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ export default class Tabs {
|
||||
|
||||
// FIXME This looks very much like what we have in Extension
|
||||
private accountsSubscribe (url: string, id: string, port: chrome.runtime.Port): boolean {
|
||||
const cb = createSubscription<'accounts.subscribe'>(id, port);
|
||||
const cb = createSubscription<'pub(accounts.subscribe)'>(id, port);
|
||||
const subscription = accountsObservable.subject.subscribe((accounts: SubjectInfo): void =>
|
||||
cb(transformAccounts(accounts))
|
||||
);
|
||||
@ -56,25 +56,25 @@ export default class Tabs {
|
||||
|
||||
assert(pair, 'Unable to find keypair');
|
||||
|
||||
return this.state.signQueue(url, request);
|
||||
return this.state.signQueue(url, request, { address, ...pair.meta });
|
||||
}
|
||||
|
||||
public async handle<TMessageType extends MessageTypes> (id: string, type: TMessageType, request: RequestTypes[TMessageType], url: string, port: chrome.runtime.Port): Promise<ResponseTypes[keyof ResponseTypes]> {
|
||||
if (type !== 'authorize.tab') {
|
||||
if (type !== 'pub(authorize.tab)') {
|
||||
this.state.ensureUrlAuthorized(url);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'authorize.tab':
|
||||
case 'pub(authorize.tab)':
|
||||
return this.authorize(url, request as RequestAuthorizeTab);
|
||||
|
||||
case 'accounts.list':
|
||||
case 'pub(accounts.list)':
|
||||
return this.accountsList(url);
|
||||
|
||||
case 'accounts.subscribe':
|
||||
case 'pub(accounts.subscribe)':
|
||||
return this.accountsSubscribe(url, id, port);
|
||||
|
||||
case 'extrinsic.sign':
|
||||
case 'pub(extrinsic.sign)':
|
||||
return this.extrinsicSign(url, request as RequestExtrinsicSign);
|
||||
|
||||
default:
|
||||
|
||||
@ -14,33 +14,55 @@ type NoUndefinedValues<T> = {
|
||||
[K in KeysWithDefinedValues<T>]: T[K]
|
||||
};
|
||||
|
||||
type IsNull<T, K extends keyof T> = { [K1 in Exclude<keyof T, K>]: T[K1] } & T[K] extends null ? K : never
|
||||
type NullKeys<T> = { [K in keyof T]: IsNull<T, K> }[keyof T]
|
||||
type IsNull<T, K extends keyof T> = { [K1 in Exclude<keyof T, K>]: T[K1] } & T[K] extends null ? K : never;
|
||||
|
||||
type NullKeys<T> = { [K in keyof T]: IsNull<T, K> }[keyof T];
|
||||
|
||||
export type SeedLengths = 12 | 24;
|
||||
|
||||
export type AuthorizeRequest = [string, RequestAuthorizeTab, string];
|
||||
export type SigningRequest = [string, RequestExtrinsicSign, string];
|
||||
export interface AccountJson {
|
||||
address: string;
|
||||
genesisHash?: string | null;
|
||||
isExternal?: boolean;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface AuthorizeRequest {
|
||||
id: string;
|
||||
request: RequestAuthorizeTab;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface SigningRequest {
|
||||
account: AccountJson;
|
||||
id: string;
|
||||
request: RequestExtrinsicSign;
|
||||
url: string;
|
||||
}
|
||||
|
||||
// [MessageType]: [RequestType, ResponseType, SubscriptionMessageType?]
|
||||
export interface RequestSignatures {
|
||||
'accounts.create': [RequestAccountCreate, boolean];
|
||||
'accounts.edit': [RequestAccountEdit, boolean];
|
||||
'accounts.forget': [RequestAccountForget, boolean];
|
||||
'accounts.list': [RequestAccountList, InjectedAccount[]];
|
||||
'accounts.subscribe': [RequestAccountSubscribe, boolean, InjectedAccount[]];
|
||||
'authorize.tab': [RequestAuthorizeTab, null];
|
||||
'authorize.approve': [RequestAuthorizeApprove, boolean];
|
||||
'authorize.reject': [RequestAuthorizeReject, boolean];
|
||||
'authorize.requests': [RequestAuthorizeRequests, AuthorizeRequest[]];
|
||||
'authorize.subscribe': [RequestAuthorizeSubscribe, boolean, AuthorizeRequest[]];
|
||||
'extrinsic.sign': [RequestExtrinsicSign, ResponseExtrinsicSign];
|
||||
'seed.create': [RequestSeedCreate, ResponseSeedCreate];
|
||||
'seed.validate': [RequestSeedValidate, ResponseSeedValidate];
|
||||
'signing.approve': [RequestSigningApprove, boolean];
|
||||
'signing.cancel': [RequestSigningCancel, boolean];
|
||||
'signing.requests': [RequestSigningRequests, SigningRequest[]];
|
||||
'signing.subscribe': [RequestSigningSubscribe, boolean, SigningRequest[]];
|
||||
// private/internal requests, i.e. from a popup
|
||||
'pri(accounts.create.suri)': [RequestAccountCreateSuri, boolean];
|
||||
'pri(accounts.edit)': [RequestAccountEdit, boolean];
|
||||
'pri(accounts.forget)': [RequestAccountForget, boolean];
|
||||
'pri(accounts.list)': [RequestAccountList, AccountJson[]];
|
||||
'pri(accounts.subscribe)': [RequestAccountSubscribe, boolean, AccountJson[]];
|
||||
'pri(authorize.approve)': [RequestAuthorizeApprove, boolean];
|
||||
'pri(authorize.reject)': [RequestAuthorizeReject, boolean];
|
||||
'pri(authorize.requests)': [RequestAuthorizeRequests, AuthorizeRequest[]];
|
||||
'pri(authorize.subscribe)': [RequestAuthorizeSubscribe, boolean, AuthorizeRequest[]];
|
||||
'pri(seed.create)': [RequestSeedCreate, ResponseSeedCreate];
|
||||
'pri(seed.validate)': [RequestSeedValidate, ResponseSeedValidate];
|
||||
'pri(signing.approve.password)': [RequestSigningApprovePassword, boolean];
|
||||
'pri(signing.cancel)': [RequestSigningCancel, boolean];
|
||||
'pri(signing.requests)': [RequestSigningRequests, SigningRequest[]];
|
||||
'pri(signing.subscribe)': [RequestSigningSubscribe, boolean, SigningRequest[]];
|
||||
// public/external requests, i.e. from a page
|
||||
'pub(accounts.list)': [RequestAccountList, InjectedAccount[]];
|
||||
'pub(accounts.subscribe)': [RequestAccountSubscribe, boolean, InjectedAccount[]];
|
||||
'pub(authorize.tab)': [RequestAuthorizeTab, null];
|
||||
'pub(extrinsic.sign)': [RequestExtrinsicSign, ResponseExtrinsicSign];
|
||||
}
|
||||
|
||||
export type MessageTypes = keyof RequestSignatures;
|
||||
@ -76,8 +98,9 @@ export type RequestAuthorizeRequests = null;
|
||||
|
||||
export type RequestAuthorizeSubscribe = null;
|
||||
|
||||
export interface RequestAccountCreate {
|
||||
export interface RequestAccountCreateSuri {
|
||||
name: string;
|
||||
genesisHash?: string | null;
|
||||
password: string;
|
||||
suri: string;
|
||||
type?: KeypairType;
|
||||
@ -85,6 +108,7 @@ export interface RequestAccountCreate {
|
||||
|
||||
export interface RequestAccountEdit {
|
||||
address: string;
|
||||
genesisHash?: string | null;
|
||||
name: string;
|
||||
}
|
||||
|
||||
@ -98,7 +122,7 @@ export type RequestAccountSubscribe = null;
|
||||
|
||||
export type RequestExtrinsicSign = SignerPayloadJSON;
|
||||
|
||||
export interface RequestSigningApprove {
|
||||
export interface RequestSigningApprovePassword {
|
||||
id: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
@ -13,12 +13,12 @@ export default class Accounts implements InjectedAccounts {
|
||||
}
|
||||
|
||||
public get (): Promise<InjectedAccount[]> {
|
||||
return sendRequest('accounts.list');
|
||||
return sendRequest('pub(accounts.list)');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public subscribe (cb: (accounts: InjectedAccount[]) => any): Unsubcall {
|
||||
sendRequest('accounts.subscribe', null, cb)
|
||||
sendRequest('pub(accounts.subscribe)', null, cb)
|
||||
.catch((error: Error) => console.error(error));
|
||||
|
||||
return (): void => {
|
||||
|
||||
@ -19,7 +19,7 @@ export default class Signer implements SignerInterface {
|
||||
|
||||
public async signPayload (payload: SignerPayloadJSON): Promise<SignerResult> {
|
||||
const id = ++nextId;
|
||||
const result = await sendRequest('extrinsic.sign', payload);
|
||||
const result = await sendRequest('pub(extrinsic.sign)', payload);
|
||||
|
||||
// we add an internal id (number) - should have a mapping from the
|
||||
// extension id (string) -> internal id (number) if we wish to provide
|
||||
|
||||
@ -52,13 +52,13 @@ function sendMessage<TMessageType extends MessageTypes> (message: TMessageType,
|
||||
|
||||
// the enable function, called by the dapp to allow access
|
||||
async function enable (origin: string): Promise<Injected> {
|
||||
await sendMessage('authorize.tab', { origin });
|
||||
await sendMessage('pub(authorize.tab)', { origin });
|
||||
|
||||
return new Injected(sendMessage);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function handleResponse<TMessageType extends MessageTypes> (data: TransportResponseMessage<TMessageType> & {subscription?: any}): void {
|
||||
function handleResponse<TMessageType extends MessageTypes> (data: TransportResponseMessage<TMessageType> & { subscription?: any }): void {
|
||||
const handler = handlers[data.id];
|
||||
|
||||
if (!handler) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user