diff options
Diffstat (limited to 'packages')
5 files changed, 12 insertions, 451 deletions
diff --git a/packages/merchant-backoffice-ui/src/hooks/testing.tsx b/packages/merchant-backoffice-ui/src/hooks/testing.tsx index 67831f8a4..132c5f166 100644 --- a/packages/merchant-backoffice-ui/src/hooks/testing.tsx +++ b/packages/merchant-backoffice-ui/src/hooks/testing.tsx @@ -71,16 +71,19 @@ export class ApiMockEnvironment extends MockEnvironment { request: options.data, }, ); + const status = mocked.expectedQuery?.query.code ?? 200; + const requestPayload = mocked.expectedQuery?.params?.request; + const responsePayload = mocked.expectedQuery?.params?.response; return { ok: true, - data: (!mocked ? undefined : mocked.payload) as T, + data: responsePayload as T, loading: false, clientError: false, serverError: false, info: { hasToken: !!options.token, - status: !mocked ? 200 : mocked.status, + status, url: _url.href, payload: options.data, options: {}, diff --git a/packages/taler-wallet-webextension/src/browserHttpLib.ts b/packages/taler-wallet-webextension/src/browserHttpLib.ts deleted file mode 100644 index 2b6ca019c..000000000 --- a/packages/taler-wallet-webextension/src/browserHttpLib.ts +++ /dev/null @@ -1,203 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 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, - RequestThrottler, - TalerErrorCode, - TalerError, -} from "@gnu-taler/taler-util"; - -import { - HttpRequestLibrary, - HttpRequestOptions, - HttpResponse, - Headers, -} from "@gnu-taler/taler-util/http"; - -const logger = new Logger("browserHttpLib"); - -/** - * An implementation of the [[HttpRequestLibrary]] using the - * browser's XMLHttpRequest. - */ -export class BrowserHttpLib implements HttpRequestLibrary { - private throttle = new RequestThrottler(); - private throttlingEnabled = true; - - fetch( - requestUrl: string, - options?: HttpRequestOptions, - ): Promise<HttpResponse> { - const requestMethod = options?.method ?? "GET"; - const requestBody = options?.body; - - if (this.throttlingEnabled && this.throttle.applyThrottle(requestUrl)) { - const parsedUrl = new URL(requestUrl); - throw TalerError.fromDetail( - TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED, - { - requestMethod, - requestUrl, - throttleStats: this.throttle.getThrottleStats(requestUrl), - }, - `request to origin ${parsedUrl.origin} was throttled`, - ); - } - - return new Promise<HttpResponse>((resolve, reject) => { - const myRequest = new XMLHttpRequest(); - myRequest.open(requestMethod, requestUrl); - if (options?.headers) { - for (const headerName in options.headers) { - myRequest.setRequestHeader(headerName, options.headers[headerName]); - } - } - myRequest.responseType = "arraybuffer"; - if (requestBody) { - if (requestBody instanceof ArrayBuffer) { - myRequest.send(requestBody); - } else if (ArrayBuffer.isView(requestBody)) { - myRequest.send(requestBody); - } else if (typeof requestBody === "string") { - myRequest.send(requestBody); - } else { - myRequest.send(JSON.stringify(requestBody)); - } - } else { - myRequest.send(); - } - - myRequest.onerror = (e) => { - logger.error("http request error"); - reject( - TalerError.fromDetail( - TalerErrorCode.WALLET_NETWORK_ERROR, - { - requestUrl, - requestMethod, - }, - "Could not make request", - ), - ); - }; - - myRequest.addEventListener("readystatechange", (e) => { - if (myRequest.readyState === XMLHttpRequest.DONE) { - if (myRequest.status === 0) { - const exc = TalerError.fromDetail( - TalerErrorCode.WALLET_NETWORK_ERROR, - { - requestUrl, - requestMethod, - }, - "HTTP request failed (status 0, maybe URI scheme was wrong?)", - ); - reject(exc); - return; - } - const makeText = async (): Promise<string> => { - const td = new TextDecoder(); - return td.decode(myRequest.response); - }; - const makeJson = async (): Promise<any> => { - let responseJson; - try { - const td = new TextDecoder(); - const responseString = td.decode(myRequest.response); - responseJson = JSON.parse(responseString); - } catch (e) { - throw TalerError.fromDetail( - TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, - { - requestUrl, - requestMethod, - httpStatusCode: myRequest.status, - }, - "Invalid JSON from HTTP response", - ); - } - if (responseJson === null || typeof responseJson !== "object") { - throw TalerError.fromDetail( - TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, - { - requestUrl, - requestMethod, - httpStatusCode: myRequest.status, - }, - "Invalid JSON from HTTP response", - ); - } - return responseJson; - }; - - const headers = myRequest.getAllResponseHeaders(); - const arr = headers.trim().split(/[\r\n]+/); - - // Create a map of header names to values - const headerMap: Headers = new Headers(); - arr.forEach(function (line) { - const parts = line.split(": "); - const headerName = parts.shift(); - if (!headerName) { - logger.warn("skipping invalid header"); - return; - } - const value = parts.join(": "); - headerMap.set(headerName, value); - }); - const resp: HttpResponse = { - requestUrl: requestUrl, - status: myRequest.status, - headers: headerMap, - requestMethod: requestMethod, - json: makeJson, - text: makeText, - bytes: async () => myRequest.response, - }; - resolve(resp); - } - }); - }); - } - - 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", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(body), - ...opt, - }); - } - - stop(): void { - // Nothing to do - } -} diff --git a/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts b/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts deleted file mode 100644 index 4ee572435..000000000 --- a/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 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/> - */ - -/** - * API to access the Taler crypto worker thread. - * @author Florian Dold - */ - -import { - CryptoWorker, - CryptoWorkerFactory, - SynchronousCryptoWorkerPlain, -} from "@gnu-taler/taler-wallet-core"; - -export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory { - startWorker(): CryptoWorker { - return new SynchronousCryptoWorkerPlain(); - } - - getConcurrency(): number { - return 1; - } -} diff --git a/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts b/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts deleted file mode 100644 index 921acd63b..000000000 --- a/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts +++ /dev/null @@ -1,205 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 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 { - RequestThrottler, - TalerErrorCode, - TalerError, -} from "@gnu-taler/taler-util"; - -import { - Headers, - HttpRequestLibrary, - HttpRequestOptions, - HttpResponse, -} from "@gnu-taler/taler-util/http"; - -/** - * An implementation of the [[HttpRequestLibrary]] using the - * browser's XMLHttpRequest. - */ -export class ServiceWorkerHttpLib implements HttpRequestLibrary { - private throttle = new RequestThrottler(); - private throttlingEnabled = true; - - async fetch( - requestUrl: string, - options?: HttpRequestOptions, - ): Promise<HttpResponse> { - const requestMethod = options?.method ?? "GET"; - const requestBody = options?.body; - const requestHeader = options?.headers; - const requestTimeout = options?.timeout ?? { d_ms: 2 * 1000 }; - - if (this.throttlingEnabled && this.throttle.applyThrottle(requestUrl)) { - const parsedUrl = new URL(requestUrl); - throw TalerError.fromDetail( - TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED, - { - requestMethod, - requestUrl, - throttleStats: this.throttle.getThrottleStats(requestUrl), - }, - `request to origin ${parsedUrl.origin} was throttled`, - ); - } - - let myBody: BodyInit | undefined = undefined; - if (requestBody != null) { - if (typeof requestBody === "string") { - myBody = requestBody; - } else if (requestBody instanceof ArrayBuffer) { - myBody = requestBody; - } else if (ArrayBuffer.isView(requestBody)) { - myBody = requestBody; - } else if (typeof requestBody === "object") { - myBody = JSON.stringify(requestBody); - } else { - throw Error("unsupported request body type"); - } - } - - const controller = new AbortController(); - let timeoutId: any | undefined; - if (requestTimeout.d_ms !== "forever") { - timeoutId = setTimeout(() => { - controller.abort(TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT); - }, requestTimeout.d_ms); - } - - try { - const response = await fetch(requestUrl, { - headers: requestHeader, - body: myBody, - method: requestMethod, - signal: controller.signal, - }); - - if (timeoutId) { - clearTimeout(timeoutId); - } - - const headerMap = new Headers(); - response.headers.forEach((value, key) => { - headerMap.set(key, value); - }); - return { - headers: headerMap, - status: response.status, - requestMethod, - requestUrl, - json: makeJsonHandler(response, requestUrl, requestMethod), - text: makeTextHandler(response, requestUrl, requestMethod), - bytes: async () => (await response.blob()).arrayBuffer(), - }; - } catch (e) { - if (controller.signal) { - throw TalerError.fromDetail( - controller.signal.reason, - {}, - `request to ${requestUrl} timed out`, - ); - } - throw e; - } - } - - 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", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(body), - ...opt, - }); - } - - stop(): void { - // Nothing to do - } -} - -function makeTextHandler( - response: Response, - requestUrl: string, - requestMethod: string, -) { - return async function getJsonFromResponse(): Promise<any> { - let respText; - try { - respText = await response.text(); - } catch (e) { - throw TalerError.fromDetail( - TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, - { - requestUrl, - requestMethod, - httpStatusCode: response.status, - }, - "Invalid JSON from HTTP response", - ); - } - return respText; - }; -} - -function makeJsonHandler( - response: Response, - requestUrl: string, - requestMethod: string, -) { - return async function getJsonFromResponse(): Promise<any> { - let responseJson; - try { - responseJson = await response.json(); - } catch (e) { - throw TalerError.fromDetail( - TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, - { - requestUrl, - requestMethod, - httpStatusCode: response.status, - }, - "Invalid JSON from HTTP response", - ); - } - if (responseJson === null || typeof responseJson !== "object") { - throw TalerError.fromDetail( - TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, - { - requestUrl, - requestMethod, - httpStatusCode: response.status, - }, - "Invalid JSON from HTTP response", - ); - } - return responseJson; - }; -} diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts index 8acc41247..cc72fc9c9 100644 --- a/packages/taler-wallet-webextension/src/wxBackend.ts +++ b/packages/taler-wallet-webextension/src/wxBackend.ts @@ -34,9 +34,14 @@ import { setLogLevelFromString, } from "@gnu-taler/taler-util"; import { + ServiceWorkerHttpLib, + BrowserHttpLib, +} from "@gnu-taler/web-util/lib/index.browser"; +import { DbAccess, OpenedPromise, SetTimeoutTimerAPI, + SynchronousCryptoWorkerFactoryPlain, Wallet, WalletOperations, WalletStoresV1, @@ -46,15 +51,12 @@ import { openPromise, openTalerDatabase, } from "@gnu-taler/taler-wallet-core"; -import { BrowserHttpLib } from "./browserHttpLib.js"; import { MessageFromBackend, MessageFromFrontend, MessageResponse, } from "./platform/api.js"; import { platform } from "./platform/background.js"; -import { SynchronousCryptoWorkerFactory } from "./serviceWorkerCryptoWorkerFactory.js"; -import { ServiceWorkerHttpLib } from "./serviceWorkerHttpLib.js"; import { ExtensionOperations } from "./taler-wallet-interaction-loader.js"; import { BackgroundOperations } from "./wxApi.js"; @@ -308,14 +310,14 @@ async function reinitWallet(): Promise<void> { if (platform.useServiceWorkerAsBackgroundProcess()) { httpLib = new ServiceWorkerHttpLib(); - cryptoWorker = new SynchronousCryptoWorkerFactory(); + cryptoWorker = new SynchronousCryptoWorkerFactoryPlain(); timer = new SetTimeoutTimerAPI(); } else { httpLib = new BrowserHttpLib(); // We could (should?) use the BrowserCryptoWorkerFactory here, // but right now we don't, to have less platform differences. // cryptoWorker = new BrowserCryptoWorkerFactory(); - cryptoWorker = new SynchronousCryptoWorkerFactory(); + cryptoWorker = new SynchronousCryptoWorkerFactoryPlain(); timer = new SetTimeoutTimerAPI(); } |