diff --git a/packages/extension-base/README.md b/packages/extension-base/README.md index 21b07d64..ac535f28 100644 --- a/packages/extension-base/README.md +++ b/packages/extension-base/README.md @@ -5,4 +5,6 @@ Functions, classes and other utilities used in `@polkadot/extension`. These incl - message passing, - scripts injected inside pages. -They are primarily meant to be used in `@polkadot/extension`, and can be broken without any notice to cater for `@polkadot/extension`'s needs. They are exported here if you wish to use part of them in the development of your own extension. +They are primarily meant to be used in `@polkadot/extension`, and can be broken without any notice to cater for `@polkadot/extension`'s needs. + +They are exported here if you wish to use part of them in the development of your own extension. Don't forget to add `process.env.EXTENSION_PREFIX` to separate ports and stores from the current extension's ones. diff --git a/packages/extension-base/src/background/handlers/State.ts b/packages/extension-base/src/background/handlers/State.ts index e0ad9fd9..721ea817 100644 --- a/packages/extension-base/src/background/handlers/State.ts +++ b/packages/extension-base/src/background/handlers/State.ts @@ -7,6 +7,7 @@ import type { AccountJson, AuthorizeRequest, MetadataRequest, RequestAuthorizeTa import { BehaviorSubject } from 'rxjs'; +import { getId } from '@polkadot/extension-base/utils/getId'; import { addMetadata, knownMetadata } from '@polkadot/extension-chains'; import chrome from '@polkadot/extension-inject/chrome'; import settings from '@polkadot/ui-settings'; @@ -58,8 +59,6 @@ interface SignRequest extends Resolver { url: string; } -let idCounter = 0; - const NOTIFICATION_URL = chrome.extension.getURL('notification.html'); const POPUP_WINDOW_OPTS: chrome.windows.CreateData = { @@ -86,10 +85,6 @@ export enum NotificationOptions { const AUTH_URLS_KEY = 'authUrls'; -function getId (): string { - return `${Date.now()}.${++idCounter}`; -} - export default class State { readonly #authUrls: AuthUrls = {}; diff --git a/packages/extension-base/src/background/types.ts b/packages/extension-base/src/background/types.ts index ecfb6997..85214767 100644 --- a/packages/extension-base/src/background/types.ts +++ b/packages/extension-base/src/background/types.ts @@ -141,7 +141,7 @@ export type MessageTypesWithNullRequest = NullKeys export interface TransportRequestMessage { id: string; message: TMessageType; - origin: 'page' | 'extension'; + origin: string; request: RequestTypes[TMessageType]; } diff --git a/packages/extension-base/src/defaults.ts b/packages/extension-base/src/defaults.ts index 35918046..bd88a5f9 100644 --- a/packages/extension-base/src/defaults.ts +++ b/packages/extension-base/src/defaults.ts @@ -2,9 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 const ALLOWED_PATH = ['/', '/account/import-ledger', '/account/restore-json'] as const; -const PORT_CONTENT = 'content'; const PHISHING_PAGE_REDIRECT = '/phishing-page-detected'; -const PORT_EXTENSION = 'extension'; +const EXTENSION_PREFIX = process.env.EXTENSION_PREFIX as string || ''; +const PORT_CONTENT = `${EXTENSION_PREFIX}content`; +const PORT_EXTENSION = `${EXTENSION_PREFIX}extension`; +const MESSAGE_ORIGIN_PAGE = `${EXTENSION_PREFIX}page`; +const MESSAGE_ORIGIN_CONTENT = `${EXTENSION_PREFIX}content`; const PASSWORD_EXPIRY_MIN = 15; const PASSWORD_EXPIRY_MS = PASSWORD_EXPIRY_MIN * 60 * 1000; @@ -13,6 +16,9 @@ export { PASSWORD_EXPIRY_MIN, PASSWORD_EXPIRY_MS, PHISHING_PAGE_REDIRECT, + EXTENSION_PREFIX, PORT_CONTENT, - PORT_EXTENSION + PORT_EXTENSION, + MESSAGE_ORIGIN_PAGE, + MESSAGE_ORIGIN_CONTENT }; diff --git a/packages/extension-base/src/page/index.ts b/packages/extension-base/src/page/index.ts index 9b9bcd67..a9d79b9e 100644 --- a/packages/extension-base/src/page/index.ts +++ b/packages/extension-base/src/page/index.ts @@ -3,6 +3,8 @@ import type { MessageTypes, MessageTypesWithNoSubscriptions, MessageTypesWithNullRequest, MessageTypesWithSubscriptions, RequestTypes, ResponseTypes, SubscriptionMessageTypes, TransportRequestMessage, TransportResponseMessage } from '../background/types'; +import { MESSAGE_ORIGIN_PAGE } from '../defaults'; +import { getId } from '../utils/getId'; import Injected from './Injected'; // when sending a message from the injector to the extension, we @@ -23,7 +25,6 @@ export interface Handler { export type Handlers = Record; const handlers: Handlers = {}; -let idCounter = 0; // a generic message sender that creates an event, returning a promise that will // resolve once the event is resolved (by the response listener just below this) @@ -33,14 +34,14 @@ export function sendMessage( export function sendMessage (message: TMessageType, request?: RequestTypes[TMessageType], subscriber?: (data: unknown) => void): Promise { return new Promise((resolve, reject): void => { - const id = `${Date.now()}.${++idCounter}`; + const id = getId(); handlers[id] = { reject, resolve, subscriber }; const transportRequestMessage: TransportRequestMessage = { id, message, - origin: 'page', + origin: MESSAGE_ORIGIN_PAGE, request: request || null as RequestTypes[TMessageType] }; diff --git a/packages/extension-base/src/stores/Accounts.ts b/packages/extension-base/src/stores/Accounts.ts index 53147547..8a3278c1 100644 --- a/packages/extension-base/src/stores/Accounts.ts +++ b/packages/extension-base/src/stores/Accounts.ts @@ -3,11 +3,12 @@ import type { KeyringJson, KeyringStore } from '@polkadot/ui-keyring/types'; +import { EXTENSION_PREFIX } from '../defaults'; import BaseStore from './Base'; export default class AccountsStore extends BaseStore implements KeyringStore { constructor () { - super(null); + super(`${EXTENSION_PREFIX}accounts`); } public override set (key: string, value: KeyringJson, update?: () => void): void { diff --git a/packages/extension-base/src/stores/Metadata.ts b/packages/extension-base/src/stores/Metadata.ts index 357ae1bd..575edb69 100644 --- a/packages/extension-base/src/stores/Metadata.ts +++ b/packages/extension-base/src/stores/Metadata.ts @@ -3,10 +3,11 @@ import type { MetadataDef } from '@polkadot/extension-inject/types'; +import { EXTENSION_PREFIX } from '../defaults'; import BaseStore from './Base'; export default class MetadataStore extends BaseStore { constructor () { - super('metadata'); + super(`${EXTENSION_PREFIX}metadata`); } } diff --git a/packages/extension-base/src/utils/getId.ts b/packages/extension-base/src/utils/getId.ts new file mode 100644 index 00000000..96d960ef --- /dev/null +++ b/packages/extension-base/src/utils/getId.ts @@ -0,0 +1,10 @@ +// Copyright 2019-2021 @polkadot/extension authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { EXTENSION_PREFIX } from '../defaults'; + +let counter = 0; + +export function getId (): string { + return `${EXTENSION_PREFIX}.${Date.now()}.${++counter}`; +} diff --git a/packages/extension-ui/src/messaging.ts b/packages/extension-ui/src/messaging.ts index e10dfddd..171dd8d6 100644 --- a/packages/extension-ui/src/messaging.ts +++ b/packages/extension-ui/src/messaging.ts @@ -10,6 +10,7 @@ import type { HexString } from '@polkadot/util/types'; import type { KeypairType } from '@polkadot/util-crypto/types'; import { PORT_EXTENSION } from '@polkadot/extension-base/defaults'; +import { getId } from '@polkadot/extension-base/utils/getId'; import { metadataExpand } from '@polkadot/extension-chains'; import chrome from '@polkadot/extension-inject/chrome'; import { MetadataDef } from '@polkadot/extension-inject/types'; @@ -29,7 +30,6 @@ type Handlers = Record; const port = chrome.runtime.connect({ name: PORT_EXTENSION }); const handlers: Handlers = {}; -let idCounter = 0; // setup a listener for messages, any incoming resolves the promise port.onMessage.addListener((data: Message['data']): void => { @@ -60,7 +60,7 @@ function sendMessage(messa function sendMessage(message: TMessageType, request: RequestTypes[TMessageType], subscriber: (data: SubscriptionMessageTypes[TMessageType]) => void): Promise; function sendMessage (message: TMessageType, request?: RequestTypes[TMessageType], subscriber?: (data: unknown) => void): Promise { return new Promise((resolve, reject): void => { - const id = `${Date.now()}.${++idCounter}`; + const id = getId(); handlers[id] = { reject, resolve, subscriber }; diff --git a/packages/extension/src/content.ts b/packages/extension/src/content.ts index 9bce5899..3f16d5bb 100644 --- a/packages/extension/src/content.ts +++ b/packages/extension/src/content.ts @@ -3,7 +3,7 @@ import type { Message } from '@polkadot/extension-base/types'; -import { PORT_CONTENT } from '@polkadot/extension-base/defaults'; +import { MESSAGE_ORIGIN_CONTENT, MESSAGE_ORIGIN_PAGE, PORT_CONTENT } from '@polkadot/extension-base/defaults'; import chrome from '@polkadot/extension-inject/chrome'; // connect to the extension @@ -11,13 +11,13 @@ const port = chrome.runtime.connect({ name: PORT_CONTENT }); // send any messages from the extension back to the page port.onMessage.addListener((data): void => { - window.postMessage({ ...data, origin: 'content' }, '*'); + window.postMessage({ ...data, origin: MESSAGE_ORIGIN_CONTENT }, '*'); }); // all messages from the page, pass them to the extension window.addEventListener('message', ({ data, source }: Message): void => { // only allow messages from our window, by the inject - if (source !== window || data.origin !== 'page') { + if (source !== window || data.origin !== MESSAGE_ORIGIN_PAGE) { return; } diff --git a/packages/extension/src/page.ts b/packages/extension/src/page.ts index 2fcbc68a..c1817488 100644 --- a/packages/extension/src/page.ts +++ b/packages/extension/src/page.ts @@ -4,13 +4,14 @@ import type { RequestSignatures, TransportRequestMessage } from '@polkadot/extension-base/background/types'; import type { Message } from '@polkadot/extension-base/types'; +import { MESSAGE_ORIGIN_CONTENT } from '@polkadot/extension-base/defaults'; import { enable, handleResponse, redirectIfPhishing } from '@polkadot/extension-base/page'; import { injectExtension } from '@polkadot/extension-inject'; // setup a response listener (events created by the loader for extension responses) window.addEventListener('message', ({ data, source }: Message): void => { // only allow messages from our window, by the loader - if (source !== window || data.origin !== 'content') { + if (source !== window || data.origin !== MESSAGE_ORIGIN_CONTENT) { return; }