From e20b6e0f16a984b3d6cb52646afdd91c28275772 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 6 Sep 2019 10:52:57 +0200 Subject: [PATCH] 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 --- packages/extension-dapp/src/index.ts | 4 +- packages/extension-inject/src/types.ts | 2 + .../src/Popup/Authorize/index.tsx | 2 +- packages/extension-ui/src/Popup/Create.tsx | 4 +- packages/extension-ui/src/Popup/Import.tsx | 4 +- .../src/Popup/Signing/Request.tsx | 4 +- .../extension-ui/src/Popup/Signing/index.tsx | 2 +- packages/extension-ui/src/Popup/index.tsx | 5 +- .../extension-ui/src/components/Address.tsx | 4 +- .../extension-ui/src/components/contexts.tsx | 14 ++- packages/extension-ui/src/components/types.ts | 9 +- packages/extension-ui/src/messaging.ts | 41 ++++---- .../src/background/handlers/Extension.ts | 95 +++++++++---------- .../src/background/handlers/State.ts | 10 +- .../extension/src/background/handlers/Tabs.ts | 20 ++-- packages/extension/src/background/types.ts | 70 +++++++++----- packages/extension/src/page/Accounts.ts | 4 +- packages/extension/src/page/Signer.ts | 2 +- packages/extension/src/page/index.ts | 4 +- 19 files changed, 158 insertions(+), 142 deletions(-) diff --git a/packages/extension-dapp/src/index.ts b/packages/extension-dapp/src/index.ts index 8731aab7..0d793c66 100644 --- a/packages/extension-dapp/src/index.ts +++ b/packages/extension-dapp/src/index.ts @@ -22,9 +22,9 @@ function throwError (method: string): never { // internal helper to map from Array -> Array 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 } })); } diff --git a/packages/extension-inject/src/types.ts b/packages/extension-inject/src/types.ts index c54ccc17..f4b1468f 100644 --- a/packages/extension-inject/src/types.ts +++ b/packages/extension-inject/src/types.ts @@ -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; }; diff --git a/packages/extension-ui/src/Popup/Authorize/index.tsx b/packages/extension-ui/src/Popup/Authorize/index.tsx index a3d137fe..efb6c1f0 100644 --- a/packages/extension-ui/src/Popup/Authorize/index.tsx +++ b/packages/extension-ui/src/Popup/Authorize/index.tsx @@ -13,7 +13,7 @@ export default function Authorize (): React.ReactElement<{}> { return (
- {requests.map(([id, request, url], index): React.ReactNode => ( + {requests.map(({ id, request, url }, index): React.ReactNode => ( { 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)); } diff --git a/packages/extension-ui/src/Popup/Import.tsx b/packages/extension-ui/src/Popup/Import.tsx index 85e62a06..dc2d7ed7 100644 --- a/packages/extension-ui/src/Popup/Import.tsx +++ b/packages/extension-ui/src/Popup/Import.tsx @@ -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 { 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)); } diff --git a/packages/extension-ui/src/Popup/Signing/Request.tsx b/packages/extension-ui/src/Popup/Signing/Request.tsx index 2fef2514..71641cd9 100644 --- a/packages/extension-ui/src/Popup/Signing/Request.tsx +++ b/packages/extension-ui/src/Popup/Signing/Request.tsx @@ -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 => - approveSignRequest(signId, password) + approveSignPassword(signId, password) .then((): void => onAction()); const blockNumber = createType('BlockNumber', request.blockNumber); const payload = createType('ExtrinsicPayload', request, { version: request.version }); diff --git a/packages/extension-ui/src/Popup/Signing/index.tsx b/packages/extension-ui/src/Popup/Signing/index.tsx index 04703e5a..dafc9061 100644 --- a/packages/extension-ui/src/Popup/Signing/index.tsx +++ b/packages/extension-ui/src/Popup/Signing/index.tsx @@ -13,7 +13,7 @@ export default function Signing (): React.ReactElement<{}> { return (
- {requests.map(([id, request, url], index): React.ReactNode => ( + {requests.map(({ id, request, url }, index): React.ReactNode => ( { - const [accounts, setAccounts] = useState(null); + const [accounts, setAccounts] = useState(null); const [authRequests, setAuthRequests] = useState(null); const [signRequests, setSignRequests] = useState(null); const [isWelcomeDone, setWelcomeDone] = useState(false); diff --git a/packages/extension-ui/src/components/Address.tsx b/packages/extension-ui/src/components/Address.tsx index 2cbe5ff0..6af5e775 100644 --- a/packages/extension-ui/src/components/Address.tsx +++ b/packages/extension-ui/src/components/Address.tsx @@ -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 { const accounts = useContext(AccountContext); - const [account, setAccount] = useState(null); + const [account, setAccount] = useState(null); const [formatted, setFormatted] = useState(null); useEffect((): void => { diff --git a/packages/extension-ui/src/components/contexts.tsx b/packages/extension-ui/src/components/contexts.tsx index e77a8f2f..fa8b6044 100644 --- a/packages/extension-ui/src/components/contexts.tsx +++ b/packages/extension-ui/src/components/contexts.tsx @@ -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([]); -const ActionContext = React.createContext(noop); -const AuthorizeContext = React.createContext([]); -const SigningContext = React.createContext([]); +const AccountContext = React.createContext([]); +const ActionContext = React.createContext<(to?: string) => void>(noop); +const AuthorizeContext = React.createContext([]); +const SigningContext = React.createContext([]); export { AccountContext, diff --git a/packages/extension-ui/src/components/types.ts b/packages/extension-ui/src/components/types.ts index 4cceff98..fea82f1c 100644 --- a/packages/extension-ui/src/components/types.ts +++ b/packages/extension-ui/src/components/types.ts @@ -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 = Pick>; -export type SubtractProps = OmitProps; -export type AccountsFromCtx = InjectedAccount[]; -export type OnActionFromCtx = (to?: string) => void; -export type AuthRequestsFromCtx = AuthorizeRequest[]; -export type SignRequestsFromCtx = SigningRequest[]; +export type SubtractProps = OmitProps; diff --git a/packages/extension-ui/src/messaging.ts b/packages/extension-ui/src/messaging.ts index 81f2141e..b58489a7 100644 --- a/packages/extension-ui/src/messaging.ts +++ b/packages/extension-ui/src/messaging.ts @@ -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 (message: TMessageType, } export async function editAccount (address: string, name: string): Promise { - return sendMessage('accounts.edit', { address, name }); + return sendMessage('pri(accounts.edit)', { address, name }); } export async function forgetAccount (address: string): Promise { - return sendMessage('accounts.forget', { address }); + return sendMessage('pri(accounts.forget)', { address }); } -export async function getAccounts (): Promise { - return sendMessage('accounts.list'); +export async function getAccounts (): Promise { + return sendMessage('pri(accounts.list)'); } export async function getAuthRequests (): Promise { - return sendMessage('authorize.requests'); + return sendMessage('pri(authorize.requests)'); } export async function rejectAuthRequest (id: string): Promise { - return sendMessage('authorize.reject', { id }); + return sendMessage('pri(authorize.reject)', { id }); } export async function approveAuthRequest (id: string): Promise { - return sendMessage('authorize.approve', { id }); + return sendMessage('pri(authorize.approve)', { id }); } export async function getSignRequests (): Promise { - return sendMessage('signing.requests'); + return sendMessage('pri(signing.requests)'); } export async function cancelSignRequest (id: string): Promise { - return sendMessage('signing.cancel', { id }); + return sendMessage('pri(signing.cancel)', { id }); } -export async function approveSignRequest (id: string, password: string): Promise { - return sendMessage('signing.approve', { id, password }); +export async function approveSignPassword (id: string, password: string): Promise { + return sendMessage('pri(signing.approve.password)', { id, password }); } -export async function createAccount (name: string, password: string, suri: string, type?: KeypairType): Promise { - return sendMessage('accounts.create', { name, password, suri, type }); +export async function createAccountSuri (name: string, password: string, suri: string, type?: KeypairType): Promise { + 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 { - return sendMessage('accounts.subscribe', null, cb); +export async function subscribeAccounts (cb: (accounts: AccountJson[]) => void): Promise { + return sendMessage('pri(accounts.subscribe)', null, cb); } export async function subscribeAuthorize (cb: (accounts: AuthorizeRequest[]) => void): Promise { - return sendMessage('authorize.subscribe', null, cb); + return sendMessage('pri(authorize.subscribe)', null, cb); } export async function subscribeSigning (cb: (accounts: SigningRequest[]) => void): Promise { - 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 }); } diff --git a/packages/extension/src/background/handlers/Extension.ts b/packages/extension/src/background/handlers/Extension.ts index 5c91eacb..35ac8f77 100644 --- a/packages/extension/src/background/handlers/Extension.ts +++ b/packages/extension/src/background/handlers/Extension.ts @@ -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 (id: string, type: TMessageType, request: RequestTypes[TMessageType], port: chrome.runtime.Port): Promise { - 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 (id: string, type: TMessageType, request: RequestTypes[TMessageType], port: chrome.runtime.Port): Promise { + 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}`); + } } } diff --git a/packages/extension/src/background/handlers/State.ts b/packages/extension/src/background/handlers/State.ts index cdf0af83..954f1c46 100644 --- a/packages/extension/src/background/handlers/State.ts +++ b/packages/extension/src/background/handlers/State.ts @@ -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; 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 { + public signQueue (url: string, request: RequestExtrinsicSign, account: AccountJson): Promise { const id = getId(); return new Promise((resolve, reject): void => { this._signRequests[id] = { + account, id, request, resolve: this.signComplete(id, resolve), diff --git a/packages/extension/src/background/handlers/Tabs.ts b/packages/extension/src/background/handlers/Tabs.ts index 0098012a..0831c64d 100644 --- a/packages/extension/src/background/handlers/Tabs.ts +++ b/packages/extension/src/background/handlers/Tabs.ts @@ -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 (id: string, type: TMessageType, request: RequestTypes[TMessageType], url: string, port: chrome.runtime.Port): Promise { - 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: diff --git a/packages/extension/src/background/types.ts b/packages/extension/src/background/types.ts index 03e6e5b6..4f61a1a8 100644 --- a/packages/extension/src/background/types.ts +++ b/packages/extension/src/background/types.ts @@ -14,33 +14,55 @@ type NoUndefinedValues = { [K in KeysWithDefinedValues]: T[K] }; -type IsNull = { [K1 in Exclude]: T[K1] } & T[K] extends null ? K : never -type NullKeys = { [K in keyof T]: IsNull }[keyof T] +type IsNull = { [K1 in Exclude]: T[K1] } & T[K] extends null ? K : never; + +type NullKeys = { [K in keyof T]: IsNull }[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; } diff --git a/packages/extension/src/page/Accounts.ts b/packages/extension/src/page/Accounts.ts index 707d60da..07b1bdba 100644 --- a/packages/extension/src/page/Accounts.ts +++ b/packages/extension/src/page/Accounts.ts @@ -13,12 +13,12 @@ export default class Accounts implements InjectedAccounts { } public get (): Promise { - 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 => { diff --git a/packages/extension/src/page/Signer.ts b/packages/extension/src/page/Signer.ts index f3889a12..a5f52d74 100644 --- a/packages/extension/src/page/Signer.ts +++ b/packages/extension/src/page/Signer.ts @@ -19,7 +19,7 @@ export default class Signer implements SignerInterface { public async signPayload (payload: SignerPayloadJSON): Promise { 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 diff --git a/packages/extension/src/page/index.ts b/packages/extension/src/page/index.ts index 69c7e0e0..21b7c930 100644 --- a/packages/extension/src/page/index.ts +++ b/packages/extension/src/page/index.ts @@ -52,13 +52,13 @@ function sendMessage (message: TMessageType, // the enable function, called by the dapp to allow access async function enable (origin: string): Promise { - 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 (data: TransportResponseMessage & {subscription?: any}): void { +function handleResponse (data: TransportResponseMessage & { subscription?: any }): void { const handler = handlers[data.id]; if (!handler) {