splitting syncWorker with the factory so the former do not require nodejs runtime
This commit is contained in:
parent
8b0294ee41
commit
bf0cb6ab13
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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";
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user