diff options
author | Florian Dold <florian@dold.me> | 2022-10-05 12:52:49 +0200 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2022-10-05 12:52:49 +0200 |
commit | dd14e67c70cd7b5b6891295759cb08aa2f94f180 (patch) | |
tree | 296b07938b676d21ba9f75196cae621e292fc714 /packages/taler-wallet-core/src/crypto | |
parent | 4d232fd56510ae69b76fef4f4ecade1e0d4b230d (diff) | |
download | wallet-core-dd14e67c70cd7b5b6891295759cb08aa2f94f180.tar.xz |
wallet-core: improve crypto worker code duplication
Also add new testCrypto call for later testing
Diffstat (limited to 'packages/taler-wallet-core/src/crypto')
6 files changed, 113 insertions, 164 deletions
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoDispatcher.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoDispatcher.ts index 8568f0db8..85f9acddc 100644 --- a/packages/taler-wallet-core/src/crypto/workers/cryptoDispatcher.ts +++ b/packages/taler-wallet-core/src/crypto/workers/cryptoDispatcher.ts @@ -29,7 +29,7 @@ import { timer, performanceNow, TimerHandle } from "../../util/timer.js"; import { nullCrypto, TalerCryptoInterface } from "../cryptoImplementation.js"; import { CryptoWorker } from "./cryptoWorkerInterface.js"; -const logger = new Logger("cryptoApi.ts"); +const logger = new Logger("cryptoDispatcher.ts"); /** * State of a crypto worker. @@ -238,7 +238,7 @@ export class CryptoDispatcher { } handleWorkerMessage(ws: WorkerInfo, msg: any): void { - const id = msg.data.id; + const id = msg.id; if (typeof id !== "number") { logger.error("rpc id must be number"); return; @@ -256,12 +256,12 @@ export class CryptoDispatcher { if (currentWorkItem.state === WorkItemState.Running) { this.numBusy--; currentWorkItem.state = WorkItemState.Finished; - if (msg.data.type === "success") { - currentWorkItem.resolve(msg.data.result); - } else if (msg.data.type === "error") { + if (msg.type === "success") { + currentWorkItem.resolve(msg.result); + } else if (msg.type === "error") { currentWorkItem.reject( TalerError.fromDetail(TalerErrorCode.WALLET_CRYPTO_WORKER_ERROR, { - innerError: msg.data.error, + innerError: msg.error, }), ); } else { diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoWorkerInterface.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoWorkerInterface.ts index 9f3ee6f50..b3620e950 100644 --- a/packages/taler-wallet-core/src/crypto/workers/cryptoWorkerInterface.ts +++ b/packages/taler-wallet-core/src/crypto/workers/cryptoWorkerInterface.ts @@ -1,8 +1,65 @@ +/* + 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 { TalerErrorDetail } from "@gnu-taler/taler-util"; + +/** + * Common interface for all crypto workers. + */ export interface CryptoWorker { postMessage(message: any): void; - terminate(): void; - onmessage: ((m: any) => void) | undefined; onerror: ((m: any) => void) | undefined; } + +/** + * Type of requests sent to the crypto worker. + */ +export type CryptoWorkerRequestMessage = { + /** + * Operation ID to correlate request with the response. + */ + id: number; + + /** + * Operation to execute. + */ + operation: string; + + /** + * Operation-specific request payload. + */ + req: any; +}; + +/** + * Type of messages sent back by the crypto worker. + */ +export type CryptoWorkerResponseMessage = + | { + type: "success"; + id: number; + result: any; + } + | { + type: "error"; + id?: number; + error: TalerErrorDetail; + }; diff --git a/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts b/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts index 71f137f29..ed67d2e95 100644 --- a/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts +++ b/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts @@ -17,12 +17,12 @@ /** * Imports */ -import { CryptoWorkerFactory } from "./cryptoDispatcher.js"; -import { CryptoWorker } from "./cryptoWorkerInterface.js"; -import os from "os"; import { Logger } from "@gnu-taler/taler-util"; +import os from "os"; import { nativeCryptoR } from "../cryptoImplementation.js"; -import { getErrorDetailFromException } from "../../errors.js"; +import { CryptoWorkerFactory } from "./cryptoDispatcher.js"; +import { CryptoWorker } from "./cryptoWorkerInterface.js"; +import { processRequestWithImpl } from "./worker-common.js"; const logger = new Logger("nodeThreadWorker.ts"); @@ -71,44 +71,7 @@ const workerCode = ` */ export function handleWorkerMessage(msg: any): void { const handleRequest = async (): Promise<void> => { - const req = msg.req; - if (typeof req !== "object") { - logger.error("request must be an object"); - return; - } - const id = msg.id; - if (typeof id !== "number") { - logger.error("RPC id must be number"); - return; - } - const operation = msg.operation; - if (typeof operation !== "string") { - logger.error("RPC operation must be string"); - return; - } - const impl = nativeCryptoR; - - if (!(operation in impl)) { - logger.error(`crypto operation '${operation}' not found`); - return; - } - - let responseMsg: any; - - try { - const result = await (impl as any)[operation](impl, req); - responseMsg = { data: { type: "success", result, id } }; - } catch (e: any) { - logger.error(`error during operation: ${e.stack ?? e.toString()}`); - responseMsg = { - data: { - type: "error", - error: getErrorDetailFromException(e), - id, - }, - }; - } - + const responseMsg = await processRequestWithImpl(msg, nativeCryptoR); try { // eslint-disable-next-line @typescript-eslint/no-var-requires const _r = "require"; @@ -122,16 +85,12 @@ export function handleWorkerMessage(msg: any): void { logger.error("parent port not available (not running in thread?"); } } catch (e: any) { - logger.error( - `error sending back operation result: ${e.stack ?? e.toString()}`, - ); + logger.error(`error in node worker: ${e.stack ?? e.toString()}`); return; } }; - handleRequest().catch((e) => { - logger.error("error in node worker", e); - }); + handleRequest(); } export function handleWorkerError(e: Error): void { diff --git a/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts b/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts index a8df8b4c6..f3a4fff1c 100644 --- a/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts +++ b/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts @@ -24,6 +24,9 @@ import { OpenedPromise, openPromise } from "../../util/promiseUtils.js"; const logger = new Logger("synchronousWorkerFactory.ts"); +/** + * Client for the crypto helper process (taler-crypto-worker from exchange.git). + */ export class CryptoRpcClient { proc: child_process.ChildProcessByStdio< internal.Writable, diff --git a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts b/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts index f3cfc5ef9..28ff1860b 100644 --- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts +++ b/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts @@ -14,20 +14,24 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { Logger } from "@gnu-taler/taler-util"; -import { getErrorDetailFromException } from "../../errors.js"; +import { j2s, Logger } from "@gnu-taler/taler-util"; import { nativeCryptoR, TalerCryptoInterfaceR, } from "../cryptoImplementation.js"; +import { CryptoWorker } from "./cryptoWorkerInterface.js"; import { CryptoRpcClient } from "./rpcClient.js"; +import { processRequestWithImpl } from "./worker-common.js"; const logger = new Logger("synchronousWorker.ts"); /** * Worker implementation that uses node subprocesses. + * + * The node cryto worker can also use IPC to offload cryptographic + * operations to a helper process (ususally written in C / part of taler-exchange). */ -export class SynchronousCryptoWorker { +export class SynchronousCryptoWorker implements CryptoWorker { /** * Function to be called when we receive a message from the worker thread. */ @@ -144,61 +148,19 @@ export class SynchronousCryptoWorker { } } - private async handleRequest( - operation: string, - id: number, - req: unknown, - ): Promise<void> { - const impl = this.cryptoImplR; - - if (!(operation in impl)) { - logger.error(`crypto operation '${operation}' not found`); - return; - } - - let responseMsg: any; - try { - const result = await (impl as any)[operation](impl, req); - responseMsg = { data: { type: "success", result, id } }; - } catch (e: any) { - logger.error(`error during operation: ${e.stack ?? e.toString()}`); - responseMsg = { - data: { - type: "error", - id, - error: getErrorDetailFromException(e), - }, - }; - } - - try { - setTimeout(() => this.dispatchMessage(responseMsg), 0); - } catch (e) { - logger.error("got error during dispatch", e); - } - } - /** * Send a message to the worker thread. */ postMessage(msg: any): void { - const req = msg.req; - if (typeof req !== "object") { - logger.error("request must be an object"); - return; - } - const id = msg.id; - if (typeof id !== "number") { - logger.error("RPC id must be number"); - return; - } - const operation = msg.operation; - if (typeof operation !== "string") { - logger.error("RPC operation must be string"); - return; - } - - this.handleRequest(operation, id, req).catch((e) => { + const handleRequest = async () => { + const responseMsg = await processRequestWithImpl(msg, this.cryptoImplR); + try { + setTimeout(() => this.dispatchMessage(responseMsg), 0); + } catch (e) { + logger.error("got error during dispatch", e); + } + }; + handleRequest().catch((e) => { logger.error("Error while handling crypto request:", e); }); } diff --git a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerWeb.ts b/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerWeb.ts index 22fd0d96b..780f6c634 100644 --- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerWeb.ts +++ b/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerWeb.ts @@ -14,19 +14,26 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ +/** + * Imports. + */ import { Logger } from "@gnu-taler/taler-util"; -import { getErrorDetailFromException } from "../../errors.js"; import { nativeCryptoR, TalerCryptoInterfaceR, } from "../cryptoImplementation.js"; +import { CryptoWorker } from "./cryptoWorkerInterface.js"; +import { + processRequestWithImpl, +} from "./worker-common.js"; const logger = new Logger("synchronousWorker.ts"); /** - * Worker implementation that uses node subprocesses. + * Worker implementation that synchronously executes cryptographic + * operations. */ -export class SynchronousCryptoWorker { +export class SynchronousCryptoWorker implements CryptoWorker { /** * Function to be called when we receive a message from the worker thread. */ @@ -65,61 +72,22 @@ export class SynchronousCryptoWorker { } } - private async handleRequest( - operation: string, - id: number, - req: unknown, - ): Promise<void> { - const impl = this.cryptoImplR; - - if (!(operation in impl)) { - logger.error(`crypto operation '${operation}' not found`); - return; - } - - let responseMsg: any; - try { - const result = await (impl as any)[operation](impl, req); - responseMsg = { data: { type: "success", result, id } }; - } catch (e: any) { - logger.error(`error during operation: ${e.stack ?? e.toString()}`); - responseMsg = { - data: { - type: "error", - id, - error: getErrorDetailFromException(e), - }, - }; - } - - try { - setTimeout(() => this.dispatchMessage(responseMsg), 0); - } catch (e) { - logger.error("got error during dispatch", e); - } - } - /** * Send a message to the worker thread. */ postMessage(msg: any): void { - const req = msg.req; - if (typeof req !== "object") { - logger.error("request must be an object"); - return; - } - const id = msg.id; - if (typeof id !== "number") { - logger.error("RPC id must be number"); - return; - } - const operation = msg.operation; - if (typeof operation !== "string") { - logger.error("RPC operation must be string"); - return; - } - - this.handleRequest(operation, id, req).catch((e) => { + const handleRequest = async () => { + const responseMsg = await processRequestWithImpl( + msg, + this.cryptoImplR, + ); + try { + setTimeout(() => this.dispatchMessage(responseMsg), 0); + } catch (e) { + logger.error("got error during dispatch", e); + } + }; + handleRequest().catch((e) => { logger.error("Error while handling crypto request:", e); }); } |