blockintel-gate-sdk 0.3.7 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -5,7 +5,9 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var crypto = require('crypto');
6
6
  var uuid = require('uuid');
7
7
  var clientKms = require('@aws-sdk/client-kms');
8
+ var module$1 = require('module');
8
9
 
10
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
9
11
  var __defProp = Object.defineProperty;
10
12
  var __getOwnPropNames = Object.getOwnPropertyNames;
11
13
  var __esm = (fn, res) => function __init() {
@@ -50,6 +52,55 @@ var init_canonicalJson = __esm({
50
52
  "src/utils/canonicalJson.ts"() {
51
53
  }
52
54
  });
55
+
56
+ // src/utils/decisionTokenVerify.ts
57
+ var decisionTokenVerify_exports = {};
58
+ __export(decisionTokenVerify_exports, {
59
+ decodeJwtUnsafe: () => decodeJwtUnsafe,
60
+ verifyDecisionTokenRs256: () => verifyDecisionTokenRs256
61
+ });
62
+ function decodeJwtUnsafe(token) {
63
+ try {
64
+ const parts = token.split(".");
65
+ if (parts.length !== 3) return null;
66
+ const header = JSON.parse(
67
+ Buffer.from(parts[0], "base64url").toString("utf8")
68
+ );
69
+ const payload = JSON.parse(
70
+ Buffer.from(parts[1], "base64url").toString("utf8")
71
+ );
72
+ return { header, payload };
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+ function verifyDecisionTokenRs256(token, publicKeyPem) {
78
+ const decoded = decodeJwtUnsafe(token);
79
+ if (!decoded || (decoded.header.alg || "").toUpperCase() !== "RS256") return null;
80
+ const { payload } = decoded;
81
+ const now = Math.floor(Date.now() / 1e3);
82
+ if (payload.iss !== ISS || payload.aud !== AUD) return null;
83
+ if (payload.exp != null && payload.exp < now - 5) return null;
84
+ try {
85
+ const parts = token.split(".");
86
+ const signingInput = `${parts[0]}.${parts[1]}`;
87
+ const signature = Buffer.from(parts[2], "base64url");
88
+ const verify = crypto.createVerify("RSA-SHA256");
89
+ verify.update(signingInput);
90
+ verify.end();
91
+ const ok = verify.verify(publicKeyPem, signature);
92
+ return ok ? payload : null;
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+ var ISS, AUD;
98
+ var init_decisionTokenVerify = __esm({
99
+ "src/utils/decisionTokenVerify.ts"() {
100
+ ISS = "blockintel-gate";
101
+ AUD = "gate-decision";
102
+ }
103
+ });
53
104
  async function hmacSha256(secret, message) {
54
105
  const hmac = crypto.createHmac("sha256", secret);
55
106
  hmac.update(message, "utf8");
@@ -869,6 +920,12 @@ var MetricsCollector = class {
869
920
  this.circuitBreakerOpenTotal++;
870
921
  this.emitMetrics();
871
922
  }
923
+ /**
924
+ * Record soft-enforce override (app chose to sign despite BLOCK decision)
925
+ */
926
+ recordSoftBlockOverride(decision) {
927
+ this.emitMetrics();
928
+ }
872
929
  /**
873
930
  * Get current metrics snapshot
874
931
  */
@@ -922,6 +979,75 @@ var MetricsCollector = class {
922
979
  this.latencyMs = [];
923
980
  }
924
981
  };
982
+ function canonicalJsonBinding(obj) {
983
+ if (obj === null || obj === void 0) return "null";
984
+ if (typeof obj === "string") return JSON.stringify(obj);
985
+ if (typeof obj === "number") return obj.toString();
986
+ if (typeof obj === "boolean") return obj ? "true" : "false";
987
+ if (Array.isArray(obj)) {
988
+ const items = obj.map((item) => canonicalJsonBinding(item));
989
+ return "[" + items.join(",") + "]";
990
+ }
991
+ if (typeof obj === "object") {
992
+ const keys = Object.keys(obj).sort();
993
+ const pairs = [];
994
+ for (const key of keys) {
995
+ const value = obj[key];
996
+ if (value !== void 0) {
997
+ pairs.push(JSON.stringify(key) + ":" + canonicalJsonBinding(value));
998
+ }
999
+ }
1000
+ return "{" + pairs.join(",") + "}";
1001
+ }
1002
+ return JSON.stringify(obj);
1003
+ }
1004
+ function normalizeAddress(addr) {
1005
+ if (addr == null || addr === "") return "";
1006
+ const s = String(addr).trim();
1007
+ if (s.startsWith("0x")) return s.toLowerCase();
1008
+ return "0x" + s.toLowerCase();
1009
+ }
1010
+ function normalizeData(data) {
1011
+ if (data == null || data === "") return "";
1012
+ const s = String(data).trim().toLowerCase();
1013
+ return s.startsWith("0x") ? s : "0x" + s;
1014
+ }
1015
+ function buildTxBindingObject(txIntent, signerId, decodedRecipient, decodedFields, fromAddress) {
1016
+ const toAddr = txIntent.toAddress ?? txIntent.to ?? "";
1017
+ const value = (txIntent.valueAtomic ?? txIntent.valueDecimal ?? txIntent.value ?? "0").toString();
1018
+ const data = normalizeData(
1019
+ txIntent.data ?? txIntent.payloadHash ?? txIntent.dataHash ?? ""
1020
+ );
1021
+ const chainId = (txIntent.chainId ?? txIntent.chain ?? "").toString();
1022
+ const toAddress = normalizeAddress(toAddr);
1023
+ const nonce = txIntent.nonce != null ? String(txIntent.nonce) : "";
1024
+ const decoded = {};
1025
+ if (decodedFields && typeof decodedFields === "object") {
1026
+ for (const [k, v] of Object.entries(decodedFields)) {
1027
+ if (v !== void 0) decoded[k] = v;
1028
+ }
1029
+ }
1030
+ const out = {
1031
+ chainId,
1032
+ toAddress,
1033
+ value,
1034
+ data,
1035
+ nonce
1036
+ };
1037
+ if (fromAddress) out.fromAddress = normalizeAddress(fromAddress);
1038
+ if (decodedRecipient != null)
1039
+ out.decodedRecipient = decodedRecipient ? normalizeAddress(decodedRecipient) : null;
1040
+ if (Object.keys(decoded).length > 0) out.decoded = decoded;
1041
+ if (signerId) out.signerId = signerId;
1042
+ if (txIntent.networkFamily) out.networkFamily = txIntent.networkFamily;
1043
+ return out;
1044
+ }
1045
+ function computeTxDigest(binding) {
1046
+ const canonical = canonicalJsonBinding(binding);
1047
+ return crypto.createHash("sha256").update(canonical, "utf8").digest("hex");
1048
+ }
1049
+
1050
+ // src/kms/wrapAwsSdkV3KmsClient.ts
925
1051
  function wrapKmsClient(kmsClient, gateClient, options = {}) {
926
1052
  const defaultOptions = {
927
1053
  mode: options.mode || "enforce",
@@ -997,6 +1123,34 @@ async function handleSignCommand(command, originalClient, gateClient, options) {
997
1123
  // Type assertion - txIntent may have extra fields
998
1124
  signingContext
999
1125
  });
1126
+ if (decision.decision === "ALLOW" && gateClient.getRequireDecisionToken() && decision.txDigest != null) {
1127
+ const binding = buildTxBindingObject(
1128
+ txIntent,
1129
+ signerId,
1130
+ void 0,
1131
+ void 0,
1132
+ signingContext.actorPrincipal
1133
+ );
1134
+ const computedDigest = computeTxDigest(binding);
1135
+ if (computedDigest !== decision.txDigest) {
1136
+ options.onDecision("BLOCK", {
1137
+ error: new BlockIntelBlockedError(
1138
+ "DECISION_TOKEN_TX_MISMATCH",
1139
+ decision.decisionId,
1140
+ decision.correlationId,
1141
+ void 0
1142
+ ),
1143
+ signerId,
1144
+ command
1145
+ });
1146
+ throw new BlockIntelBlockedError(
1147
+ "DECISION_TOKEN_TX_MISMATCH",
1148
+ decision.decisionId,
1149
+ decision.correlationId,
1150
+ void 0
1151
+ );
1152
+ }
1153
+ }
1000
1154
  options.onDecision("ALLOW", { decision, signerId, command });
1001
1155
  if (options.mode === "dry-run") {
1002
1156
  return await originalClient.send(new clientKms.SignCommand(command));
@@ -1593,6 +1747,16 @@ var GateClient = class {
1593
1747
  });
1594
1748
  }
1595
1749
  }
1750
+ /**
1751
+ * Whether the SDK requires a decision token for ALLOW before sign (ENFORCE/HARD).
1752
+ * Env GATE_REQUIRE_DECISION_TOKEN overrides config.
1753
+ */
1754
+ getRequireDecisionToken() {
1755
+ if (typeof process !== "undefined" && process.env.GATE_REQUIRE_DECISION_TOKEN !== void 0) {
1756
+ return process.env.GATE_REQUIRE_DECISION_TOKEN === "true" || process.env.GATE_REQUIRE_DECISION_TOKEN === "1";
1757
+ }
1758
+ return this.config.requireDecisionToken ?? (this.mode === "ENFORCE" || this.config.enforcementMode === "HARD");
1759
+ }
1596
1760
  /**
1597
1761
  * Perform async IAM permission risk check (non-blocking)
1598
1762
  *
@@ -1622,7 +1786,9 @@ var GateClient = class {
1622
1786
  const timestampMs = req.timestampMs ?? nowMs();
1623
1787
  const startTime = Date.now();
1624
1788
  const failSafeMode = this.config.failSafeMode ?? "ALLOW_ON_TIMEOUT";
1789
+ const evaluationMode = this.config.evaluationMode ?? "BLOCKING";
1625
1790
  const requestMode = req.mode || this.mode;
1791
+ const requireToken = this.getRequireDecisionToken();
1626
1792
  const executeRequest = async () => {
1627
1793
  if (!this.config.local && this.heartbeatManager && req.signingContext?.signerId) {
1628
1794
  this.heartbeatManager.updateSignerId(req.signingContext.signerId);
@@ -1765,6 +1931,10 @@ var GateClient = class {
1765
1931
  reasonCodes: responseData.reason_codes ?? responseData.reasonCodes ?? [],
1766
1932
  policyVersion: responseData.policy_version ?? responseData.policyVersion,
1767
1933
  correlationId: responseData.correlation_id ?? responseData.correlationId,
1934
+ decisionId: responseData.decision_id ?? responseData.decisionId,
1935
+ decisionToken: responseData.decision_token ?? responseData.decisionToken,
1936
+ expiresAt: responseData.expires_at ?? responseData.expiresAt,
1937
+ txDigest: responseData.tx_digest ?? responseData.txDigest,
1768
1938
  stepUp: responseData.step_up ? {
1769
1939
  requestId: responseData.step_up.request_id ?? (responseData.stepUp?.requestId ?? ""),
1770
1940
  ttlSeconds: responseData.step_up.ttl_seconds ?? responseData.stepUp?.ttlSeconds
@@ -1780,10 +1950,115 @@ var GateClient = class {
1780
1950
  errorReason: simulationData.errorReason ?? simulationData.error_reason
1781
1951
  },
1782
1952
  simulationLatencyMs: metadata.simulationLatencyMs ?? metadata.simulation_latency_ms
1783
- } : {}
1953
+ } : {},
1954
+ metadata: {
1955
+ evaluationLatencyMs: metadata.evaluationLatencyMs ?? metadata.evaluation_latency_ms,
1956
+ policyHash: metadata.policyHash ?? metadata.policy_hash,
1957
+ snapshotVersion: metadata.snapshotVersion ?? metadata.snapshot_version
1958
+ }
1784
1959
  };
1785
1960
  const latencyMs = Date.now() - startTime;
1961
+ const expectedPolicyHash = this.config.expectedPolicyHash;
1962
+ const expectedSnapshotVersion = this.config.expectedSnapshotVersion;
1963
+ if (expectedPolicyHash != null && result.metadata?.policyHash !== expectedPolicyHash) {
1964
+ if (this.config.debug) {
1965
+ console.warn("[GATE SDK] Policy hash mismatch (pinning)", {
1966
+ expected: expectedPolicyHash,
1967
+ received: result.metadata?.policyHash,
1968
+ requestId
1969
+ });
1970
+ }
1971
+ this.metrics.recordRequest("BLOCK", latencyMs);
1972
+ throw new BlockIntelBlockedError(
1973
+ "POLICY_HASH_MISMATCH",
1974
+ result.decisionId ?? requestId,
1975
+ result.correlationId,
1976
+ requestId
1977
+ );
1978
+ }
1979
+ if (expectedSnapshotVersion != null && result.metadata?.snapshotVersion !== void 0 && result.metadata.snapshotVersion !== expectedSnapshotVersion) {
1980
+ if (this.config.debug) {
1981
+ console.warn("[GATE SDK] Snapshot version mismatch (pinning)", {
1982
+ expected: expectedSnapshotVersion,
1983
+ received: result.metadata?.snapshotVersion,
1984
+ requestId
1985
+ });
1986
+ }
1987
+ this.metrics.recordRequest("BLOCK", latencyMs);
1988
+ throw new BlockIntelBlockedError(
1989
+ "SNAPSHOT_VERSION_MISMATCH",
1990
+ result.decisionId ?? requestId,
1991
+ result.correlationId,
1992
+ requestId
1993
+ );
1994
+ }
1995
+ if (requireToken && requestMode === "ENFORCE" && result.decision === "ALLOW" && !this.config.local) {
1996
+ if (!result.decisionToken || !result.txDigest) {
1997
+ this.metrics.recordRequest("BLOCK", latencyMs);
1998
+ throw new BlockIntelBlockedError(
1999
+ "DECISION_TOKEN_MISSING",
2000
+ result.decisionId ?? requestId,
2001
+ result.correlationId,
2002
+ requestId
2003
+ );
2004
+ }
2005
+ const nowSec = Math.floor(Date.now() / 1e3);
2006
+ if (result.expiresAt != null && result.expiresAt < nowSec - 5) {
2007
+ this.metrics.recordRequest("BLOCK", latencyMs);
2008
+ throw new BlockIntelBlockedError(
2009
+ "DECISION_TOKEN_EXPIRED",
2010
+ result.decisionId ?? requestId,
2011
+ result.correlationId,
2012
+ requestId
2013
+ );
2014
+ }
2015
+ const publicKeyPem = this.config.decisionTokenPublicKey;
2016
+ if (publicKeyPem && result.decisionToken) {
2017
+ const { decodeJwtUnsafe: decodeJwtUnsafe2, verifyDecisionTokenRs256: verifyDecisionTokenRs2562 } = await Promise.resolve().then(() => (init_decisionTokenVerify(), decisionTokenVerify_exports));
2018
+ const decoded = decodeJwtUnsafe2(result.decisionToken);
2019
+ if (decoded && (decoded.header.alg || "").toUpperCase() === "RS256") {
2020
+ const resolvedPem = publicKeyPem.startsWith("-----") ? publicKeyPem : Buffer.from(publicKeyPem, "base64").toString("utf8");
2021
+ const verified = verifyDecisionTokenRs2562(result.decisionToken, resolvedPem);
2022
+ if (verified === null) {
2023
+ this.metrics.recordRequest("BLOCK", latencyMs);
2024
+ throw new BlockIntelBlockedError(
2025
+ "DECISION_TOKEN_INVALID",
2026
+ result.decisionId ?? requestId,
2027
+ result.correlationId,
2028
+ requestId
2029
+ );
2030
+ }
2031
+ }
2032
+ }
2033
+ const signerId = signingContext?.signerId ?? req.signingContext?.signerId;
2034
+ const fromAddress = txIntent.fromAddress ?? txIntent.from;
2035
+ const binding = buildTxBindingObject(txIntent, signerId, void 0, void 0, fromAddress);
2036
+ const computedDigest = computeTxDigest(binding);
2037
+ if (computedDigest !== result.txDigest) {
2038
+ this.metrics.recordRequest("BLOCK", latencyMs);
2039
+ throw new BlockIntelBlockedError(
2040
+ "DECISION_TOKEN_DIGEST_MISMATCH",
2041
+ result.decisionId ?? requestId,
2042
+ result.correlationId,
2043
+ requestId
2044
+ );
2045
+ }
2046
+ }
1786
2047
  if (result.decision === "BLOCK") {
2048
+ if (requestMode === "SOFT_ENFORCE") {
2049
+ console.warn("[SOFT ENFORCE] Policy violation detected - app can override", {
2050
+ requestId,
2051
+ reasonCodes: result.reasonCodes
2052
+ });
2053
+ this.metrics.recordRequest("BLOCK", latencyMs);
2054
+ return {
2055
+ ...result,
2056
+ decision: "BLOCK",
2057
+ enforced: false,
2058
+ mode: "SOFT_ENFORCE",
2059
+ warning: "Policy violation detected. Override at your own risk."
2060
+ };
2061
+ }
1787
2062
  if (requestMode === "SHADOW") {
1788
2063
  console.warn("[GATE SHADOW MODE] Would have blocked transaction", {
1789
2064
  requestId,
@@ -1822,6 +2097,26 @@ var GateClient = class {
1822
2097
  this.metrics.recordRequest("ALLOW", latencyMs);
1823
2098
  return result;
1824
2099
  };
2100
+ if (evaluationMode === "FIRE_AND_FORGET") {
2101
+ executeRequest().then((res) => {
2102
+ if (res.decision === "BLOCK" || res.shadowWouldBlock) {
2103
+ console.warn("[FIRE-AND-FORGET] Would have blocked:", res.reasonCodes);
2104
+ }
2105
+ this.metrics.recordRequest(res.decision === "ALLOW" ? "ALLOW" : "WOULD_BLOCK", Date.now() - startTime);
2106
+ }).catch((err) => {
2107
+ console.error("[FIRE-AND-FORGET] Attestation failed:", err);
2108
+ this.metrics.recordError();
2109
+ });
2110
+ return {
2111
+ decision: "ALLOW",
2112
+ decisionId: requestId,
2113
+ correlationId: requestId,
2114
+ reasonCodes: [],
2115
+ enforced: false,
2116
+ mode: requestMode,
2117
+ fireAndForget: true
2118
+ };
2119
+ }
1825
2120
  try {
1826
2121
  if (this.circuitBreaker) {
1827
2122
  return await this.circuitBreaker.execute(executeRequest);
@@ -1962,6 +2257,102 @@ var GateClient = class {
1962
2257
  intervalMs: args.intervalMs ?? this.config.stepUp?.pollingIntervalMs
1963
2258
  });
1964
2259
  }
2260
+ /**
2261
+ * Evaluate policy and sign in one call when decision is ALLOW.
2262
+ * Convenience for: evaluate → if ALLOW then sign → return { decision, signature }.
2263
+ */
2264
+ async evaluateAndSign(params) {
2265
+ const decision = await this.evaluate({
2266
+ txIntent: params.txIntent,
2267
+ signingContext: params.signingContext
2268
+ });
2269
+ if (decision.decision === "ALLOW") {
2270
+ const signature = await params.signer.sign({
2271
+ keyId: params.keyId,
2272
+ message: params.message,
2273
+ algorithm: params.algorithm ?? "ECDSA_SHA_256"
2274
+ });
2275
+ return { decision, signature };
2276
+ }
2277
+ return { decision };
2278
+ }
2279
+ /**
2280
+ * Attest a completed signature (post-sign). Use when you want zero latency impact on signing
2281
+ * but still want an audit trail. Policy is evaluated against txIntent; returns ALLOW or
2282
+ * POLICY_VIOLATION_DETECTED. Cannot be used for enforcement (signature already created).
2283
+ */
2284
+ async attestCompleted(req) {
2285
+ const requestId = uuid.v4();
2286
+ const timestampMs = nowMs();
2287
+ const txIntent = { ...req.txIntent };
2288
+ if (txIntent.to && !txIntent.toAddress) {
2289
+ txIntent.toAddress = txIntent.to;
2290
+ delete txIntent.to;
2291
+ }
2292
+ if (!txIntent.networkFamily && txIntent.chainId) txIntent.networkFamily = "EVM";
2293
+ const signingContext = {
2294
+ ...req.signingContext,
2295
+ signerId: req.signingContext?.signerId ?? req.signature.signerId
2296
+ };
2297
+ const body = {
2298
+ tenantId: this.config.tenantId,
2299
+ requestId,
2300
+ timestampMs,
2301
+ txIntent,
2302
+ signature: req.signature,
2303
+ signingContext
2304
+ };
2305
+ let headers = { "Content-Type": "application/json" };
2306
+ if (this.config.local) ; else if (this.hmacSigner) {
2307
+ const { canonicalizeJson: canonicalizeJson2 } = await Promise.resolve().then(() => (init_canonicalJson(), canonicalJson_exports));
2308
+ const canonicalBodyJson = canonicalizeJson2(body);
2309
+ const hmacHeaders = await this.hmacSigner.signRequest({
2310
+ method: "POST",
2311
+ path: "/defense/attest-completed",
2312
+ tenantId: this.config.tenantId,
2313
+ timestampMs,
2314
+ requestId,
2315
+ body
2316
+ });
2317
+ headers = { ...hmacHeaders };
2318
+ body.__canonicalJson = canonicalBodyJson;
2319
+ } else if (this.apiKeyAuth) {
2320
+ const apiKeyHeaders = this.apiKeyAuth.createHeaders({
2321
+ tenantId: this.config.tenantId,
2322
+ timestampMs,
2323
+ requestId
2324
+ });
2325
+ headers = { ...apiKeyHeaders };
2326
+ } else {
2327
+ throw new Error("No authentication configured");
2328
+ }
2329
+ const apiResponse = await this.httpClient.request({
2330
+ method: "POST",
2331
+ path: "/defense/attest-completed",
2332
+ headers,
2333
+ body,
2334
+ requestId
2335
+ });
2336
+ if (apiResponse.success === true && apiResponse.data) {
2337
+ const data = apiResponse.data;
2338
+ if (data.decision === "POLICY_VIOLATION_DETECTED") {
2339
+ console.warn("[POST-SIGN ATTESTATION] Policy violation detected after signing", {
2340
+ requestId,
2341
+ reasonCodes: data.reasonCodes
2342
+ });
2343
+ }
2344
+ return data;
2345
+ }
2346
+ if (apiResponse.error) {
2347
+ const err = apiResponse.error;
2348
+ throw new GateError(err.code || "SERVER_ERROR", err.message || "Request failed", {
2349
+ status: err.status,
2350
+ correlationId: err.correlationId,
2351
+ requestId
2352
+ });
2353
+ }
2354
+ throw new GateError("INVALID_RESPONSE" /* INVALID_RESPONSE */, "Invalid response from attest-completed", { requestId });
2355
+ }
1965
2356
  /**
1966
2357
  * Wrap AWS SDK v3 KMS client to intercept SignCommand calls
1967
2358
  *
@@ -1994,6 +2385,39 @@ var Gate = class {
1994
2385
  constructor(opts) {
1995
2386
  this.apiKey = opts?.apiKey ?? process.env.BLOCKINTEL_API_KEY;
1996
2387
  }
2388
+ /**
2389
+ * Create a GateClient from environment variables (5-line integration).
2390
+ *
2391
+ * Reads: GATE_BASE_URL, GATE_TENANT_ID, GATE_API_KEY (or GATE_KEY_ID + GATE_HMAC_SECRET), GATE_MODE.
2392
+ */
2393
+ static fromEnv(overrides) {
2394
+ const baseUrl = process.env.GATE_BASE_URL;
2395
+ const tenantId = process.env.GATE_TENANT_ID;
2396
+ const apiKey = process.env.GATE_API_KEY;
2397
+ const keyId = process.env.GATE_KEY_ID;
2398
+ const hmacSecret = process.env.GATE_HMAC_SECRET;
2399
+ const mode = process.env.GATE_MODE ?? "SHADOW";
2400
+ if (!baseUrl || !tenantId) {
2401
+ throw new Error("GATE_BASE_URL and GATE_TENANT_ID environment variables are required");
2402
+ }
2403
+ let auth;
2404
+ if (apiKey) {
2405
+ auth = { mode: "apiKey", apiKey };
2406
+ } else if (keyId && hmacSecret) {
2407
+ auth = { mode: "hmac", keyId, secret: hmacSecret };
2408
+ } else {
2409
+ throw new Error(
2410
+ "Either GATE_API_KEY or (GATE_KEY_ID and GATE_HMAC_SECRET) environment variables are required"
2411
+ );
2412
+ }
2413
+ return new GateClient({
2414
+ baseUrl,
2415
+ tenantId,
2416
+ auth,
2417
+ mode,
2418
+ ...overrides
2419
+ });
2420
+ }
1997
2421
  /**
1998
2422
  * Guard a signing operation. In passthrough mode, executes the callback.
1999
2423
  * For full Gate integration, use GateClient with evaluate() before sending.
@@ -2002,18 +2426,613 @@ var Gate = class {
2002
2426
  return cb();
2003
2427
  }
2004
2428
  };
2429
+ var AwsKmsSigner = class {
2430
+ config;
2431
+ constructor(config) {
2432
+ this.config = config;
2433
+ }
2434
+ getName() {
2435
+ return "AWS KMS";
2436
+ }
2437
+ isAvailable() {
2438
+ return !!this.config.kmsClient;
2439
+ }
2440
+ async sign(request) {
2441
+ if (!this.isAvailable()) {
2442
+ throw new Error("AWS KMS client not configured");
2443
+ }
2444
+ const algorithm = this.mapAlgorithm(request.algorithm || this.config.defaultAlgorithm || "ECDSA_SHA_256");
2445
+ const signInput = {
2446
+ KeyId: request.keyId,
2447
+ Message: Buffer.from(request.message),
2448
+ MessageType: request.messageType || this.config.defaultMessageType || "RAW",
2449
+ SigningAlgorithm: algorithm
2450
+ };
2451
+ const command = new clientKms.SignCommand(signInput);
2452
+ const response = await this.config.kmsClient.send(command);
2453
+ if (!response.Signature) {
2454
+ throw new Error("AWS KMS sign response missing signature");
2455
+ }
2456
+ return {
2457
+ signature: Buffer.from(response.Signature),
2458
+ keyId: response.KeyId || request.keyId,
2459
+ algorithm: response.SigningAlgorithm || algorithm,
2460
+ metadata: {
2461
+ keyId: response.KeyId,
2462
+ signingAlgorithm: response.SigningAlgorithm
2463
+ }
2464
+ };
2465
+ }
2466
+ /**
2467
+ * Map algorithm string to AWS KMS SigningAlgorithmSpec
2468
+ */
2469
+ mapAlgorithm(algorithm) {
2470
+ if (Object.values(clientKms.SigningAlgorithmSpec).includes(algorithm)) {
2471
+ return algorithm;
2472
+ }
2473
+ const algorithmMap = {
2474
+ "ECDSA_SHA_256": clientKms.SigningAlgorithmSpec.ECDSA_SHA_256,
2475
+ "ECDSA_SHA_384": clientKms.SigningAlgorithmSpec.ECDSA_SHA_384,
2476
+ "ECDSA_SHA_512": clientKms.SigningAlgorithmSpec.ECDSA_SHA_512,
2477
+ "RSASSA_PSS_SHA_256": clientKms.SigningAlgorithmSpec.RSASSA_PSS_SHA_256,
2478
+ "RSASSA_PSS_SHA_384": clientKms.SigningAlgorithmSpec.RSASSA_PSS_SHA_384,
2479
+ "RSASSA_PSS_SHA_512": clientKms.SigningAlgorithmSpec.RSASSA_PSS_SHA_512,
2480
+ "RSASSA_PKCS1_V1_5_SHA_256": clientKms.SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_256,
2481
+ "RSASSA_PKCS1_V1_5_SHA_384": clientKms.SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_384,
2482
+ "RSASSA_PKCS1_V1_5_SHA_512": clientKms.SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_512
2483
+ };
2484
+ return algorithmMap[algorithm.toUpperCase()] || clientKms.SigningAlgorithmSpec.ECDSA_SHA_256;
2485
+ }
2486
+ };
2487
+
2488
+ // src/signer/VaultSigner.ts
2489
+ var VaultSigner = class {
2490
+ config;
2491
+ authToken = null;
2492
+ constructor(config) {
2493
+ this.config = {
2494
+ mountPath: "transit",
2495
+ ...config
2496
+ };
2497
+ }
2498
+ getName() {
2499
+ return "HashiCorp Vault";
2500
+ }
2501
+ isAvailable() {
2502
+ return !!this.config.vaultUrl && (!!this.config.token || !!this.config.appRole);
2503
+ }
2504
+ async sign(request) {
2505
+ if (!this.isAvailable()) {
2506
+ throw new Error("Vault signer not configured");
2507
+ }
2508
+ if (!this.authToken && this.config.appRole) {
2509
+ await this.authenticateAppRole();
2510
+ }
2511
+ const token = this.config.token || this.authToken;
2512
+ if (!token) {
2513
+ throw new Error("Vault authentication token not available");
2514
+ }
2515
+ const algorithm = this.mapAlgorithm(request.algorithm || this.config.defaultAlgorithm || "ecdsa-sha2-256");
2516
+ const url = `${this.config.vaultUrl}/v1/${this.config.mountPath}/sign/${request.keyId}`;
2517
+ const messageBase64 = Buffer.from(request.message).toString("base64");
2518
+ const requestBody = {
2519
+ input: messageBase64,
2520
+ ...algorithm && { algorithm },
2521
+ ...request.options || {}
2522
+ };
2523
+ const timeout = this.config.httpOptions?.timeout || 5e3;
2524
+ const controller = new AbortController();
2525
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
2526
+ try {
2527
+ const response = await fetch(url, {
2528
+ method: "POST",
2529
+ headers: {
2530
+ "Content-Type": "application/json",
2531
+ "X-Vault-Token": token
2532
+ },
2533
+ body: JSON.stringify(requestBody),
2534
+ signal: controller.signal
2535
+ });
2536
+ clearTimeout(timeoutId);
2537
+ if (!response.ok) {
2538
+ const errorText = await response.text();
2539
+ throw new Error(`Vault sign failed: ${response.status} ${errorText}`);
2540
+ }
2541
+ const data = await response.json();
2542
+ if (!data.data || !data.data.signature) {
2543
+ throw new Error("Vault sign response missing signature");
2544
+ }
2545
+ const signatureParts = data.data.signature.split(":");
2546
+ const signatureBase64 = signatureParts[signatureParts.length - 1];
2547
+ const signature = Buffer.from(signatureBase64, "base64");
2548
+ return {
2549
+ signature,
2550
+ keyId: request.keyId,
2551
+ algorithm,
2552
+ metadata: {
2553
+ vaultSignature: data.data.signature,
2554
+ keyVersion: data.data.key_version
2555
+ }
2556
+ };
2557
+ } catch (error) {
2558
+ clearTimeout(timeoutId);
2559
+ if (error.name === "AbortError") {
2560
+ throw new Error("Vault sign request timeout");
2561
+ }
2562
+ throw error;
2563
+ }
2564
+ }
2565
+ /**
2566
+ * Authenticate using AppRole
2567
+ */
2568
+ async authenticateAppRole() {
2569
+ if (!this.config.appRole) {
2570
+ throw new Error("AppRole not configured");
2571
+ }
2572
+ const url = `${this.config.vaultUrl}/v1/auth/approle/login`;
2573
+ const response = await fetch(url, {
2574
+ method: "POST",
2575
+ headers: {
2576
+ "Content-Type": "application/json"
2577
+ },
2578
+ body: JSON.stringify({
2579
+ role_id: this.config.appRole.roleId,
2580
+ secret_id: this.config.appRole.secretId
2581
+ })
2582
+ });
2583
+ if (!response.ok) {
2584
+ const errorText = await response.text();
2585
+ throw new Error(`Vault AppRole authentication failed: ${response.status} ${errorText}`);
2586
+ }
2587
+ const data = await response.json();
2588
+ if (!data.auth || !data.auth.client_token) {
2589
+ throw new Error("Vault AppRole authentication response missing token");
2590
+ }
2591
+ this.authToken = data.auth.client_token;
2592
+ }
2593
+ /**
2594
+ * Map algorithm string to Vault format
2595
+ */
2596
+ mapAlgorithm(algorithm) {
2597
+ const algorithmMap = {
2598
+ "ECDSA_SHA_256": "ecdsa-sha2-256",
2599
+ "ECDSA_SHA_384": "ecdsa-sha2-384",
2600
+ "ECDSA_SHA_512": "ecdsa-sha2-512",
2601
+ "RSASSA_PSS_SHA_256": "rsa-sha2-256",
2602
+ "RSASSA_PSS_SHA_384": "rsa-sha2-384",
2603
+ "RSASSA_PSS_SHA_512": "rsa-sha2-512"
2604
+ };
2605
+ if (algorithm.startsWith("ecdsa-") || algorithm.startsWith("rsa-")) {
2606
+ return algorithm;
2607
+ }
2608
+ return algorithmMap[algorithm.toUpperCase()] || "ecdsa-sha2-256";
2609
+ }
2610
+ };
2611
+
2612
+ // src/signer/GcpKmsSigner.ts
2613
+ var GcpKmsSigner = class {
2614
+ config;
2615
+ accessToken = null;
2616
+ tokenExpiry = 0;
2617
+ constructor(config) {
2618
+ this.config = {
2619
+ useWorkloadIdentity: false,
2620
+ ...config
2621
+ };
2622
+ }
2623
+ getName() {
2624
+ return "Google Cloud KMS";
2625
+ }
2626
+ isAvailable() {
2627
+ if (this.config.useWorkloadIdentity) {
2628
+ return true;
2629
+ }
2630
+ return !!this.config.credentials && !!this.config.projectId;
2631
+ }
2632
+ async sign(request) {
2633
+ if (!this.isAvailable()) {
2634
+ throw new Error("GCP KMS signer not configured");
2635
+ }
2636
+ const accessToken = await this.getAccessToken();
2637
+ const algorithm = this.mapAlgorithm(request.algorithm || this.config.defaultAlgorithm || "EC_SIGN_P256_SHA256");
2638
+ const keyName = request.keyId.includes("/") ? request.keyId : `projects/${this.config.projectId}/locations/${this.config.location}/keyRings/${this.config.keyRing}/cryptoKeys/${request.keyId}`;
2639
+ const url = `https://cloudkms.googleapis.com/v1/${keyName}:asymmetricSign`;
2640
+ const messageBase64 = Buffer.from(request.message).toString("base64");
2641
+ const requestBody = {
2642
+ digest: {
2643
+ sha256: messageBase64
2644
+ // GCP expects digest, not raw message
2645
+ }
2646
+ };
2647
+ const timeout = this.config.httpOptions?.timeout || 5e3;
2648
+ const controller = new AbortController();
2649
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
2650
+ try {
2651
+ const response = await fetch(url, {
2652
+ method: "POST",
2653
+ headers: {
2654
+ "Content-Type": "application/json",
2655
+ "Authorization": `Bearer ${accessToken}`
2656
+ },
2657
+ body: JSON.stringify(requestBody),
2658
+ signal: controller.signal
2659
+ });
2660
+ clearTimeout(timeoutId);
2661
+ if (!response.ok) {
2662
+ const errorText = await response.text();
2663
+ throw new Error(`GCP KMS sign failed: ${response.status} ${errorText}`);
2664
+ }
2665
+ const data = await response.json();
2666
+ if (!data.signature) {
2667
+ throw new Error("GCP KMS sign response missing signature");
2668
+ }
2669
+ const signature = Buffer.from(data.signature, "base64");
2670
+ return {
2671
+ signature,
2672
+ keyId: request.keyId,
2673
+ algorithm,
2674
+ metadata: {
2675
+ name: data.name,
2676
+ verifiedDigestCrc32c: data.verifiedDigestCrc32c
2677
+ }
2678
+ };
2679
+ } catch (error) {
2680
+ clearTimeout(timeoutId);
2681
+ if (error.name === "AbortError") {
2682
+ throw new Error("GCP KMS sign request timeout");
2683
+ }
2684
+ throw error;
2685
+ }
2686
+ }
2687
+ /**
2688
+ * Get GCP access token
2689
+ */
2690
+ async getAccessToken() {
2691
+ if (this.accessToken && Date.now() < this.tokenExpiry - 5 * 60 * 1e3) {
2692
+ return this.accessToken;
2693
+ }
2694
+ if (this.config.useWorkloadIdentity) {
2695
+ const metadataUrl = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token";
2696
+ const response = await fetch(metadataUrl, {
2697
+ method: "GET",
2698
+ headers: {
2699
+ "Metadata-Flavor": "Google"
2700
+ }
2701
+ });
2702
+ if (!response.ok) {
2703
+ throw new Error(`GCP metadata service authentication failed: ${response.status}`);
2704
+ }
2705
+ const data = await response.json();
2706
+ this.accessToken = data.access_token;
2707
+ this.tokenExpiry = Date.now() + data.expires_in * 1e3;
2708
+ return data.access_token;
2709
+ } else {
2710
+ if (!this.config.credentials) {
2711
+ throw new Error("GCP credentials not configured");
2712
+ }
2713
+ throw new Error("Service account authentication requires @google-cloud/kms SDK. Install it with: npm install @google-cloud/kms. Alternatively, use workload identity (recommended for GCP environments).");
2714
+ }
2715
+ }
2716
+ /**
2717
+ * Map algorithm string to GCP format
2718
+ */
2719
+ mapAlgorithm(algorithm) {
2720
+ const algorithmMap = {
2721
+ "ECDSA_SHA_256": "EC_SIGN_P256_SHA256",
2722
+ "ECDSA_SHA_384": "EC_SIGN_P384_SHA384",
2723
+ "ECDSA_SHA_512": "EC_SIGN_P512_SHA512",
2724
+ "RSASSA_PSS_SHA_256": "RSA_SIGN_PSS_2048_SHA256",
2725
+ "RSASSA_PSS_SHA_384": "RSA_SIGN_PSS_3072_SHA256",
2726
+ "RSASSA_PSS_SHA_512": "RSA_SIGN_PSS_4096_SHA256",
2727
+ "RSASSA_PKCS1_V1_5_SHA_256": "RSA_SIGN_PKCS1_2048_SHA256",
2728
+ "RSASSA_PKCS1_V1_5_SHA_384": "RSA_SIGN_PKCS1_3072_SHA256",
2729
+ "RSASSA_PKCS1_V1_5_SHA_512": "RSA_SIGN_PKCS1_4096_SHA256"
2730
+ };
2731
+ if (algorithm.startsWith("EC_SIGN_") || algorithm.startsWith("RSA_SIGN_")) {
2732
+ return algorithm;
2733
+ }
2734
+ return algorithmMap[algorithm.toUpperCase()] || "EC_SIGN_P256_SHA256";
2735
+ }
2736
+ };
2737
+ var FireblocksSigner = class {
2738
+ config;
2739
+ apiBaseUrl;
2740
+ constructor(config) {
2741
+ this.config = config;
2742
+ this.apiBaseUrl = config.apiBaseUrl ?? "https://api.fireblocks.io";
2743
+ }
2744
+ getName() {
2745
+ return "Fireblocks";
2746
+ }
2747
+ isAvailable() {
2748
+ return !!this.config.apiKey && !!this.config.apiSecret;
2749
+ }
2750
+ async sign(request) {
2751
+ if (!this.isAvailable()) {
2752
+ throw new Error("Fireblocks API key and secret required");
2753
+ }
2754
+ const keyIdMatch = request.keyId.match(/^fireblocks:\/\/([^/]+)\/(.+)$/);
2755
+ if (!keyIdMatch) {
2756
+ throw new Error(
2757
+ "Invalid Fireblocks keyId format. Expected: fireblocks://vaultAccountId/assetId"
2758
+ );
2759
+ }
2760
+ const [, vaultAccountId, assetId] = keyIdMatch;
2761
+ const messageHex = request.message instanceof Buffer ? request.message.toString("hex") : Buffer.from(request.message).toString("hex");
2762
+ const requestId = request.options?.requestId || request.requestId;
2763
+ const txRequest = {
2764
+ operation: "RAW",
2765
+ source: { type: "VAULT_ACCOUNT", id: vaultAccountId },
2766
+ assetId,
2767
+ note: `Gate signing request: ${requestId ?? "unknown"}`,
2768
+ extraParameters: {
2769
+ rawMessageData: {
2770
+ messages: [{ content: messageHex }]
2771
+ }
2772
+ }
2773
+ };
2774
+ const token = this.createAuthToken("/v1/transactions", JSON.stringify(txRequest));
2775
+ const response = await fetch(`${this.apiBaseUrl}/v1/transactions`, {
2776
+ method: "POST",
2777
+ headers: {
2778
+ "Content-Type": "application/json",
2779
+ "X-API-Key": this.config.apiKey,
2780
+ Authorization: `Bearer ${token}`
2781
+ },
2782
+ body: JSON.stringify(txRequest)
2783
+ });
2784
+ if (!response.ok) {
2785
+ const error = await response.text();
2786
+ throw new Error(`Fireblocks API error: ${response.status} ${error}`);
2787
+ }
2788
+ const result = await response.json();
2789
+ const txId = result.id;
2790
+ if (!txId) {
2791
+ throw new Error("Fireblocks API did not return transaction id");
2792
+ }
2793
+ const signed = await this.pollTransaction(txId);
2794
+ const sigHex = signed?.signature ?? signed?.signedMessages?.[0]?.signature;
2795
+ if (!sigHex) {
2796
+ throw new Error(`Fireblocks transaction ${txId} did not return signature`);
2797
+ }
2798
+ return {
2799
+ signature: Buffer.from(sigHex, "hex"),
2800
+ keyId: request.keyId,
2801
+ algorithm: request.algorithm ?? "ECDSA_SHA_256"
2802
+ };
2803
+ }
2804
+ /**
2805
+ * Create JWT for Fireblocks API (RS256, uri + bodyHash in payload).
2806
+ */
2807
+ createAuthToken(uri, bodyJson) {
2808
+ const now = Math.floor(Date.now() / 1e3);
2809
+ const nonce = crypto.randomBytes(16).toString("hex");
2810
+ const bodyHash = bodyJson ? crypto.createHash("sha256").update(bodyJson, "utf8").digest("hex") : "";
2811
+ const payload = {
2812
+ uri,
2813
+ nonce,
2814
+ iat: now,
2815
+ exp: now + 30,
2816
+ sub: this.config.apiKey,
2817
+ bodyHash
2818
+ };
2819
+ const header = { alg: "RS256", typ: "JWT" };
2820
+ const encodedHeader = base64UrlEncode(JSON.stringify(header));
2821
+ const encodedPayload = base64UrlEncode(JSON.stringify(payload));
2822
+ const signingInput = `${encodedHeader}.${encodedPayload}`;
2823
+ const sign = crypto.createSign("RSA-SHA256");
2824
+ sign.update(signingInput);
2825
+ const signature = sign.sign(this.config.apiSecret);
2826
+ const encodedSig = base64UrlEncode(signature);
2827
+ return `${signingInput}.${encodedSig}`;
2828
+ }
2829
+ async pollTransaction(txId, maxAttempts = 30) {
2830
+ for (let i = 0; i < maxAttempts; i++) {
2831
+ const token = this.createAuthToken(`/v1/transactions/${txId}`);
2832
+ const response = await fetch(`${this.apiBaseUrl}/v1/transactions/${txId}`, {
2833
+ headers: {
2834
+ "X-API-Key": this.config.apiKey,
2835
+ Authorization: `Bearer ${token}`
2836
+ }
2837
+ });
2838
+ if (!response.ok) {
2839
+ throw new Error(`Failed to fetch transaction status: ${await response.text()}`);
2840
+ }
2841
+ const tx = await response.json();
2842
+ if (tx.status === "COMPLETED") {
2843
+ return tx.signedMessages?.[0] ? { signature: tx.signedMessages[0].signature } : tx;
2844
+ }
2845
+ if (tx.status === "FAILED" || tx.status === "REJECTED") {
2846
+ throw new Error(`Fireblocks transaction ${txId} failed: ${tx.status}`);
2847
+ }
2848
+ await new Promise((r) => setTimeout(r, 1e3));
2849
+ }
2850
+ throw new Error(
2851
+ `Fireblocks transaction ${txId} did not complete within ${maxAttempts} seconds`
2852
+ );
2853
+ }
2854
+ };
2855
+ function base64UrlEncode(input) {
2856
+ const raw = typeof input === "string" ? Buffer.from(input, "utf8").toString("base64") : input.toString("base64");
2857
+ return raw.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2858
+ }
2859
+ var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
2860
+ var NOT_LINKED = "PKCS#11 runtime not linked. Install pkcs11js (npm install pkcs11js) and ensure the HSM library path is correct, or provide a custom pkcs11Session to GenericHsmSigner.";
2861
+ function mechanismToPkcs11(mechanism) {
2862
+ switch (mechanism) {
2863
+ case "CKM_ECDSA_SHA256":
2864
+ return getPkcs11().CKM_ECDSA_SHA256;
2865
+ case "CKM_RSA_PKCS":
2866
+ return getPkcs11().CKM_SHA256_RSA_PKCS;
2867
+ default:
2868
+ throw new Error(`Unsupported PKCS#11 mechanism: ${mechanism}`);
2869
+ }
2870
+ }
2871
+ var pkcs11Module = void 0;
2872
+ function getPkcs11() {
2873
+ if (pkcs11Module !== void 0) {
2874
+ if (pkcs11Module === null) throw new Error(NOT_LINKED);
2875
+ return pkcs11Module;
2876
+ }
2877
+ try {
2878
+ pkcs11Module = require2("pkcs11js");
2879
+ return pkcs11Module;
2880
+ } catch {
2881
+ pkcs11Module = null;
2882
+ throw new Error(NOT_LINKED);
2883
+ }
2884
+ }
2885
+ var Pkcs11SessionImpl = class {
2886
+ libPath = "";
2887
+ pin = "";
2888
+ pkcs11 = null;
2889
+ session = null;
2890
+ initialized = false;
2891
+ async initialize(libraryPath, pin, options) {
2892
+ const p = getPkcs11();
2893
+ this.libPath = libraryPath;
2894
+ this.pin = pin;
2895
+ this.pkcs11 = new p.PKCS11();
2896
+ this.pkcs11.load(libraryPath);
2897
+ this.pkcs11.C_Initialize();
2898
+ this.initialized = true;
2899
+ const slots = this.pkcs11.C_GetSlotList(true);
2900
+ if (!slots || slots.length === 0) {
2901
+ await this.close();
2902
+ throw new Error("PKCS#11: no token present in any slot");
2903
+ }
2904
+ const slotIndex = options?.slotId ?? 0;
2905
+ if (slotIndex < 0 || slotIndex >= slots.length) {
2906
+ await this.close();
2907
+ throw new Error(`PKCS#11: slotId ${slotIndex} out of range (0..${slots.length - 1})`);
2908
+ }
2909
+ const slot = slots[slotIndex];
2910
+ const flags = p.CKF_SERIAL_SESSION | p.CKF_RW_SESSION;
2911
+ this.session = this.pkcs11.C_OpenSession(slot, flags);
2912
+ this.pkcs11.C_Login(this.session, p.CKU_USER, pin);
2913
+ }
2914
+ async sign(keyHandle, mechanism, data) {
2915
+ if (!this.pkcs11 || !this.session) {
2916
+ throw new Error("PKCS#11 session not initialized. Call initialize() first.");
2917
+ }
2918
+ getPkcs11();
2919
+ const mechCode = mechanismToPkcs11(mechanism);
2920
+ this.pkcs11.C_SignInit(this.session, { mechanism: mechCode }, keyHandle);
2921
+ const maxSigLen = 512;
2922
+ const outData = Buffer.alloc(maxSigLen);
2923
+ const signature = this.pkcs11.C_Sign(this.session, data, outData);
2924
+ return Buffer.from(signature);
2925
+ }
2926
+ async close() {
2927
+ if (!this.initialized) return;
2928
+ this.initialized = false;
2929
+ try {
2930
+ if (this.pkcs11 && this.session) {
2931
+ try {
2932
+ this.pkcs11.C_Logout(this.session);
2933
+ } catch {
2934
+ }
2935
+ try {
2936
+ this.pkcs11.C_CloseSession(this.session);
2937
+ } catch {
2938
+ }
2939
+ }
2940
+ if (this.pkcs11) {
2941
+ try {
2942
+ this.pkcs11.C_Finalize();
2943
+ } catch {
2944
+ }
2945
+ try {
2946
+ this.pkcs11.close();
2947
+ } catch {
2948
+ }
2949
+ }
2950
+ } finally {
2951
+ this.pkcs11 = null;
2952
+ this.session = null;
2953
+ }
2954
+ }
2955
+ };
2956
+
2957
+ // src/signer/GenericHsmSigner.ts
2958
+ var GenericHsmSigner = class {
2959
+ config;
2960
+ session = null;
2961
+ constructor(config) {
2962
+ this.config = config;
2963
+ }
2964
+ getName() {
2965
+ return "Generic HSM (PKCS#11)";
2966
+ }
2967
+ isAvailable() {
2968
+ return !!this.config.pkcs11LibraryPath && !!this.config.pin;
2969
+ }
2970
+ async sign(request) {
2971
+ if (!this.session) {
2972
+ this.session = this.config.pkcs11Session ?? await this.initializePkcs11Session();
2973
+ }
2974
+ const keyIdMatch = request.keyId.match(/^hsm:\/\/(.+)$/);
2975
+ if (!keyIdMatch) {
2976
+ throw new Error(
2977
+ "Invalid HSM keyId format. Expected: hsm://keyHandle (hex-encoded) or hsm://keyLabel"
2978
+ );
2979
+ }
2980
+ const keyHandle = Buffer.from(keyIdMatch[1], "hex");
2981
+ const mechanism = this.mapAlgorithmToMechanism(
2982
+ request.algorithm ?? "ECDSA_SHA_256"
2983
+ );
2984
+ const message = request.message instanceof Buffer ? request.message : Buffer.from(request.message);
2985
+ const signature = await this.session.sign(keyHandle, mechanism, message);
2986
+ return {
2987
+ signature,
2988
+ keyId: request.keyId,
2989
+ algorithm: request.algorithm ?? "ECDSA_SHA_256"
2990
+ };
2991
+ }
2992
+ async initializePkcs11Session() {
2993
+ const session = new Pkcs11SessionImpl();
2994
+ await session.initialize(this.config.pkcs11LibraryPath, this.config.pin, {
2995
+ slotId: this.config.slotId
2996
+ });
2997
+ return session;
2998
+ }
2999
+ mapAlgorithmToMechanism(algorithm) {
3000
+ switch (algorithm) {
3001
+ case "ECDSA_SHA_256":
3002
+ return "CKM_ECDSA_SHA256";
3003
+ case "RSASSA_PKCS1_V1_5_SHA_256":
3004
+ return "CKM_RSA_PKCS";
3005
+ default:
3006
+ throw new Error(`Unsupported algorithm for HSM: ${algorithm}`);
3007
+ }
3008
+ }
3009
+ /** Release the PKCS#11 session. Call when done to free resources. */
3010
+ async close() {
3011
+ if (this.session) {
3012
+ await this.session.close();
3013
+ this.session = null;
3014
+ }
3015
+ }
3016
+ };
2005
3017
 
3018
+ exports.AwsKmsSigner = AwsKmsSigner;
2006
3019
  exports.BlockIntelAuthError = BlockIntelAuthError;
2007
3020
  exports.BlockIntelBlockedError = BlockIntelBlockedError;
2008
3021
  exports.BlockIntelStepUpRequiredError = BlockIntelStepUpRequiredError;
2009
3022
  exports.BlockIntelUnavailableError = BlockIntelUnavailableError;
3023
+ exports.FireblocksSigner = FireblocksSigner;
2010
3024
  exports.Gate = Gate;
2011
3025
  exports.GateClient = GateClient;
2012
3026
  exports.GateError = GateError;
2013
3027
  exports.GateErrorCode = GateErrorCode;
3028
+ exports.GcpKmsSigner = GcpKmsSigner;
3029
+ exports.GenericHsmSigner = GenericHsmSigner;
2014
3030
  exports.HeartbeatManager = HeartbeatManager;
2015
3031
  exports.ProvenanceProvider = ProvenanceProvider;
2016
3032
  exports.StepUpNotConfiguredError = StepUpNotConfiguredError;
3033
+ exports.VaultSigner = VaultSigner;
3034
+ exports.buildTxBindingObject = buildTxBindingObject;
3035
+ exports.computeTxDigest = computeTxDigest;
2017
3036
  exports.createGateClient = createGateClient;
2018
3037
  exports.default = GateClient;
2019
3038
  exports.wrapKmsClient = wrapKmsClient;