toggle permission

This commit is contained in:
Sebastian 2022-04-27 14:33:52 -03:00
parent 0b8e0a0806
commit 451dd746da
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
16 changed files with 215 additions and 187 deletions

View File

@ -1,63 +0,0 @@
/*
This file is part of TALER
(C) 2016 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { h, VNode } from "preact";
import { useTranslationContext } from "../context/translation.js";
export function DebugCheckbox({
enabled,
onToggle,
}: {
enabled: boolean;
onToggle: () => void;
}): VNode {
const { i18n } = useTranslationContext();
return (
<div>
<input
checked={enabled}
onClick={onToggle}
type="checkbox"
id="checkbox-perm"
style={{ width: "1.5em", height: "1.5em", verticalAlign: "middle" }}
/>
<label
htmlFor="checkbox-perm"
style={{ marginLeft: "0.5em", fontWeight: "bold" }}
>
<i18n.Translate>
Automatically open wallet based on page content
</i18n.Translate>
</label>
<span
style={{
color: "#383838",
fontSize: "smaller",
display: "block",
marginLeft: "2em",
}}
>
(
<i18n.Translate>
Enabling this option below will make using the wallet faster, but
requires more permissions from your browser.
</i18n.Translate>
)
</span>
</div>
);
}

View File

@ -229,3 +229,10 @@ export const EditExchangeModified = createExample(TestedComponent, {
tosProps: normalTosState, tosProps: normalTosState,
}, },
}); });
export const CompletedWithoutBankURL = createExample(TestedComponent, {
state: {
status: "completed",
hook: undefined,
},
});

View File

@ -37,6 +37,7 @@ import {
ButtonWarning, ButtonWarning,
LinkSuccess, LinkSuccess,
SubTitle, SubTitle,
SuccessBox,
WalletAction, WalletAction,
} from "../components/styled/index.js"; } from "../components/styled/index.js";
import { useTranslationContext } from "../context/translation.js"; import { useTranslationContext } from "../context/translation.js";
@ -53,7 +54,12 @@ interface Props {
talerWithdrawUri?: string; talerWithdrawUri?: string;
} }
type State = LoadingUri | LoadingExchange | LoadingInfoError | Success; type State =
| LoadingUri
| LoadingExchange
| LoadingInfoError
| Success
| Completed;
interface LoadingUri { interface LoadingUri {
status: "loading-uri"; status: "loading-uri";
@ -68,6 +74,11 @@ interface LoadingInfoError {
hook: HookError | undefined; hook: HookError | undefined;
} }
type Completed = {
status: "completed";
hook: undefined;
};
type Success = { type Success = {
status: "success"; status: "success";
hook: undefined; hook: undefined;
@ -185,6 +196,7 @@ export function useComponentState(
undefined, undefined,
); );
const [doingWithdraw, setDoingWithdraw] = useState<boolean>(false); const [doingWithdraw, setDoingWithdraw] = useState<boolean>(false);
const [withdrawCompleted, setWithdrawCompleted] = useState<boolean>(false);
const [showExchangeSelection, setShowExchangeSelection] = useState(false); const [showExchangeSelection, setShowExchangeSelection] = useState(false);
const [nextExchange, setNextExchange] = useState<string | undefined>(); const [nextExchange, setNextExchange] = useState<string | undefined>();
@ -220,6 +232,7 @@ export function useComponentState(
if (res.confirmTransferUrl) { if (res.confirmTransferUrl) {
document.location.href = res.confirmTransferUrl; document.location.href = res.confirmTransferUrl;
} }
setWithdrawCompleted(true);
} catch (e) { } catch (e) {
if (e instanceof TalerError) { if (e instanceof TalerError) {
setWithdrawError(e); setWithdrawError(e);
@ -245,6 +258,12 @@ export function useComponentState(
hook: undefined, hook: undefined,
}; };
} }
if (withdrawCompleted) {
return {
status: "completed",
hook: undefined,
};
}
const exchangeHandler: SelectFieldHandler = { const exchangeHandler: SelectFieldHandler = {
onChange: async (e) => setNextExchange(e), onChange: async (e) => setNextExchange(e),
@ -332,8 +351,64 @@ export function useComponentState(
}; };
} }
export function View({ state }: { state: Success }): VNode { export function View({ state }: { state: State }): VNode {
const { i18n } = useTranslationContext(); const { i18n } = useTranslationContext();
if (state.status === "loading-uri") {
if (!state.hook) return <Loading />;
return (
<LoadingError
title={
<i18n.Translate>Could not get the info from the URI</i18n.Translate>
}
error={state.hook}
/>
);
}
if (state.status === "loading-exchange") {
if (!state.hook) return <Loading />;
return (
<LoadingError
title={<i18n.Translate>Could not get exchange</i18n.Translate>}
error={state.hook}
/>
);
}
if (state.status === "loading-info") {
if (!state.hook) return <Loading />;
return (
<LoadingError
title={
<i18n.Translate>Could not get info of withdrawal</i18n.Translate>
}
error={state.hook}
/>
);
}
if (state.status === "completed") {
return (
<WalletAction>
<LogoHeader />
<SubTitle>
<i18n.Translate>Digital cash withdrawal</i18n.Translate>
</SubTitle>
<SuccessBox>
<h3>
<i18n.Translate>Withdrawal in process...</i18n.Translate>
</h3>
<p>
<i18n.Translate>
You can close the page now. Check your bank if the transaction
need a confirmation step to be completed
</i18n.Translate>
</p>
</SuccessBox>
</WalletAction>
);
}
return ( return (
<WalletAction> <WalletAction>
<LogoHeader /> <LogoHeader />
@ -460,39 +535,5 @@ export function WithdrawPage({ talerWithdrawUri }: Props): VNode {
return <Loading />; return <Loading />;
} }
if (state.status === "loading-uri") {
if (!state.hook) return <Loading />;
return (
<LoadingError
title={
<i18n.Translate>Could not get the info from the URI</i18n.Translate>
}
error={state.hook}
/>
);
}
if (state.status === "loading-exchange") {
if (!state.hook) return <Loading />;
return (
<LoadingError
title={<i18n.Translate>Could not get exchange</i18n.Translate>}
error={state.hook}
/>
);
}
if (state.status === "loading-info") {
if (!state.hook) return <Loading />;
return (
<LoadingError
title={
<i18n.Translate>Could not get info of withdrawal</i18n.Translate>
}
error={state.hook}
/>
);
}
return <View state={state} />; return <View state={state} />;
} }

View File

@ -17,23 +17,32 @@
import { useState, useEffect } from "preact/hooks"; import { useState, useEffect } from "preact/hooks";
import * as wxApi from "../wxApi.js"; import * as wxApi from "../wxApi.js";
import { platform } from "../platform/api.js"; import { platform } from "../platform/api.js";
import { getReadRequestPermissions } from "../permissions.js"; import { ToggleHandler } from "../mui/handlers.js";
import { TalerError } from "@gnu-taler/taler-wallet-core";
export function useExtendedPermissions(): [boolean, () => Promise<void>] { export function useExtendedPermissions(): ToggleHandler {
const [enabled, setEnabled] = useState(false); const [enabled, setEnabled] = useState(false);
const [error, setError] = useState<TalerError | undefined>();
const toggle = async (): Promise<void> => { const toggle = async (): Promise<void> => {
return handleExtendedPerm(enabled, setEnabled) return handleExtendedPerm(enabled, setEnabled).catch(e => {
setError(TalerError.fromException(e))
})
}; };
useEffect(() => { useEffect(() => {
async function getExtendedPermValue(): Promise<void> { async function getExtendedPermValue(): Promise<void> {
const res = await wxApi.getExtendedPermissions(); const res = await wxApi.containsHeaderListener();
setEnabled(res.newValue); setEnabled(res.newValue);
} }
getExtendedPermValue(); getExtendedPermValue();
}, []); }, []);
return [enabled, toggle]; return {
value: enabled,
button: {
onClick: toggle,
error
}
};
} }
async function handleExtendedPerm(isEnabled: boolean, onChange: (value: boolean) => void): Promise<void> { async function handleExtendedPerm(isEnabled: boolean, onChange: (value: boolean) => void): Promise<void> {
@ -42,18 +51,20 @@ async function handleExtendedPerm(isEnabled: boolean, onChange: (value: boolean)
// as the result of an input event ... // as the result of an input event ...
let granted: boolean; let granted: boolean;
try { try {
granted = await platform.getPermissionsApi().request(getReadRequestPermissions()); granted = await platform.getPermissionsApi().requestHostPermissions();
} catch (lastError) { } catch (lastError) {
console.error("error requesting permissions");
console.error(lastError);
onChange(false); onChange(false);
return throw lastError;
} }
console.log("permissions granted:", granted); const res = await wxApi.toggleHeaderListener(granted);
const res = await wxApi.setExtendedPermissions(granted);
onChange(res.newValue); onChange(res.newValue);
} else { } else {
await wxApi.setExtendedPermissions(false).then(r => onChange(r.newValue)); try {
await wxApi.toggleHeaderListener(false).then(r => onChange(r.newValue));
} catch (e) {
console.log(e)
}
} }
return return
} }

View File

@ -11,6 +11,11 @@ export interface ButtonHandler {
error?: TalerError; error?: TalerError;
} }
export interface ToggleHandler {
value?: boolean;
button: ButtonHandler;
}
export interface SelectFieldHandler { export interface SelectFieldHandler {
onChange: (value: string) => Promise<void>; onChange: (value: string) => Promise<void>;
error?: string; error?: string;

View File

@ -1,21 +0,0 @@
/*
This file is part of GNU Taler
(C) 2020 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
const perms = {
permissions: ["webRequest"],
origins: ["http://*/*", "https://*/*"],
}
export const getReadRequestPermissions = (): typeof perms => perms

