toggle permission
This commit is contained in:
parent
0b8e0a0806
commit
451dd746da
@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
@ -229,3 +229,10 @@ export const EditExchangeModified = createExample(TestedComponent, {
|
|||||||
tosProps: normalTosState,
|
tosProps: normalTosState,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const CompletedWithoutBankURL = createExample(TestedComponent, {
|
||||||
|
state: {
|
||||||
|
status: "completed",
|
||||||
|
hook: undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
@ -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} />;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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) {
|
||||||
|
@ -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'
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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: [
|
||||||
{
|
{
|
||||||
|
@ -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>
|
||||||
|
@ -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: {} },
|
||||||
});
|
});
|
||||||
|
@ -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>
|
||||||
|
@ -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", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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 });
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user