Refactor open window (#473)
* add mnemonic redirect like json * undefined not allowed because request is a defined object * Apply suggestions from code review Co-authored-by: Jaco Greeff <jacogr@gmail.com> * remove redirect Co-authored-by: Jaco Greeff <jacogr@gmail.com>
This commit is contained in:
parent
3e357cc864
commit
7c01b9e658
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
import { MetadataDef } from '@polkadot/extension-inject/types';
|
import { MetadataDef } from '@polkadot/extension-inject/types';
|
||||||
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
|
||||||
import { AccountJson, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountCreateExternal, RequestAccountCreateSuri, RequestAccountEdit, RequestAccountExport, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestAuthorizeApprove, RequestAuthorizeReject, RequestDeriveCreate, ResponseDeriveValidate, RequestMetadataApprove, RequestMetadataReject, RequestSigningApprovePassword, RequestSigningApproveSignature, RequestSigningCancel, RequestSigningIsLocked, RequestSeedCreate, RequestTypes, ResponseAccountExport, RequestAccountForget, ResponseSeedCreate, RequestSeedValidate, RequestDeriveValidate, ResponseSeedValidate, ResponseType, SigningRequest, RequestJsonRestore, ResponseJsonRestore, RequestAccountChangePassword } from '../types';
|
import { AccountJson, AllowedPath, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountCreateExternal, RequestAccountCreateSuri, RequestAccountEdit, RequestAccountExport, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestAuthorizeApprove, RequestAuthorizeReject, RequestDeriveCreate, ResponseDeriveValidate, RequestMetadataApprove, RequestMetadataReject, RequestSigningApprovePassword, RequestSigningApproveSignature, RequestSigningCancel, RequestSigningIsLocked, RequestSeedCreate, RequestTypes, ResponseAccountExport, RequestAccountForget, ResponseSeedCreate, RequestSeedValidate, RequestDeriveValidate, ResponseSeedValidate, ResponseType, SigningRequest, RequestJsonRestore, ResponseJsonRestore, RequestAccountChangePassword } from '../types';
|
||||||
|
|
||||||
import { PASSWORD_EXPIRY_MS } from '@polkadot/extension-base/defaults';
|
import { ALLOWED_PATH, PASSWORD_EXPIRY_MS } from '@polkadot/extension-base/defaults';
|
||||||
import chrome from '@polkadot/extension-inject/chrome';
|
import chrome from '@polkadot/extension-inject/chrome';
|
||||||
import keyring from '@polkadot/ui-keyring';
|
import keyring from '@polkadot/ui-keyring';
|
||||||
import accountsObservable from '@polkadot/ui-keyring/observable/accounts';
|
import accountsObservable from '@polkadot/ui-keyring/observable/accounts';
|
||||||
@ -377,12 +377,17 @@ export default class Extension {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private windowOpen (path = '/'): boolean {
|
private windowOpen (path: AllowedPath): boolean {
|
||||||
console.error('open', `${chrome.extension.getURL('index.html')}#${path}`);
|
const url = `${chrome.extension.getURL('index.html')}#${path}`;
|
||||||
|
|
||||||
chrome.tabs.create({
|
if (!ALLOWED_PATH.includes(path)) {
|
||||||
url: `${chrome.extension.getURL('index.html')}#${path}`
|
console.error('Not allowed to open the url:', url);
|
||||||
});
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('open', url);
|
||||||
|
chrome.tabs.create({ url });
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -520,10 +525,7 @@ export default class Extension {
|
|||||||
return this.signingSubscribe(id, port);
|
return this.signingSubscribe(id, port);
|
||||||
|
|
||||||
case 'pri(window.open)':
|
case 'pri(window.open)':
|
||||||
return this.windowOpen();
|
return this.windowOpen(request as AllowedPath);
|
||||||
|
|
||||||
case 'pri(window.open.json)':
|
|
||||||
return this.windowOpen('/account/restore-json');
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unable to handle message of type ${type}`);
|
throw new Error(`Unable to handle message of type ${type}`);
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import { KeyringPair, KeyringPair$Json, KeyringPair$Meta } from '@polkadot/keyri
|
|||||||
import { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types';
|
import { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types';
|
||||||
import { TypeRegistry } from '@polkadot/types';
|
import { TypeRegistry } from '@polkadot/types';
|
||||||
|
|
||||||
|
import { ALLOWED_PATH } from '../defaults';
|
||||||
|
|
||||||
type KeysWithDefinedValues<T> = {
|
type KeysWithDefinedValues<T> = {
|
||||||
[K in keyof T]: T[K] extends undefined ? never : K
|
[K in keyof T]: T[K] extends undefined ? never : K
|
||||||
}[keyof T];
|
}[keyof T];
|
||||||
@ -97,8 +99,7 @@ export interface RequestSignatures {
|
|||||||
'pri(signing.cancel)': [RequestSigningCancel, boolean];
|
'pri(signing.cancel)': [RequestSigningCancel, boolean];
|
||||||
'pri(signing.isLocked)': [RequestSigningIsLocked, boolean];
|
'pri(signing.isLocked)': [RequestSigningIsLocked, boolean];
|
||||||
'pri(signing.requests)': [RequestSigningSubscribe, boolean, SigningRequest[]];
|
'pri(signing.requests)': [RequestSigningSubscribe, boolean, SigningRequest[]];
|
||||||
'pri(window.open)': [null, boolean];
|
'pri(window.open)': [AllowedPath, boolean];
|
||||||
'pri(window.open.json)': [null, boolean];
|
|
||||||
// public/external requests, i.e. from a page
|
// public/external requests, i.e. from a page
|
||||||
'pub(accounts.list)': [RequestAccountList, InjectedAccount[]];
|
'pub(accounts.list)': [RequestAccountList, InjectedAccount[]];
|
||||||
'pub(accounts.subscribe)': [RequestAccountSubscribe, boolean, InjectedAccount[]];
|
'pub(accounts.subscribe)': [RequestAccountSubscribe, boolean, InjectedAccount[]];
|
||||||
@ -348,3 +349,5 @@ export interface RequestJsonRestore {
|
|||||||
export interface ResponseJsonRestore {
|
export interface ResponseJsonRestore {
|
||||||
error: string | null;
|
error: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AllowedPath = typeof ALLOWED_PATH[number];
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
// Copyright 2019-2020 @polkadot/extension-base authors & contributors
|
// Copyright 2019-2020 @polkadot/extension-base authors & contributors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
const ALLOWED_PATH = ['/', '/account/restore-json'] as const;
|
||||||
const PORT_CONTENT = 'content';
|
const PORT_CONTENT = 'content';
|
||||||
const PORT_EXTENSION = 'extension';
|
const PORT_EXTENSION = 'extension';
|
||||||
const PASSWORD_EXPIRY_MIN = 15;
|
const PASSWORD_EXPIRY_MIN = 15;
|
||||||
const PASSWORD_EXPIRY_MS = PASSWORD_EXPIRY_MIN * 60 * 1000;
|
const PASSWORD_EXPIRY_MS = PASSWORD_EXPIRY_MIN * 60 * 1000;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
ALLOWED_PATH,
|
||||||
PASSWORD_EXPIRY_MIN,
|
PASSWORD_EXPIRY_MIN,
|
||||||
PASSWORD_EXPIRY_MS,
|
PASSWORD_EXPIRY_MS,
|
||||||
PORT_CONTENT,
|
PORT_CONTENT,
|
||||||
|
|||||||
10
packages/extension-ui/src/hooks/useIsPopup.ts
Normal file
10
packages/extension-ui/src/hooks/useIsPopup.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2019-2020 @polkadot/extension-ui authors & contributors
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
export default function useIsPopup (): boolean {
|
||||||
|
return useMemo(() => {
|
||||||
|
return window.innerWidth <= 560;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import { Message } from '@polkadot/extension-base/types';
|
import { Message } from '@polkadot/extension-base/types';
|
||||||
import { AccountJson, AuthorizeRequest, SigningRequest, RequestTypes, MessageTypes, ResponseTypes, SeedLengths, SubscriptionMessageTypes, MetadataRequest, MessageTypesWithNullRequest, MessageTypesWithNoSubscriptions, MessageTypesWithSubscriptions, ResponseDeriveValidate, ResponseJsonRestore } from '@polkadot/extension-base/background/types';
|
import { AccountJson, AllowedPath, AuthorizeRequest, SigningRequest, RequestTypes, MessageTypes, ResponseTypes, SeedLengths, SubscriptionMessageTypes, MetadataRequest, MessageTypesWithNullRequest, MessageTypesWithNoSubscriptions, MessageTypesWithSubscriptions, ResponseDeriveValidate, ResponseJsonRestore } from '@polkadot/extension-base/background/types';
|
||||||
import { Chain } from '@polkadot/extension-chains/types';
|
import { Chain } from '@polkadot/extension-chains/types';
|
||||||
import { MetadataDef } from '@polkadot/extension-inject/types';
|
import { MetadataDef } from '@polkadot/extension-inject/types';
|
||||||
import { KeypairType } from '@polkadot/util-crypto/types';
|
import { KeypairType } from '@polkadot/util-crypto/types';
|
||||||
@ -186,10 +186,6 @@ export async function validateSeed (suri: string, type?: KeypairType): Promise<{
|
|||||||
return sendMessage('pri(seed.validate)', { suri, type });
|
return sendMessage('pri(seed.validate)', { suri, type });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function windowOpen (): Promise<boolean> {
|
|
||||||
return sendMessage('pri(window.open)', null);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function validateDerivationPath (parentAddress: string, suri: string, parentPassword: string): Promise<ResponseDeriveValidate> {
|
export async function validateDerivationPath (parentAddress: string, suri: string, parentPassword: string): Promise<ResponseDeriveValidate> {
|
||||||
return sendMessage('pri(derivation.validate)', { parentAddress, parentPassword, suri });
|
return sendMessage('pri(derivation.validate)', { parentAddress, parentPassword, suri });
|
||||||
}
|
}
|
||||||
@ -198,8 +194,8 @@ export async function deriveAccount (parentAddress: string, suri: string, parent
|
|||||||
return sendMessage('pri(derivation.create)', { genesisHash, name, parentAddress, parentPassword, password, suri });
|
return sendMessage('pri(derivation.create)', { genesisHash, name, parentAddress, parentPassword, password, suri });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function jsonRestoreWindowOpen (): Promise<boolean> {
|
export async function windowOpen (path: AllowedPath): Promise<boolean> {
|
||||||
return sendMessage('pri(window.open.json)', null);
|
return sendMessage('pri(window.open)', path);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function jsonVerifyFile (json: KeyringPair$Json): Promise<boolean> {
|
export async function jsonVerifyFile (json: KeyringPair$Json): Promise<boolean> {
|
||||||
|
|||||||
@ -11,23 +11,25 @@ import plusIcon from '../assets/plus.svg';
|
|||||||
import qrIcon from '../assets/qr.svg';
|
import qrIcon from '../assets/qr.svg';
|
||||||
import seedIcon from '../assets/secret.svg';
|
import seedIcon from '../assets/secret.svg';
|
||||||
import { AccountContext, Link, MediaContext, Menu, MenuDivider, MenuItem, Svg } from '../components';
|
import { AccountContext, Link, MediaContext, Menu, MenuDivider, MenuItem, Svg } from '../components';
|
||||||
|
import useIsPopup from '../hooks/useIsPopup';
|
||||||
import useTranslation from '../hooks/useTranslation';
|
import useTranslation from '../hooks/useTranslation';
|
||||||
import { jsonRestoreWindowOpen } from '../messaging';
|
import { windowOpen } from '../messaging';
|
||||||
|
|
||||||
interface Props extends ThemeProps {
|
interface Props extends ThemeProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
reference: React.MutableRefObject<null>;
|
reference: React.MutableRefObject<null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPopup = window.innerWidth <= 480;
|
const jsonPath = '/account/restore-json';
|
||||||
|
|
||||||
function MenuAdd ({ className, reference }: Props): React.ReactElement<Props> {
|
function MenuAdd ({ className, reference }: Props): React.ReactElement<Props> {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { master } = useContext(AccountContext);
|
const { master } = useContext(AccountContext);
|
||||||
const mediaAllowed = useContext(MediaContext);
|
const mediaAllowed = useContext(MediaContext);
|
||||||
|
const isPopup = useIsPopup();
|
||||||
|
|
||||||
const _openJson = useCallback((): void => {
|
const _openJson = useCallback((): void => {
|
||||||
jsonRestoreWindowOpen().catch(console.error);
|
windowOpen(jsonPath).catch(console.error);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -55,7 +57,7 @@ function MenuAdd ({ className, reference }: Props): React.ReactElement<Props> {
|
|||||||
<MenuItem className='menuItem'>
|
<MenuItem className='menuItem'>
|
||||||
<Link
|
<Link
|
||||||
onClick={isPopup ? _openJson : undefined}
|
onClick={isPopup ? _openJson : undefined}
|
||||||
to={isPopup ? undefined : '/account/restore-json'}
|
to={isPopup ? undefined : jsonPath}
|
||||||
>
|
>
|
||||||
<Svg src={fileIcon} />
|
<Svg src={fileIcon} />
|
||||||
<span>{t<string>('Restore account from backup JSON file')}</span>
|
<span>{t<string>('Restore account from backup JSON file')}</span>
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import settings from '@polkadot/ui-settings';
|
|||||||
|
|
||||||
import FullScreenIcon from '../assets/fullscreen.svg';
|
import FullScreenIcon from '../assets/fullscreen.svg';
|
||||||
import { ActionText, Checkbox, Dropdown, Menu, MenuDivider, MenuItem, Svg, Switch, ThemeSwitchContext, themes } from '../components';
|
import { ActionText, Checkbox, Dropdown, Menu, MenuDivider, MenuItem, Svg, Switch, ThemeSwitchContext, themes } from '../components';
|
||||||
|
import useIsPopup from '../hooks/useIsPopup';
|
||||||
import useTranslation from '../hooks/useTranslation';
|
import useTranslation from '../hooks/useTranslation';
|
||||||
import { windowOpen } from '../messaging';
|
import { windowOpen } from '../messaging';
|
||||||
import getLanguageOptions from '../util/getLanguageOptions';
|
import getLanguageOptions from '../util/getLanguageOptions';
|
||||||
@ -23,7 +24,6 @@ interface Props extends ThemeProps {
|
|||||||
reference: React.MutableRefObject<null>;
|
reference: React.MutableRefObject<null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPopup = window.innerWidth <= 560;
|
|
||||||
const prefixOptions = settings.availablePrefixes
|
const prefixOptions = settings.availablePrefixes
|
||||||
.filter(({ value }) => value !== -1)
|
.filter(({ value }) => value !== -1)
|
||||||
.map(({ text, value }): Option => ({ text, value: `${value}` }));
|
.map(({ text, value }): Option => ({ text, value: `${value}` }));
|
||||||
@ -34,6 +34,7 @@ function MenuSettings ({ className, reference }: Props): React.ReactElement<Prop
|
|||||||
const [prefix, setPrefix] = useState(`${settings.prefix === -1 ? 42 : settings.prefix}`);
|
const [prefix, setPrefix] = useState(`${settings.prefix === -1 ? 42 : settings.prefix}`);
|
||||||
const themeContext = useContext<Theme>(ThemeContext);
|
const themeContext = useContext<Theme>(ThemeContext);
|
||||||
const setTheme = useContext(ThemeSwitchContext);
|
const setTheme = useContext(ThemeSwitchContext);
|
||||||
|
const isPopup = useIsPopup();
|
||||||
const languageOptions = useMemo(() => getLanguageOptions(), []);
|
const languageOptions = useMemo(() => getLanguageOptions(), []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -53,6 +54,11 @@ function MenuSettings ({ className, reference }: Props): React.ReactElement<Prop
|
|||||||
[setTheme]
|
[setTheme]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const _onWindowOpen = useCallback(
|
||||||
|
() => windowOpen('/'),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const _onChangeLang = useCallback(
|
const _onChangeLang = useCallback(
|
||||||
(value: string): void => {
|
(value: string): void => {
|
||||||
settings.set({ i18nLang: value });
|
settings.set({ i18nLang: value });
|
||||||
@ -121,7 +127,7 @@ function MenuSettings ({ className, reference }: Props): React.ReactElement<Prop
|
|||||||
<ActionText
|
<ActionText
|
||||||
className='openWindow'
|
className='openWindow'
|
||||||
icon={FullScreenIcon}
|
icon={FullScreenIcon}
|
||||||
onClick={windowOpen}
|
onClick={_onWindowOpen}
|
||||||
text={t<string>('Open extension in new window')}
|
text={t<string>('Open extension in new window')}
|
||||||
/>
|
/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user