View File

@ -34,9 +34,9 @@ export interface Permissions {
* Compatibility API that works on multiple browsers. * Compatibility API that works on multiple browsers.
*/ */
export interface CrossBrowserPermissionsApi { export interface CrossBrowserPermissionsApi {
contains(p: Permissions): Promise<boolean>; containsHostPermissions(): Promise<boolean>;
request(p: Permissions): Promise<boolean>; requestHostPermissions(): Promise<boolean>;
remove(p: Permissions): Promise<boolean>; removeHostPermissions(): Promise<boolean>;
addPermissionsListener(callback: (p: Permissions, lastError?: string) => void): void; addPermissionsListener(callback: (p: Permissions, lastError?: string) => void): void;
@ -131,6 +131,10 @@ export interface PlatformAPI {
* Backend API * Backend API
*/ */
registerTalerHeaderListener(onHeader: (tabId: number, url: string) => void): void; registerTalerHeaderListener(onHeader: (tabId: number, url: string) => void): void;
/**
* Frontend API
*/
containsTalerHeaderListener(): boolean;
/** /**
* Backend API * Backend API
*/ */

View File

@ -16,7 +16,6 @@
*/ */
import { classifyTalerUri, CoreApiResponse, TalerUriType } from "@gnu-taler/taler-util"; import { classifyTalerUri, CoreApiResponse, TalerUriType } from "@gnu-taler/taler-util";
import { getReadRequestPermissions } from "../permissions.js";
import { CrossBrowserPermissionsApi, MessageFromBackend, Permissions, PlatformAPI } from "./api.js"; import { CrossBrowserPermissionsApi, MessageFromBackend, Permissions, PlatformAPI } from "./api.js";
const api: PlatformAPI = { const api: PlatformAPI = {
@ -37,7 +36,8 @@ const api: PlatformAPI = {
registerTalerHeaderListener, registerTalerHeaderListener,
sendMessageToAllChannels, sendMessageToAllChannels,
sendMessageToWalletBackground, sendMessageToWalletBackground,
useServiceWorkerAsBackgroundProcess useServiceWorkerAsBackgroundProcess,
containsTalerHeaderListener,
} }
export default api; export default api;
@ -46,9 +46,15 @@ function isFirefox(): boolean {
return false; return false;
} }
export function contains(p: Permissions): Promise<boolean> { const hostPermissions = {
permissions: ["webRequest"],
origins: ["http://*/*", "https://*/*"],
}
export function containsHostPermissions(): Promise<boolean> {
return new Promise((res, rej) => { return new Promise((res, rej) => {
chrome.permissions.contains(p, (resp) => { chrome.permissions.contains(hostPermissions, (resp) => {
const le = chrome.runtime.lastError?.message const le = chrome.runtime.lastError?.message
if (le) { if (le) {
rej(le) rej(le)
@ -58,9 +64,9 @@ export function contains(p: Permissions): Promise<boolean> {
}) })
} }
export async function request(p: Permissions): Promise<boolean> { export async function requestHostPermissions(): Promise<boolean> {
return new Promise((res, rej) => { return new Promise((res, rej) => {
chrome.permissions.request(p, (resp) => { chrome.permissions.request(hostPermissions, (resp) => {
const le = chrome.runtime.lastError?.message const le = chrome.runtime.lastError?.message
if (le) { if (le) {
rej(le) rej(le)
@ -70,9 +76,41 @@ export async function request(p: Permissions): Promise<boolean> {
}) })
} }
export async function remove(p: Permissions): Promise<boolean> { type HeaderListenerFunc = (details: chrome.webRequest.WebResponseHeadersDetails) => void
let currentHeaderListener: HeaderListenerFunc | undefined = undefined;
export function containsTalerHeaderListener(): boolean {
return currentHeaderListener !== undefined;
}
export async function removeHostPermissions(): Promise<boolean> {
//if there is a handler already, remove it
if (
"webRequest" in chrome &&
"onHeadersReceived" in chrome.webRequest &&
currentHeaderListener &&
chrome.webRequest.onHeadersReceived.hasListener(currentHeaderListener)
) {
chrome.webRequest.onHeadersReceived.removeListener(currentHeaderListener);
}
currentHeaderListener = undefined;
//notify the browser about this change, this operation is expensive
if ("webRequest" in chrome) {
chrome.webRequest.handlerBehaviorChanged(() => {
if (chrome.runtime.lastError) {
console.error(JSON.stringify(chrome.runtime.lastError));
}
});
}
if (chrome.runtime && chrome.runtime.getManifest().manifest_version === 3) {
// Trying to remove host permissions with manifest >= v3 throws an error
return true;
}
return new Promise((res, rej) => { return new Promise((res, rej) => {
chrome.permissions.remove(p, (resp) => { chrome.permissions.remove(hostPermissions, (resp) => {
const le = chrome.runtime.lastError?.message const le = chrome.runtime.lastError?.message
if (le) { if (le) {
rej(le) rej(le)
@ -92,7 +130,7 @@ function addPermissionsListener(callback: (p: Permissions, lastError?: string) =
function getPermissionsApi(): CrossBrowserPermissionsApi { function getPermissionsApi(): CrossBrowserPermissionsApi {
return { return {
addPermissionsListener, contains, request, remove addPermissionsListener, containsHostPermissions, requestHostPermissions, removeHostPermissions
} }
} }
@ -245,7 +283,6 @@ function getWalletVersion(): WalletVersion {
return manifestData; return manifestData;
} }
function registerTalerHeaderListener(callback: (tabId: number, url: string) => void): void { function registerTalerHeaderListener(callback: (tabId: number, url: string) => void): void {
console.log("setting up header listener"); console.log("setting up header listener");
@ -271,15 +308,18 @@ function registerTalerHeaderListener(callback: (tabId: number, url: string) => v
} }
return; return;
} }
const prevHeaderListener = currentHeaderListener;
currentHeaderListener = headerListener;
getPermissionsApi().contains(getReadRequestPermissions()).then(result => { getPermissionsApi().containsHostPermissions().then(result => {
//if there is a handler already, remove it //if there is a handler already, remove it
if ( if (
"webRequest" in chrome && "webRequest" in chrome &&
"onHeadersReceived" in chrome.webRequest && "onHeadersReceived" in chrome.webRequest &&
chrome.webRequest.onHeadersReceived.hasListener(headerListener) prevHeaderListener &&
chrome.webRequest.onHeadersReceived.hasListener(prevHeaderListener)
) { ) {
chrome.webRequest.onHeadersReceived.removeListener(headerListener); chrome.webRequest.onHeadersReceived.removeListener(prevHeaderListener);
} }
//if the result was positive, add the headerListener //if the result was positive, add the headerListener
if (result) { if (result) {

View File

@ -22,8 +22,9 @@ const frames = ["popup", "wallet"]
const api: PlatformAPI = ({ const api: PlatformAPI = ({
isFirefox: () => false, isFirefox: () => false,
findTalerUriInActiveTab: async () => undefined, findTalerUriInActiveTab: async () => undefined,
containsTalerHeaderListener: () => { return true },
getPermissionsApi: () => ({ getPermissionsApi: () => ({
addPermissionsListener: () => undefined, contains: async () => true, remove: async () => false, request: async () => false addPermissionsListener: () => undefined, containsHostPermissions: async () => true, removeHostPermissions: async () => false, requestHostPermissions: async () => false
}), }),
getWalletVersion: () => ({ getWalletVersion: () => ({
version: 'none' version: 'none'

View File

@ -15,7 +15,7 @@
*/ */
import { CrossBrowserPermissionsApi, Permissions, PlatformAPI } from "./api.js"; import { CrossBrowserPermissionsApi, Permissions, PlatformAPI } from "./api.js";
import chromePlatform, { contains as chromeContains, remove as chromeRemove, request as chromeRequest } from "./chrome.js"; import chromePlatform, { containsHostPermissions as chromeContains, removeHostPermissions as chromeRemove, requestHostPermissions as chromeRequest } from "./chrome.js";
const api: PlatformAPI = { const api: PlatformAPI = {
...chromePlatform, ...chromePlatform,
@ -40,9 +40,9 @@ function addPermissionsListener(callback: (p: Permissions) => void): void {
function getPermissionsApi(): CrossBrowserPermissionsApi { function getPermissionsApi(): CrossBrowserPermissionsApi {
return { return {
addPermissionsListener, addPermissionsListener,
contains: chromeContains, containsHostPermissions: chromeContains,
request: chromeRequest, requestHostPermissions: chromeRequest,
remove: chromeRemove removeHostPermissions: chromeRemove
} }
} }

View File

@ -32,18 +32,19 @@ export default {
export const AllOff = createExample(TestedComponent, { export const AllOff = createExample(TestedComponent, {
deviceName: "this-is-the-device-name", deviceName: "this-is-the-device-name",
permissionToggle: { value: false, button: {} },
setDeviceName: () => Promise.resolve(), setDeviceName: () => Promise.resolve(),
}); });
export const OneChecked = createExample(TestedComponent, { export const OneChecked = createExample(TestedComponent, {
deviceName: "this-is-the-device-name", deviceName: "this-is-the-device-name",
permissionsEnabled: true, permissionToggle: { value: false, button: {} },
setDeviceName: () => Promise.resolve(), setDeviceName: () => Promise.resolve(),
}); });
export const WithOneExchange = createExample(TestedComponent, { export const WithOneExchange = createExample(TestedComponent, {
deviceName: "this-is-the-device-name", deviceName: "this-is-the-device-name",
permissionsEnabled: true, permissionToggle: { value: false, button: {} },
setDeviceName: () => Promise.resolve(), setDeviceName: () => Promise.resolve(),
knownExchanges: [ knownExchanges: [
{ {
@ -62,7 +63,7 @@ export const WithOneExchange = createExample(TestedComponent, {
export const WithExchangeInDifferentState = createExample(TestedComponent, { export const WithExchangeInDifferentState = createExample(TestedComponent, {
deviceName: "this-is-the-device-name", deviceName: "this-is-the-device-name",
permissionsEnabled: true, permissionToggle: { value: false, button: {} },
setDeviceName: () => Promise.resolve(), setDeviceName: () => Promise.resolve(),
knownExchanges: [ knownExchanges: [
{ {

View File

@ -17,6 +17,7 @@
import { ExchangeListItem } from "@gnu-taler/taler-util"; import { ExchangeListItem } from "@gnu-taler/taler-util";
import { Fragment, h, VNode } from "preact"; import { Fragment, h, VNode } from "preact";
import { Checkbox } from "../components/Checkbox.js"; import { Checkbox } from "../components/Checkbox.js";
import { ErrorTalerOperation } from "../components/ErrorTalerOperation.js";
import { JustInDevMode } from "../components/JustInDevMode.js"; import { JustInDevMode } from "../components/JustInDevMode.js";
import { SelectList } from "../components/SelectList.js"; import { SelectList } from "../components/SelectList.js";
import { import {
@ -32,12 +33,13 @@ import { useTranslationContext } from "../context/translation.js";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { useBackupDeviceName } from "../hooks/useBackupDeviceName.js"; import { useBackupDeviceName } from "../hooks/useBackupDeviceName.js";
import { useExtendedPermissions } from "../hooks/useExtendedPermissions.js"; import { useExtendedPermissions } from "../hooks/useExtendedPermissions.js";
import { ToggleHandler } from "../mui/handlers.js";
import { Pages } from "../NavigationBar.js"; import { Pages } from "../NavigationBar.js";
import { buildTermsOfServiceStatus } from "../utils/index.js"; import { buildTermsOfServiceStatus } from "../utils/index.js";
import * as wxApi from "../wxApi.js"; import * as wxApi from "../wxApi.js";
export function SettingsPage(): VNode { export function SettingsPage(): VNode {
const [permissionsEnabled, togglePermissions] = useExtendedPermissions(); const permissionToggle = useExtendedPermissions();
const { devMode, toggleDevMode } = useDevContext(); const { devMode, toggleDevMode } = useDevContext();
const { name, update } = useBackupDeviceName(); const { name, update } = useBackupDeviceName();
@ -52,8 +54,7 @@ export function SettingsPage(): VNode {
} }
deviceName={name} deviceName={name}
setDeviceName={update} setDeviceName={update}
permissionsEnabled={permissionsEnabled} permissionToggle={permissionToggle}
togglePermissions={togglePermissions}
developerMode={devMode} developerMode={devMode}
toggleDeveloperMode={toggleDevMode} toggleDeveloperMode={toggleDevMode}
/> />
@ -63,8 +64,7 @@ export function SettingsPage(): VNode {
export interface ViewProps { export interface ViewProps {
deviceName: string; deviceName: string;
setDeviceName: (s: string) => Promise<void>; setDeviceName: (s: string) => Promise<void>;
permissionsEnabled: boolean; permissionToggle: ToggleHandler;
togglePermissions: () => void;
developerMode: boolean; developerMode: boolean;
toggleDeveloperMode: () => void; toggleDeveloperMode: () => void;
knownExchanges: Array<ExchangeListItem>; knownExchanges: Array<ExchangeListItem>;
@ -72,8 +72,7 @@ export interface ViewProps {
export function SettingsView({ export function SettingsView({
knownExchanges, knownExchanges,
permissionsEnabled, permissionToggle,
togglePermissions,
developerMode, developerMode,
toggleDeveloperMode, toggleDeveloperMode,
}: ViewProps): VNode { }: ViewProps): VNode {
@ -82,6 +81,12 @@ export function SettingsView({
return ( return (
<Fragment> <Fragment>
<section> <section>
{permissionToggle.button.error && (
<ErrorTalerOperation
title={<i18n.Translate>Could not toggle auto-open</i18n.Translate>}
error={permissionToggle.button.error.errorDetail}
/>
)}
<SubTitle> <SubTitle>
<i18n.Translate>Navigator</i18n.Translate> <i18n.Translate>Navigator</i18n.Translate>
</SubTitle> </SubTitle>
@ -98,8 +103,8 @@ export function SettingsView({
requires more permissions from your browser. requires more permissions from your browser.
</i18n.Translate> </i18n.Translate>
} }
enabled={permissionsEnabled} enabled={permissionToggle.value!}
onToggle={togglePermissions} onToggle={permissionToggle.button.onClick!}
/> />
<SubTitle> <SubTitle>

View File

@ -28,7 +28,7 @@ export default {
}; };
export const Normal = createExample(TestedComponent, { export const Normal = createExample(TestedComponent, {
permissionsEnabled: true, permissionToggle: { value: true, button: {} },
diagnostics: { diagnostics: {
errors: [], errors: [],
walletManifestVersion: "1.0", walletManifestVersion: "1.0",
@ -40,9 +40,9 @@ export const Normal = createExample(TestedComponent, {
export const TimedoutDiagnostics = createExample(TestedComponent, { export const TimedoutDiagnostics = createExample(TestedComponent, {
timedOut: true, timedOut: true,
permissionsEnabled: false, permissionToggle: { value: true, button: {} },
}); });
export const RunningDiagnostics = createExample(TestedComponent, { export const RunningDiagnostics = createExample(TestedComponent, {
permissionsEnabled: false, permissionToggle: { value: true, button: {} },
}); });

View File

@ -27,15 +27,15 @@ import { SubTitle, Title } from "../components/styled/index.js";
import { useTranslationContext } from "../context/translation.js"; import { useTranslationContext } from "../context/translation.js";
import { useDiagnostics } from "../hooks/useDiagnostics.js"; import { useDiagnostics } from "../hooks/useDiagnostics.js";
import { useExtendedPermissions } from "../hooks/useExtendedPermissions.js"; import { useExtendedPermissions } from "../hooks/useExtendedPermissions.js";
import { ToggleHandler } from "../mui/handlers.js";
import { platform } from "../platform/api.js"; import { platform } from "../platform/api.js";
export function WelcomePage(): VNode { export function WelcomePage(): VNode {
const [permissionsEnabled, togglePermissions] = useExtendedPermissions(); const permissionToggle = useExtendedPermissions();
const [diagnostics, timedOut] = useDiagnostics(); const [diagnostics, timedOut] = useDiagnostics();
return ( return (
<View <View
permissionsEnabled={permissionsEnabled} permissionToggle={permissionToggle}
togglePermissions={togglePermissions}
diagnostics={diagnostics} diagnostics={diagnostics}
timedOut={timedOut} timedOut={timedOut}
/> />
@ -43,14 +43,12 @@ export function WelcomePage(): VNode {
} }
export interface ViewProps { export interface ViewProps {
permissionsEnabled: boolean; permissionToggle: ToggleHandler;
togglePermissions: () => void;
diagnostics: WalletDiagnostics | undefined; diagnostics: WalletDiagnostics | undefined;
timedOut: boolean; timedOut: boolean;
} }
export function View({ export function View({
permissionsEnabled, permissionToggle,
togglePermissions,
diagnostics, diagnostics,
timedOut, timedOut,
}: ViewProps): VNode { }: ViewProps): VNode {
@ -105,8 +103,8 @@ export function View({
requires more permissions from your browser.) requires more permissions from your browser.)
</i18n.Translate> </i18n.Translate>
} }
enabled={permissionsEnabled} enabled={permissionToggle.value!}
onToggle={togglePermissions} onToggle={permissionToggle.button.onClick!}
/> />
<SubTitle> <SubTitle>
<i18n.Translate>Next Steps</i18n.Translate> <i18n.Translate>Next Steps</i18n.Translate>

View File

@ -345,17 +345,17 @@ export function getDiagnostics(): Promise<WalletDiagnostics> {
/** /**
* Get diagnostics information * Get diagnostics information
*/ */
export function setExtendedPermissions( export function toggleHeaderListener(
value: boolean, value: boolean,
): Promise<ExtendedPermissionsResponse> { ): Promise<ExtendedPermissionsResponse> {
return callBackend("wxSetExtendedPermissions", { value }); return callBackend("toggleHeaderListener", { value });
} }
/** /**
* Get diagnostics information * Get diagnostics information
*/ */
export function getExtendedPermissions(): Promise<ExtendedPermissionsResponse> { export function containsHeaderListener(): Promise<ExtendedPermissionsResponse> {
return callBackend("wxGetExtendedPermissions", {}); return callBackend("containsHeaderListener", {});
} }
/** /**

View File

@ -43,7 +43,6 @@ import {
import { SetTimeoutTimerAPI } from "@gnu-taler/taler-wallet-core"; import { SetTimeoutTimerAPI } from "@gnu-taler/taler-wallet-core";
import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory.js"; import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory.js";
import { BrowserHttpLib } from "./browserHttpLib.js"; import { BrowserHttpLib } from "./browserHttpLib.js";
import { getReadRequestPermissions } from "./permissions.js";
import { MessageFromBackend, platform } from "./platform/api.js"; import { MessageFromBackend, platform } from "./platform/api.js";
import { SynchronousCryptoWorkerFactory } from "./serviceWorkerCryptoWorkerFactory.js"; import { SynchronousCryptoWorkerFactory } from "./serviceWorkerCryptoWorkerFactory.js";
import { ServiceWorkerHttpLib } from "./serviceWorkerHttpLib.js"; import { ServiceWorkerHttpLib } from "./serviceWorkerHttpLib.js";
@ -131,19 +130,19 @@ async function dispatch(
r = wrapResponse(await reinitWallet()); r = wrapResponse(await reinitWallet());
break; break;
} }
case "wxGetExtendedPermissions": { case "containsHeaderListener": {
const res = await platform.getPermissionsApi().contains(getReadRequestPermissions()); const res = await platform.containsTalerHeaderListener();
r = wrapResponse({ newValue: res }); r = wrapResponse({ newValue: res });
break; break;
} }
case "wxSetExtendedPermissions": { case "toggleHeaderListener": {
const newVal = req.payload.value; const newVal = req.payload.value;
logger.trace("new extended permissions value", newVal); logger.trace("new extended permissions value", newVal);
if (newVal) { if (newVal) {
platform.registerTalerHeaderListener(parseTalerUriAndRedirect); platform.registerTalerHeaderListener(parseTalerUriAndRedirect);
r = wrapResponse({ newValue: true }); r = wrapResponse({ newValue: true });
} else { } else {
const rem = await platform.getPermissionsApi().remove(getReadRequestPermissions()); const rem = await platform.getPermissionsApi().removeHostPermissions();
logger.trace("permissions removed:", rem); logger.trace("permissions removed:", rem);
r = wrapResponse({ newVal: false }); r = wrapResponse({ newVal: false });
} }