summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2022-01-16 17:54:48 -0300
committerSebastian <sebasjm@gmail.com>2022-01-16 17:55:01 -0300
commitbc817a638d4ddfff0d5f05b51453c6ca790b24ec (patch)
treeef6d62b503a163f7738ce37785b3c38ff48abb76
parentf8ae2671c176e293843525c4fc5dd4a33653fd10 (diff)
downloadwallet-core-bc817a638d4ddfff0d5f05b51453c6ca790b24ec.tar.gz
wallet-core-bc817a638d4ddfff0d5f05b51453c6ca790b24ec.tar.bz2
wallet-core-bc817a638d4ddfff0d5f05b51453c6ca790b24ec.zip
#7120 manifest v3: first iteration working
new permission needed: scripting chrome.browserAction -> chrome.action webRequestBlocking is not possible anymore chrome.extension.getUrl -> chrome.runtime.getUrl new serviceWorkerHttpLib: using fetch new serviceWorkerCryptoWorkerFactory: using syncCryptoImpl few other minor changes still missing some other changes like migrating setTimeout to chrome.alarms api
-rw-r--r--packages/taler-wallet-webextension/manifest-v3.json25
-rw-r--r--packages/taler-wallet-webextension/package.json2
-rw-r--r--packages/taler-wallet-webextension/src/api/browser.ts30
-rw-r--r--packages/taler-wallet-webextension/src/background.ts10
-rw-r--r--packages/taler-wallet-webextension/src/chromeBadge.ts2
-rw-r--r--packages/taler-wallet-webextension/src/permissions.ts2
-rw-r--r--packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/popup/Settings.tsx4
-rw-r--r--packages/taler-wallet-webextension/src/popupEntryPoint.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/renderHtml.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts36
-rw-r--r--packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts146
-rw-r--r--packages/taler-wallet-webextension/src/utils/index.ts2
-rw-r--r--packages/taler-wallet-webextension/src/wxBackend.ts71
-rw-r--r--pnpm-lock.yaml8
15 files changed, 282 insertions, 62 deletions
diff --git a/packages/taler-wallet-webextension/manifest-v3.json b/packages/taler-wallet-webextension/manifest-v3.json
index b7f7c9026..6024b7505 100644
--- a/packages/taler-wallet-webextension/manifest-v3.json
+++ b/packages/taler-wallet-webextension/manifest-v3.json
@@ -1,41 +1,28 @@
{
"manifest_version": 3,
-
"name": "GNU Taler Wallet (git)",
"description": "Privacy preserving and transparent payments",
"author": "GNU Taler Developers",
"version": "0.8.1.15",
"version_name": "0.8.1-dev.15",
-
"minimum_chrome_version": "88",
-
- "applications": {
- "gecko": {
- "id": "wallet@taler.net",
- "strict_min_version": "57.0"
- }
- },
-
"icons": {
"32": "static/img/icon.png",
"128": "static/img/logo.png"
},
-
"permissions": [
"unlimitedStorage",
- "activeTab"
+ "activeTab",
+ "scripting"
],
-
"optional_permissions": [
"webRequest",
"webRequestBlocking"
],
-
- "host_permissions":[
+ "host_permissions": [
"http://*/*",
"https://*/*"
],
-
"action": {
"default_icon": {
"32": "static/img/icon.png"
@@ -43,9 +30,7 @@
"default_title": "Taler",
"default_popup": "static/popup.html"
},
-
"background": {
- "page": "static/background.html",
- "persistent": true
+ "service_worker": "dist/background.js"
}
-}
+} \ No newline at end of file
diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json
index fd4b0fb45..9b02eee24 100644
--- a/packages/taler-wallet-webextension/package.json
+++ b/packages/taler-wallet-webextension/package.json
@@ -48,7 +48,7 @@
"@storybook/preact": "6.4.9",
"@testing-library/preact": "^2.0.1",
"@testing-library/preact-hooks": "^1.1.0",
- "@types/chrome": "^0.0.174",
+ "@types/chrome": "0.0.176",
"@types/history": "^4.7.8",
"@types/mocha": "^9.0.0",
"@types/node": "^17.0.8",
diff --git a/packages/taler-wallet-webextension/src/api/browser.ts b/packages/taler-wallet-webextension/src/api/browser.ts
index bc50853fb..b69a49680 100644
--- a/packages/taler-wallet-webextension/src/api/browser.ts
+++ b/packages/taler-wallet-webextension/src/api/browser.ts
@@ -1,6 +1,36 @@
+function searchForTalerLinks(): string | undefined {
+ let found;
+ found = document.querySelector("a[href^='taler://'")
+ if (found) return found.toString()
+ found = document.querySelector("a[href^='taler+http://'")
+ if (found) return found.toString()
+ return undefined
+}
+
+async function getCurrentTab() {
+ let queryOptions = { active: true, currentWindow: true };
+ let [tab] = await chrome.tabs.query(queryOptions);
+ return tab;
+}
+
+
export async function findTalerUriInActiveTab(): Promise<string | undefined> {
+ if (chrome.runtime.getManifest().manifest_version === 3) {
+ // manifest v3
+ const tab = await getCurrentTab();
+ const res = await chrome.scripting.executeScript({
+ target: {
+ tabId: tab.id!,
+ allFrames: true,
+ } as any,
+ func: searchForTalerLinks,
+ args: []
+ })
+ return res[0].result
+ }
return new Promise((resolve, reject) => {
+ //manifest v2
chrome.tabs.executeScript(
{
code: `
diff --git a/packages/taler-wallet-webextension/src/background.ts b/packages/taler-wallet-webextension/src/background.ts
index dcbf96139..428cd86f5 100644
--- a/packages/taler-wallet-webextension/src/background.ts
+++ b/packages/taler-wallet-webextension/src/background.ts
@@ -25,6 +25,12 @@
*/
import { wxMain } from "./wxBackend";
-window.addEventListener("load", () => {
+const loadedFromWebpage = typeof window !== "undefined"
+
+if (chrome.runtime.getManifest().manifest_version === 3) {
wxMain();
-});
+} else {
+ window.addEventListener("load", () => {
+ wxMain();
+ });
+}
diff --git a/packages/taler-wallet-webextension/src/chromeBadge.ts b/packages/taler-wallet-webextension/src/chromeBadge.ts
index 7bc5d368d..60585793e 100644
--- a/packages/taler-wallet-webextension/src/chromeBadge.ts
+++ b/packages/taler-wallet-webextension/src/chromeBadge.ts
@@ -198,7 +198,7 @@ export class ChromeBadge {
this.canvas.width,
this.canvas.height,
);
- chrome.browserAction.setIcon({ imageData });
+ chrome.action.setIcon({ imageData });
} catch (e) {
// Might fail if browser has over-eager canvas fingerprinting countermeasures.
// There's nothing we can do then ...
diff --git a/packages/taler-wallet-webextension/src/permissions.ts b/packages/taler-wallet-webextension/src/permissions.ts
index bcd357fd6..909433bb8 100644
--- a/packages/taler-wallet-webextension/src/permissions.ts
+++ b/packages/taler-wallet-webextension/src/permissions.ts
@@ -15,6 +15,6 @@
*/
export const extendedPermissions = {
- permissions: ["webRequest", "webRequestBlocking"],
+ permissions: ["webRequest"],
origins: ["http://*/*", "https://*/*"],
};
diff --git a/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx b/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx
index ea87ba01f..f4b49c230 100644
--- a/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx
@@ -194,7 +194,7 @@ export function openExtensionPage(page: string) {
// eslint-disable-next-line no-undef
chrome.tabs.create({
// eslint-disable-next-line no-undef
- url: chrome.extension.getURL(page),
+ url: chrome.runtime.getURL(page),
});
};
}
diff --git a/packages/taler-wallet-webextension/src/popup/Settings.tsx b/packages/taler-wallet-webextension/src/popup/Settings.tsx
index 3732cf7b5..a7cdf9cc0 100644
--- a/packages/taler-wallet-webextension/src/popup/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Settings.tsx
@@ -60,9 +60,9 @@ export function SettingsView({
style={{ color: "darkgreen", textDecoration: "none" }}
href={
// eslint-disable-next-line no-undef
- chrome.extension
+ chrome.runtime
? // eslint-disable-next-line no-undef
- chrome.extension.getURL(`/static/wallet.html#/settings`)
+ chrome.runtime.getURL(`/static/wallet.html#/settings`)
: "#"
}
>
diff --git a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
index 908349e89..5cd68b9b4 100644
--- a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
@@ -173,7 +173,7 @@ function goToWalletPage(page: Pages | string): null {
chrome.tabs.create({
active: true,
// eslint-disable-next-line no-undef
- url: chrome.extension.getURL(`/static/wallet.html#${page}`),
+ url: chrome.runtime.getURL(`/static/wallet.html#${page}`),
});
return null;
}
diff --git a/packages/taler-wallet-webextension/src/renderHtml.tsx b/packages/taler-wallet-webextension/src/renderHtml.tsx
index ba98ae237..1e482ccea 100644
--- a/packages/taler-wallet-webextension/src/renderHtml.tsx
+++ b/packages/taler-wallet-webextension/src/renderHtml.tsx
@@ -167,7 +167,7 @@ export function PageLink(props: {
typeof chrome === "undefined"
? undefined
: // eslint-disable-next-line no-undef
- chrome.extension?.getURL(`/static/wallet.html#/${props.pageName}`);
+ chrome.runtime?.getURL(`/static/wallet.html#/${props.pageName}`);
return (
<a class="actionLink" href={url} target="_blank" rel="noopener noreferrer">
{props.children}
diff --git a/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts b/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts
new file mode 100644
index 000000000..6084ebae1
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts
@@ -0,0 +1,36 @@
+/*
+ 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/>
+ */
+
+/**
+ * API to access the Taler crypto worker thread.
+ * @author Florian Dold
+ */
+
+import {
+ CryptoWorker,
+ CryptoWorkerFactory,
+ SynchronousCryptoWorker,
+} from "@gnu-taler/taler-wallet-core";
+
+export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
+ startWorker(): CryptoWorker {
+ return new SynchronousCryptoWorker();
+ }
+
+ getConcurrency(): number {
+ return 1;
+ }
+}
diff --git a/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts b/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts
new file mode 100644
index 000000000..f8953f73f
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts
@@ -0,0 +1,146 @@
+/*
+ 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/>
+ */
+
+/**
+ * Imports.
+ */
+import { Logger, TalerErrorCode } from "@gnu-taler/taler-util";
+import {
+ Headers, HttpRequestLibrary,
+ HttpRequestOptions,
+ HttpResponse,
+ OperationFailedError
+} from "@gnu-taler/taler-wallet-core";
+
+const logger = new Logger("browserHttpLib");
+
+/**
+ * An implementation of the [[HttpRequestLibrary]] using the
+ * browser's XMLHttpRequest.
+ */
+export class ServiceWorkerHttpLib implements HttpRequestLibrary {
+ async fetch(requestUrl: string, options?: HttpRequestOptions): Promise<HttpResponse> {
+ const requestMethod = options?.method ?? "GET";
+ const requestBody = options?.body;
+ const requestHeader = options?.headers;
+
+ const response = await fetch(requestUrl, {
+ headers: requestHeader,
+ body: requestBody,
+ method: requestMethod,
+ // timeout: options?.timeout
+ })
+
+ const headerMap = new Headers();
+ response.headers.forEach(addLineToMap(headerMap));
+
+ return {
+ headers: headerMap,
+ status: response.status,
+ requestMethod,
+ requestUrl,
+ json: makeJsonHandler(response, requestUrl),
+ text: makeTextHandler(response, requestUrl),
+ bytes: async () => (await response.blob()).arrayBuffer(),
+ }
+
+ }
+
+
+ get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
+ return this.fetch(url, {
+ method: "GET",
+ ...opt,
+ });
+ }
+
+ postJson(
+ url: string,
+ body: any,
+ opt?: HttpRequestOptions,
+ ): Promise<HttpResponse> {
+ return this.fetch(url, {
+ method: "POST",
+ body: JSON.stringify(body),
+ ...opt,
+ });
+ }
+
+ stop(): void {
+ // Nothing to do
+ }
+}
+
+function makeTextHandler(response: Response, requestUrl: string) {
+ return async function getJsonFromResponse(): Promise<any> {
+ let respText;
+ try {
+ respText = await response.text()
+ } catch (e) {
+ throw OperationFailedError.fromCode(
+ TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+ "Invalid JSON from HTTP response",
+ {
+ requestUrl,
+ httpStatusCode: response.status,
+ },
+ );
+ }
+ return respText
+ }
+}
+
+function makeJsonHandler(response: Response, requestUrl: string) {
+ return async function getJsonFromResponse(): Promise<any> {
+ let responseJson;
+ try {
+ responseJson = await response.json()
+ } catch (e) {
+ throw OperationFailedError.fromCode(
+ TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+ "Invalid JSON from HTTP response",
+ {
+ requestUrl,
+ httpStatusCode: response.status,
+ },
+ );
+ }
+ if (responseJson === null || typeof responseJson !== "object") {
+ throw OperationFailedError.fromCode(
+ TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
+ "Invalid JSON from HTTP response",
+ {
+ requestUrl,
+ httpStatusCode: response.status,
+ },
+ );
+ }
+ return responseJson
+ }
+}
+
+function addLineToMap(map: { set(k: string, v: string): void }) {
+ return (line: string) => {
+ const parts = line.split(": ");
+ const headerName = parts.shift();
+ if (!headerName) {
+ logger.warn("skipping invalid header");
+ return;
+ }
+ const value = parts.join(": ");
+ map.set(headerName, value);
+ }
+} \ No newline at end of file
diff --git a/packages/taler-wallet-webextension/src/utils/index.ts b/packages/taler-wallet-webextension/src/utils/index.ts
index 88f9bc4b3..55898d181 100644
--- a/packages/taler-wallet-webextension/src/utils/index.ts
+++ b/packages/taler-wallet-webextension/src/utils/index.ts
@@ -225,7 +225,7 @@ function makeExtensionUrlWithParams(
params?: { [name: string]: string | undefined },
): string {
// eslint-disable-next-line no-undef
- const innerUrl = new URL(chrome.extension.getURL("/" + url));
+ const innerUrl = new URL(chrome.runtime.getURL("/" + url));
if (params) {
const hParams = Object.keys(params)
.map((k) => `${k}=${params[k]}`)
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts
index 10889f781..412f33f12 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -23,18 +23,6 @@
/**
* Imports.
*/
-import { isFirefox, getPermissionsApi } from "./compat";
-import { extendedPermissions } from "./permissions";
-import {
- OpenedPromise,
- openPromise,
- openTalerDatabase,
- makeErrorDetails,
- deleteTalerDatabase,
- DbAccess,
- WalletStoresV1,
- Wallet,
-} from "@gnu-taler/taler-wallet-core";
import {
classifyTalerUri,
CoreApiResponse,
@@ -42,10 +30,19 @@ import {
NotificationType,
TalerErrorCode,
TalerUriType,
- WalletDiagnostics,
+ WalletDiagnostics
} from "@gnu-taler/taler-util";
-import { BrowserHttpLib } from "./browserHttpLib";
+import {
+ DbAccess, deleteTalerDatabase, makeErrorDetails, OpenedPromise,
+ openPromise,
+ openTalerDatabase, Wallet, WalletStoresV1
+} from "@gnu-taler/taler-wallet-core";
import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory";
+import { BrowserHttpLib } from "./browserHttpLib";
+import { getPermissionsApi, isFirefox } from "./compat";
+import { extendedPermissions } from "./permissions";
+import { SynchronousCryptoWorkerFactory } from "./serviceWorkerCryptoWorkerFactory.js";
+import { ServiceWorkerHttpLib } from "./serviceWorkerHttpLib";
/**
* Currently active wallet instance. Might be unloaded and
@@ -188,10 +185,10 @@ function getTab(tabId: number): Promise<chrome.tabs.Tab> {
});
}
-function setBadgeText(options: chrome.browserAction.BadgeTextDetails): void {
+function setBadgeText(options: chrome.action.BadgeTextDetails): void {
// not supported by all browsers ...
- if (chrome && chrome.browserAction && chrome.browserAction.setBadgeText) {
- chrome.browserAction.setBadgeText(options);
+ if (chrome && chrome.action && chrome.action.setBadgeText) {
+ chrome.action.setBadgeText(options);
} else {
console.warn("can't set badge text, not supported", options);
}
@@ -214,7 +211,7 @@ function makeSyncWalletRedirect(
oldUrl: string,
params?: { [name: string]: string | undefined },
): Record<string, unknown> {
- const innerUrl = new URL(chrome.extension.getURL(url));
+ const innerUrl = new URL(chrome.runtime.getURL(url));
if (params) {
const hParams = Object.keys(params)
.map((k) => `${k}=${params[k]}`)
@@ -256,12 +253,22 @@ async function reinitWallet(): Promise<void> {
walletInit.reject(e);
return;
}
- const http = new BrowserHttpLib();
+ let httpLib;
+ let cryptoWorker;
+
+ if (chrome.runtime.getManifest().manifest_version === 3) {
+ httpLib = new ServiceWorkerHttpLib()
+ cryptoWorker = new SynchronousCryptoWorkerFactory();
+ } else {
+ httpLib = new BrowserHttpLib()
+ cryptoWorker = new BrowserCryptoWorkerFactory()
+ }
+
console.log("setting wallet");
const wallet = await Wallet.create(
currentDatabase,
- http,
- new BrowserCryptoWorkerFactory(),
+ httpLib,
+ cryptoWorker,
);
try {
await wallet.handleCoreApiRequest("initWallet", "native-init", {});
@@ -284,7 +291,9 @@ async function reinitWallet(): Promise<void> {
console.log("error during wallet task loop", e);
});
// Useful for debugging in the background page.
- (window as any).talerWallet = wallet;
+ if (typeof window !== "undefined") {
+ (window as any).talerWallet = wallet;
+ }
currentWallet = wallet;
walletInit.resolve();
}
@@ -295,8 +304,8 @@ try {
chrome.runtime.onInstalled.addListener((details) => {
console.log("onInstalled with reason", details.reason);
if (details.reason === "install") {
- const url = chrome.extension.getURL("/static/wallet.html#/welcome");
- chrome.tabs.create({ active: true, url: url });
+ const url = chrome.runtime.getURL("/static/wallet.html#/welcome");
+ chrome.tabs.create({ active: true, url });
}
});
} catch (e) {
@@ -387,6 +396,10 @@ function headerListener(
}
function setupHeaderListener(): void {
+ if (chrome.runtime.getManifest().manifest_version === 3) {
+ console.error("cannot block request on manfest v3")
+ return
+ }
console.log("setting up header listener");
// Handlers for catching HTTP requests
getPermissionsApi().contains(extendedPermissions, (result: boolean) => {
@@ -427,12 +440,14 @@ export async function wxMain(): Promise<void> {
console.log("update available:", details);
chrome.runtime.reload();
});
- reinitWallet();
+ const afterWalletIsInitialized = reinitWallet();
// Handlers for messages coming directly from the content
// script on the page
chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {
- dispatch(req, sender, sendResponse);
+ afterWalletIsInitialized.then(() => {
+ dispatch(req, sender, sendResponse);
+ })
return true;
});
@@ -447,7 +462,9 @@ export async function wxMain(): Promise<void> {
});
try {
- setupHeaderListener();
+ if (chrome.runtime.getManifest().manifest_version === 2) {
+ setupHeaderListener();
+ }
} catch (e) {
console.log(e);
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 33b57d498..c39313437 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -338,7 +338,7 @@ importers:
'@storybook/preact': 6.4.9
'@testing-library/preact': ^2.0.1
'@testing-library/preact-hooks': ^1.1.0
- '@types/chrome': ^0.0.174
+ '@types/chrome': 0.0.176
'@types/history': ^4.7.8
'@types/mocha': ^9.0.0
'@types/node': ^17.0.8
@@ -393,7 +393,7 @@ importers:
'@storybook/preact': 6.4.9_7ac135b2eab8a45315147b85be8cb430
'@testing-library/preact': 2.0.1_preact@10.5.14
'@testing-library/preact-hooks': 1.1.0_6273b572ba1ed58b8bbb2ee93959f9e4
- '@types/chrome': 0.0.174
+ '@types/chrome': 0.0.176
'@types/history': 4.7.9
'@types/mocha': 9.0.0
'@types/node': 17.0.8
@@ -9654,8 +9654,8 @@ packages:
'@types/node': 17.0.8
dev: true
- /@types/chrome/0.0.174:
- resolution: {integrity: sha512-x5kjvNdwDtOnT+vbnksj69pDl0u9P/WH9LbQWJawLqGgkBRO3AN/xzTxTPgLpp3IqCbuwfp7bRCHqkkaZguzWw==}
+ /@types/chrome/0.0.176:
+ resolution: {integrity: sha512-LOveFOMIUhMJjvRzZv5whGBpncP/gdJ4hcxeAqg94wGi6CyKaCmLgFSofgItf85GuLTl/0BQ6J/Y1e8BqZWfEg==}
dependencies:
'@types/filesystem': 0.0.32
'@types/har-format': 1.2.8