Add authorized URL removal (#1029)

* Add authorized URL removal

Adds a trashcan icon to the website entries
Introduces removeAuth and removeAuthorization functions

* Resolves Linting issues
This commit is contained in:
CustomBlink 2022-03-21 09:56:26 +01:00 committed by GitHub
parent 6ff6073d6a
commit 415184ac0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 86 additions and 4 deletions

View File

@ -504,6 +504,10 @@ export default class Extension {
return { list: this.#state.toggleAuthorization(url) };
}
private removeAuthorization (url: string): ResponseAuthorizeList {
return { list: this.#state.removeAuthorization(url) };
}
// 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<ResponseType<TMessageType>> {
@ -520,6 +524,9 @@ export default class Extension {
case 'pri(authorize.toggle)':
return this.toggleAuthorization(request as string);
case 'pri(authorize.remove)':
return this.removeAuthorization(request as string);
case 'pri(authorize.requests)':
return this.authorizeSubscribe(id, port);

View File

@ -327,6 +327,17 @@ export default class State {
return this.#authUrls;
}
public removeAuthorization (url: string): AuthUrls {
const entry = this.#authUrls[url];
assert(entry, `The source ${url} is not known`);
delete this.#authUrls[url];
this.saveCurrentAuthList();
return this.#authUrls;
}
private updateIconAuth (shouldClose?: boolean): void {
this.authSubject.next(this.allAuthRequests);
this.updateIcon(shouldClose);

View File

@ -92,6 +92,7 @@ export interface RequestSignatures {
'pri(authorize.reject)': [RequestAuthorizeReject, boolean];
'pri(authorize.requests)': [RequestAuthorizeSubscribe, boolean, AuthorizeRequest[]];
'pri(authorize.toggle)': [string, ResponseAuthorizeList];
'pri(authorize.remove)': [string, ResponseAuthorizeList];
'pri(derivation.create)': [RequestDeriveCreate, boolean];
'pri(derivation.validate)': [RequestDeriveValidate, ResponseDeriveValidate];
'pri(json.restore)': [RequestJsonRestore, void];

View File

@ -7,24 +7,29 @@ import React, { useCallback } from 'react';
import styled from 'styled-components';
import { AuthUrlInfo } from '@polkadot/extension-base/background/handlers/State';
import { Switch } from '@polkadot/extension-ui/components';
import { RemoveAuth, Switch } from '@polkadot/extension-ui/components';
import useTranslation from '../../hooks/useTranslation';
interface Props extends ThemeProps {
className?: string;
info: AuthUrlInfo;
toggleAuth: (url: string) => void
toggleAuth: (url: string) => void;
removeAuth: (url: string) => void;
url: string;
}
function WebsiteEntry ({ className = '', info, toggleAuth, url }: Props): React.ReactElement<Props> {
function WebsiteEntry ({ className = '', info, removeAuth, toggleAuth, url }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const switchAccess = useCallback(() => {
toggleAuth(url);
}, [toggleAuth, url]);
const _removeAuth = useCallback(() => {
removeAuth(url);
}, [removeAuth, url]);
return (
<div className={`${className} ${info.isAllowed ? 'allowed' : 'denied'}`}>
<div className='url'>
@ -37,6 +42,13 @@ function WebsiteEntry ({ className = '', info, toggleAuth, url }: Props): React.
onChange={switchAccess}
uncheckedLabel={t<string>('denied')}
/>
<div
className='removeAuth'
onClick={_removeAuth}
>
<RemoveAuth />
</div>
</div>
);
}

View File

@ -10,7 +10,7 @@ import { AuthUrlInfo, AuthUrls } from '@polkadot/extension-base/background/handl
import { InputFilter } from '@polkadot/extension-ui/components';
import useTranslation from '../../hooks/useTranslation';
import { getAuthList, toggleAuthorization } from '../../messaging';
import { getAuthList, removeAuthorization, toggleAuthorization } from '../../messaging';
import { Header } from '../../partials';
import WebsiteEntry from './WebsiteEntry';
@ -39,6 +39,12 @@ function AuthManagement ({ className }: Props): React.ReactElement<Props> {
.catch(console.error);
}, []);
const removeAuth = useCallback((url: string) => {
removeAuthorization(url)
.then(({ list }) => setAuthList(list))
.catch(console.error);
}, []);
return (
<>
<Header
@ -66,6 +72,7 @@ function AuthManagement ({ className }: Props): React.ReactElement<Props> {
<WebsiteEntry
info={info}
key={url}
removeAuth={removeAuth}
toggleAuth={toggleAuth}
url={url}
/>

View File

@ -0,0 +1,39 @@
// Copyright 2019-2022 @polkadot/extension-ui authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ThemeProps } from '../types';
import { faTrash } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React from 'react';
import styled from 'styled-components';
function RemoveAuth (): React.ReactElement {
return (
<FontAwesomeIcon
className='trashIcon'
icon={faTrash}
size='lg'
/>
);
}
export default styled(RemoveAuth)(({ theme }: ThemeProps) => `
label {
position: relative;
display: inline-block;
width: 48px;
height: 24px;
margin: 8px;
}
.trashIcon {
color: ${theme.iconNeutralColor};
margin-left: 8px;
&.selected {
color: ${theme.primaryColor};
}
}
`);

View File

@ -28,6 +28,7 @@ export { default as MenuDivider } from './MenuDivider';
export { default as MenuItem } from './MenuItem';
export { default as MnemonicSeed } from './MnemonicSeed';
export { default as NextStepButton } from './NextStepButton';
export { default as RemoveAuth } from './RemoveAuth';
export { default as Spinner } from './Spinner';
export { default as Svg } from './Svg';
export { default as Switch } from './Switch';

View File

@ -196,6 +196,10 @@ export async function toggleAuthorization (url: string): Promise<ResponseAuthori
return sendMessage('pri(authorize.toggle)', url);
}
export async function removeAuthorization (url: string): Promise<ResponseAuthorizeList> {
return sendMessage('pri(authorize.remove)', url);
}
export async function subscribeMetadataRequests (cb: (accounts: MetadataRequest[]) => void): Promise<boolean> {
return sendMessage('pri(metadata.requests)', null, cb);
}