From e15e56c65a07b5b39c9f781099909469d65eefba Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 3 Jun 2020 16:21:09 +0530 Subject: make permissions work for firefox --- src/webex/compat.ts | 50 +++++++++++++++++++++++++++++++++++++++++++++ src/webex/pages/welcome.tsx | 43 ++++++++++++++++++++++++++++++++------ src/webex/permissions.ts | 20 ++++++++++++++++++ src/webex/wxBackend.ts | 45 +++++++++++++++------------------------- 4 files changed, 124 insertions(+), 34 deletions(-) create mode 100644 src/webex/permissions.ts (limited to 'src') diff --git a/src/webex/compat.ts b/src/webex/compat.ts index 1cbf34a2c..4635abd80 100644 --- a/src/webex/compat.ts +++ b/src/webex/compat.ts @@ -33,3 +33,53 @@ export function isFirefox(): boolean { export function isNode(): boolean { return typeof process !== "undefined" && process.release.name === "node"; } + +/** + * Compatibility API that works on multiple browsers. + */ +export interface CrossBrowserPermissionsApi { + contains( + permissions: chrome.permissions.Permissions, + callback: (result: boolean) => void, + ): void; + + addPermissionsListener( + callback: (permissions: chrome.permissions.Permissions) => void, + ): void; + + request( + permissions: chrome.permissions.Permissions, + callback?: (granted: boolean) => void, + ): void; + + remove( + permissions: chrome.permissions.Permissions, + callback?: (removed: boolean) => void, + ): void; +} + +export function getPermissionsApi(): CrossBrowserPermissionsApi { + const myBrowser = (globalThis as any).browser; + if ( + typeof myBrowser === "object" && + typeof myBrowser.permissions === "object" + ) { + return { + addPermissionsListener: () => { + // Not supported yet. + }, + contains: myBrowser.permissions.contains, + request: myBrowser.permissions.request, + remove: myBrowser.permissions.remove, + }; + } else { + return { + addPermissionsListener: chrome.permissions.onAdded.addListener.bind( + chrome.permissions.onAdded, + ), + contains: chrome.permissions.contains, + request: chrome.permissions.request, + remove: chrome.permissions.remove, + }; + } +} diff --git a/src/webex/pages/welcome.tsx b/src/webex/pages/welcome.tsx index 6e445e431..8d4920cac 100644 --- a/src/webex/pages/welcome.tsx +++ b/src/webex/pages/welcome.tsx @@ -25,6 +25,8 @@ import { getDiagnostics } from "../wxApi"; import { PageLink } from "../renderHtml"; import { WalletDiagnostics } from "../../types/walletTypes"; import * as wxApi from "../wxApi"; +import { getPermissionsApi } from "../compat"; +import { extendedPermissions } from "../permissions"; function Diagnostics(): JSX.Element | null { const [timedOut, setTimedOut] = useState(false); @@ -97,22 +99,51 @@ function Diagnostics(): JSX.Element | null { } export function PermissionsCheckbox(): JSX.Element { - const [extendedPermissions, setExtendedPermissions] = useState(false); - async function handleExtendedPerm(newVal: boolean): Promise { - const res = await wxApi.setExtendedPermissions(newVal); - setExtendedPermissions(res.newValue); + const [extendedPermissionsEnabled, setExtendedPermissionsEnabled] = useState( + false, + ); + async function handleExtendedPerm(requestedVal: boolean): Promise { + let nextVal: boolean | undefined; + if (requestedVal) { + const granted = await new Promise((resolve, reject) => { + // We set permissions here, since apparently FF wants this to be done + // as the result of an input event ... + getPermissionsApi().request( + extendedPermissions, + (granted: boolean) => { + if (chrome.runtime.lastError) { + console.error("error requesting permissions"); + console.error(chrome.runtime.lastError); + reject(chrome.runtime.lastError); + return; + } + console.log("permissions granted:", granted); + resolve(granted); + }, + ); + }); + const res = await wxApi.setExtendedPermissions(granted); + console.log(res); + nextVal = res.newValue; + } else { + const res = await wxApi.setExtendedPermissions(false); + console.log(res); + nextVal = res.newValue; + } + console.log("new permissions applied:", nextVal); + setExtendedPermissionsEnabled(nextVal ?? false); } useEffect(() => { async function getExtendedPermValue(): Promise { const res = await wxApi.getExtendedPermissions(); - setExtendedPermissions(res.newValue); + setExtendedPermissionsEnabled(res.newValue); } getExtendedPermValue(); }); return (
handleExtendedPerm(x.target.checked)} type="checkbox" id="checkbox-perm" diff --git a/src/webex/permissions.ts b/src/webex/permissions.ts new file mode 100644 index 000000000..57ca6dc66 --- /dev/null +++ b/src/webex/permissions.ts @@ -0,0 +1,20 @@ +/* + 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 + */ + +export const extendedPermissions = { + permissions: ["webRequest", "webRequestBlocking"], + origins: ["http://*/*", "https://*/*"], +}; \ No newline at end of file diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts index 0e8b53070..54486c356 100644 --- a/src/webex/wxBackend.ts +++ b/src/webex/wxBackend.ts @@ -40,11 +40,12 @@ import { BrowserHttpLib } from "../util/http"; import { OpenedPromise, openPromise } from "../util/promiseUtils"; import { classifyTalerUri, TalerUriType } from "../util/taleruri"; import { Wallet } from "../wallet"; -import { isFirefox } from "./compat"; +import { isFirefox, getPermissionsApi } from "./compat"; import { MessageType } from "./messages"; import * as wxApi from "./wxApi"; import MessageSender = chrome.runtime.MessageSender; import { Database } from "../util/query"; +import { extendedPermissions } from "./permissions"; const NeedsWallet = Symbol("NeedsWallet"); @@ -63,11 +64,6 @@ let outdatedDbVersion: number | undefined; const walletInit: OpenedPromise = openPromise(); -const extendedPermissions = { - permissions: ["webRequest", "webRequestBlocking"], - origins: ["http://*/*", "https://*/*"], -}; - const notificationPorts: chrome.runtime.Port[] = []; async function handleMessage( @@ -216,7 +212,7 @@ async function handleMessage( if (!proposalId) { throw Error("proposalId missing"); } - if (typeof proposalId !== "string") { + if (typeof proposalId !== "string") { throw Error("proposalId must be a string"); } return needsWallet().getPurchaseDetails(proposalId); @@ -294,26 +290,13 @@ async function handleMessage( return needsWallet().preparePayForUri(detail.talerPayUri); case "set-extended-permissions": { const newVal = detail.value; + console.log("new extended permissions value", newVal); if (newVal) { - const res = await new Promise((resolve, reject) => { - chrome.permissions.request( - extendedPermissions, - (granted: boolean) => { - console.log("permissions granted:", granted); - if (chrome.runtime.lastError) { - console.error(chrome.runtime.lastError); - } - resolve(granted); - }, - ); - }); - if (res) { - setupHeaderListener(); - } - return { newValue: res }; + setupHeaderListener(); + return { newValue: true }; } else { await new Promise((resolve, reject) => { - chrome.permissions.remove(extendedPermissions, (rem) => { + getPermissionsApi().remove(extendedPermissions, (rem) => { console.log("permissions removed:", rem); resolve(); }); @@ -323,7 +306,7 @@ async function handleMessage( } case "get-extended-permissions": { const res = await new Promise((resolve, reject) => { - chrome.permissions.contains(extendedPermissions, (result: boolean) => { + getPermissionsApi().contains(extendedPermissions, (result: boolean) => { resolve(result); }); }); @@ -590,7 +573,7 @@ function headerListener( function setupHeaderListener(): void { console.log("setting up header listener"); // Handlers for catching HTTP requests - chrome.permissions.contains(extendedPermissions, (result: boolean) => { + getPermissionsApi().contains(extendedPermissions, (result: boolean) => { if ( chrome.webRequest.onHeadersReceived && chrome.webRequest.onHeadersReceived.hasListener(headerListener) @@ -644,9 +627,15 @@ export async function wxMain(): Promise { }); }); - setupHeaderListener(); + try { + setupHeaderListener(); + } catch (e) { + console.log(e); + } - chrome.permissions.onAdded.addListener((perm) => { + // On platforms that support it, also listen to external + // modification of permissions. + getPermissionsApi().addPermissionsListener((perm) => { if (chrome.runtime.lastError) { console.error(chrome.runtime.lastError); return; -- cgit v1.2.3