splitting syncWorker with the factory so the former do not require nodejs runtime

This commit is contained in:
Sebastian 2022-01-16 17:33:21 -03:00
parent 8b0294ee41
commit bf0cb6ab13
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
4 changed files with 173 additions and 174 deletions

View File

@ -25,54 +25,24 @@
*/
// FIXME: Crypto should not use DB Types!
import { DenominationRecord, WireFee } from "../../db.js";
import {
buildSigPS,
CoinDepositPermission,
DenomKeyType,
ExchangeProtocolVersion,
FreshCoin,
hashDenomPub,
RecoupRefreshRequest,
AmountJson, Amounts, BenchmarkResult, buildSigPS,
CoinDepositPermission, createEddsaKeyPair, createHashContext, decodeCrock,
DenomKeyType, DepositInfo, eddsaGetPublic, eddsaSign, eddsaVerify,
encodeCrock, ExchangeProtocolVersion,
FreshCoin, hash, hashDenomPub, kdf, keyExchangeEcdheEddsa,
// Logger,
MakeSyncSignatureRequest, PlanchetCreationRequest, PlanchetCreationResult,
randomBytes, RecoupRefreshRequest,
RecoupRequest,
RefreshPlanchetInfo,
TalerSignaturePurpose,
} from "@gnu-taler/taler-util";
// FIXME: These types should be internal to the wallet!
import {
BenchmarkResult,
PlanchetCreationResult,
PlanchetCreationRequest,
DepositInfo,
MakeSyncSignatureRequest,
} from "@gnu-taler/taler-util";
import { AmountJson, Amounts } from "@gnu-taler/taler-util";
import * as timer from "../../util/timer.js";
import {
encodeCrock,
decodeCrock,
createEddsaKeyPair,
hash,
rsaBlind,
eddsaVerify,
eddsaSign,
rsaUnblind,
stringToBytes,
createHashContext,
keyExchangeEcdheEddsa,
setupRefreshPlanchet,
rsaVerify,
RefreshPlanchetInfo, rsaBlind, rsaUnblind, rsaVerify, setupRefreshPlanchet,
setupRefreshTransferPub,
setupTipPlanchet,
setupWithdrawPlanchet,
eddsaGetPublic,
setupWithdrawPlanchet, stringToBytes, TalerSignaturePurpose, Timestamp, timestampTruncateToSecond
} from "@gnu-taler/taler-util";
import { randomBytes } from "@gnu-taler/taler-util";
import { kdf } from "@gnu-taler/taler-util";
import { Timestamp, timestampTruncateToSecond } from "@gnu-taler/taler-util";
import { Logger } from "@gnu-taler/taler-util";
import bigint from "big-integer";
import { DenominationRecord, WireFee } from "../../db.js";
import * as timer from "../../util/timer.js";
import {
CreateRecoupRefreshReqRequest,
CreateRecoupReqRequest,
@ -80,11 +50,10 @@ import {
DerivedTipPlanchet,
DeriveRefreshSessionRequest,
DeriveTipRequest,
SignTrackTransactionRequest,
SignTrackTransactionRequest
} from "../cryptoTypes.js";
import bigint from "big-integer";
const logger = new Logger("cryptoImplementation.ts");
// const logger = new Logger("cryptoImplementation.ts");
function amountToBuffer(amount: AmountJson): Uint8Array {
const buffer = new ArrayBuffer(8 + 4 + 12);
@ -161,7 +130,7 @@ async function myEddsaSign(
export class CryptoImplementation {
static enableTracing = false;
constructor(private primitiveWorker?: PrimitiveWorker) {}
constructor(private primitiveWorker?: PrimitiveWorker) { }
/**
* Create a pre-coin of the given denomination to be withdrawn from then given

View File

@ -14,135 +14,16 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { Logger } from "@gnu-taler/taler-util";
import {
CryptoImplementation,
PrimitiveWorker,
PrimitiveWorker
} from "./cryptoImplementation.js";
import { CryptoWorkerFactory } from "./cryptoApi.js";
import { CryptoWorker } from "./cryptoWorkerInterface.js";
import child_process from "child_process";
import type internal from "stream";
import { OpenedPromise, openPromise } from "../../index.js";
import { j2s, Logger } from "@gnu-taler/taler-util";
const logger = new Logger("synchronousWorker.ts");
class MyPrimitiveWorker implements PrimitiveWorker {
proc: child_process.ChildProcessByStdio<
internal.Writable,
internal.Readable,
null
>;
requests: Array<{
p: OpenedPromise<any>;
req: any;
}> = [];
constructor() {
const stdoutChunks: Buffer[] = [];
this.proc = child_process.spawn("taler-crypto-worker", {
//stdio: ["pipe", "pipe", "inherit"],
stdio: ["pipe", "pipe", "inherit"],
detached: true,
});
this.proc.on("close", function (code) {
logger.error("child process exited");
});
(this.proc.stdout as any).unref();
(this.proc.stdin as any).unref();
this.proc.unref();
this.proc.stdout.on("data", (x) => {
// console.log("got chunk", x.toString("utf-8"));
if (x instanceof Buffer) {
const nlIndex = x.indexOf("\n");
if (nlIndex >= 0) {
const before = x.slice(0, nlIndex);
const after = x.slice(nlIndex + 1);
stdoutChunks.push(after);
const str = Buffer.concat([...stdoutChunks, before]).toString(
"utf-8",
);
const req = this.requests.shift()!;
if (this.requests.length === 0) {
this.proc.unref();
}
//logger.info(`got response: ${str}`);
req.p.resolve(JSON.parse(str));
} else {
stdoutChunks.push(x);
}
} else {
throw Error(`unexpected data chunk type (${typeof x})`);
}
});
}
async setupRefreshPlanchet(req: {
transfer_secret: string;
coin_index: number;
}): Promise<{
coin_pub: string;
coin_priv: string;
blinding_key: string;
}> {
return this.queueRequest({
op: "setup_refresh_planchet",
args: req,
});
}
async queueRequest(req: any): Promise<any> {
const p = openPromise<any>();
if (this.requests.length === 0) {
this.proc.ref();
}
this.requests.push({ req, p });
this.proc.stdin.write(JSON.stringify(req) + "\n");
return p.promise;
}
async eddsaVerify(req: {
msg: string;
sig: string;
pub: string;
}): Promise<{ valid: boolean }> {
return this.queueRequest({
op: "eddsa_verify",
args: req,
});
}
async eddsaSign(req: {
msg: string;
priv: string;
}): Promise<{ sig: string }> {
return this.queueRequest({
op: "eddsa_sign",
args: req,
});
}
}
/**
* The synchronous crypto worker produced by this factory doesn't run in the
* background, but actually blocks the caller until the operation is done.
*/
export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
startWorker(): CryptoWorker {
if (typeof require === "undefined") {
throw Error("cannot make worker, require(...) not defined");
}
return new SynchronousCryptoWorker();
}
getConcurrency(): number {
return 1;
}
}
/**
* Worker implementation that uses node subprocesses.
*/
@ -157,14 +38,9 @@ export class SynchronousCryptoWorker {
*/
onerror: undefined | ((m: any) => void);
primitiveWorker: PrimitiveWorker;
constructor() {
constructor(private primitiveWorker?: PrimitiveWorker) {
this.onerror = undefined;
this.onmessage = undefined;
if (process.env["TALER_WALLET_PRIMITIVE_WORKER"]) {
this.primitiveWorker = new MyPrimitiveWorker();
}
}
/**

View File

@ -0,0 +1,153 @@
/*
This file is part of GNU Taler
(C) 2019 GNUnet e.V.
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/>
*/
import {
PrimitiveWorker,
} from "./cryptoImplementation.js";
import { CryptoWorkerFactory } from "./cryptoApi.js";
import { CryptoWorker } from "./cryptoWorkerInterface.js";
import child_process from "child_process";
import type internal from "stream";
import { OpenedPromise, openPromise } from "../../index.js";
import { Logger } from "@gnu-taler/taler-util";
import { SynchronousCryptoWorker } from "./synchronousWorker.js";
const logger = new Logger("synchronousWorkerFactory.ts");
class MyPrimitiveWorker implements PrimitiveWorker {
proc: child_process.ChildProcessByStdio<
internal.Writable,
internal.Readable,
null
>;
requests: Array<{
p: OpenedPromise<any>;
req: any;
}> = [];
constructor() {
const stdoutChunks: Buffer[] = [];
this.proc = child_process.spawn("taler-crypto-worker", {
//stdio: ["pipe", "pipe", "inherit"],
stdio: ["pipe", "pipe", "inherit"],
detached: true,
});
this.proc.on("close", (): void => {
logger.error("child process exited");
});
(this.proc.stdout as any).unref();
(this.proc.stdin as any).unref();
this.proc.unref();
this.proc.stdout.on("data", (x) => {
// console.log("got chunk", x.toString("utf-8"));
if (x instanceof Buffer) {
const nlIndex = x.indexOf("\n");
if (nlIndex >= 0) {
const before = x.slice(0, nlIndex);
const after = x.slice(nlIndex + 1);
stdoutChunks.push(after);
const str = Buffer.concat([...stdoutChunks, before]).toString(
"utf-8",
);
const req = this.requests.shift();
if (!req) {
throw Error("request was undefined")
}
if (this.requests.length === 0) {
this.proc.unref();
}
//logger.info(`got response: ${str}`);
req.p.resolve(JSON.parse(str));
} else {
stdoutChunks.push(x);
}
} else {
throw Error(`unexpected data chunk type (${typeof x})`);
}
});
}
async setupRefreshPlanchet(req: {
transfer_secret: string;
coin_index: number;
}): Promise<{
coin_pub: string;
coin_priv: string;
blinding_key: string;
}> {
return this.queueRequest({
op: "setup_refresh_planchet",
args: req,
});
}
async queueRequest(req: any): Promise<any> {
const p = openPromise<any>();
if (this.requests.length === 0) {
this.proc.ref();
}
this.requests.push({ req, p });
this.proc.stdin.write(`${JSON.stringify(req)}\n`);
return p.promise;
}
async eddsaVerify(req: {
msg: string;
sig: string;
pub: string;
}): Promise<{ valid: boolean }> {
return this.queueRequest({
op: "eddsa_verify",
args: req,
});
}
async eddsaSign(req: {
msg: string;
priv: string;
}): Promise<{ sig: string }> {
return this.queueRequest({
op: "eddsa_sign",
args: req,
});
}
}
/**
* The synchronous crypto worker produced by this factory doesn't run in the
* background, but actually blocks the caller until the operation is done.
*/
export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
startWorker(): CryptoWorker {
if (typeof require === "undefined") {
throw Error("cannot make worker, require(...) not defined");
}
let primitiveWorker;
if (process.env["TALER_WALLET_PRIMITIVE_WORKER"]) {
primitiveWorker = new MyPrimitiveWorker();
}
return new SynchronousCryptoWorker(primitiveWorker);
}
getConcurrency(): number {
return 1;
}
}

View File

@ -36,6 +36,7 @@ export * from "./db-utils.js";
export { CryptoImplementation } from "./crypto/workers/cryptoImplementation.js";
export type { CryptoWorker } from "./crypto/workers/cryptoWorkerInterface.js";
export { CryptoWorkerFactory, CryptoApi } from "./crypto/workers/cryptoApi.js";
export { SynchronousCryptoWorker } from "./crypto/workers/synchronousWorker.js"
export * from "./pending-types.js";