@enactprotocol/mcp-server 1.0.13 → 1.2.0
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.js +2829 -944
- package/dist/index.js.bak +2829 -944
- package/dist/minimal.js +155 -199
- package/package.json +3 -3
package/dist/index.js.bak
CHANGED
|
@@ -225968,7 +225968,7 @@ class EnactApiClient {
|
|
|
225968
225968
|
throw new EnactApiError(`${errorData.error || response.statusText}`, response.status, endpoint);
|
|
225969
225969
|
}
|
|
225970
225970
|
const responseData = await response.json();
|
|
225971
|
-
if (
|
|
225971
|
+
if (!process.env.ENACT_SILENT) {
|
|
225972
225972
|
console.error(`API Response for ${endpoint}:`, responseData);
|
|
225973
225973
|
}
|
|
225974
225974
|
return responseData;
|
|
@@ -226015,7 +226015,7 @@ class EnactApiClient {
|
|
|
226015
226015
|
async searchTools(query) {
|
|
226016
226016
|
const endpoint = "/functions/v1/tools-search";
|
|
226017
226017
|
try {
|
|
226018
|
-
if (
|
|
226018
|
+
if (!process.env.ENACT_SILENT) {
|
|
226019
226019
|
console.error(`Search request to ${endpoint}:`, JSON.stringify(query, null, 2));
|
|
226020
226020
|
}
|
|
226021
226021
|
const response = await this.makeRequest(endpoint, {
|
|
@@ -226238,163 +226238,6 @@ class EnactApiError extends Error {
|
|
|
226238
226238
|
}
|
|
226239
226239
|
}
|
|
226240
226240
|
|
|
226241
|
-
// ../shared/dist/exec/logger.js
|
|
226242
|
-
var import_pino = __toESM(require_pino(), 1);
|
|
226243
|
-
var isSilentMode = () => process.env.CI === "true" || false || process.env.ENACT_SILENT === "true" || process.env.ENACT_SKIP_INTERACTIVE === "true";
|
|
226244
|
-
var logger = import_pino.default({
|
|
226245
|
-
level: process.env.LOG_LEVEL || "info",
|
|
226246
|
-
...{
|
|
226247
|
-
transport: {
|
|
226248
|
-
target: "pino-pretty",
|
|
226249
|
-
options: {
|
|
226250
|
-
colorize: true,
|
|
226251
|
-
ignore: "pid,hostname",
|
|
226252
|
-
translateTime: "SYS:standard"
|
|
226253
|
-
}
|
|
226254
|
-
}
|
|
226255
|
-
}
|
|
226256
|
-
});
|
|
226257
|
-
var wrappedLogger = {
|
|
226258
|
-
info: (...args) => {
|
|
226259
|
-
if (!isSilentMode()) {
|
|
226260
|
-
logger.info(...args);
|
|
226261
|
-
}
|
|
226262
|
-
},
|
|
226263
|
-
warn: (...args) => {
|
|
226264
|
-
if (!isSilentMode()) {
|
|
226265
|
-
logger.warn(...args);
|
|
226266
|
-
}
|
|
226267
|
-
},
|
|
226268
|
-
error: (...args) => {
|
|
226269
|
-
if (!isSilentMode()) {
|
|
226270
|
-
logger.error(...args);
|
|
226271
|
-
}
|
|
226272
|
-
},
|
|
226273
|
-
debug: (...args) => {
|
|
226274
|
-
if (!isSilentMode() && (process.env.DEBUG || process.env.VERBOSE)) {
|
|
226275
|
-
logger.debug(...args);
|
|
226276
|
-
}
|
|
226277
|
-
},
|
|
226278
|
-
clientLoggingEnabled: () => !process.env.ENACT_MCP_CLIENT,
|
|
226279
|
-
isLevelEnabled: (level) => {
|
|
226280
|
-
if (isSilentMode()) {
|
|
226281
|
-
return false;
|
|
226282
|
-
}
|
|
226283
|
-
return logger.isLevelEnabled(level);
|
|
226284
|
-
},
|
|
226285
|
-
pino: logger
|
|
226286
|
-
};
|
|
226287
|
-
var logger_default = wrappedLogger;
|
|
226288
|
-
|
|
226289
|
-
// ../shared/dist/security/security.js
|
|
226290
|
-
function verifyCommandSafety(command, tool) {
|
|
226291
|
-
const warnings = [];
|
|
226292
|
-
const blocked = [];
|
|
226293
|
-
const dangerousPatterns = [
|
|
226294
|
-
/rm\s+-rf\s+\//,
|
|
226295
|
-
/rm\s+-rf\s+\*/,
|
|
226296
|
-
/>\s*\/dev\/sd[a-z]/,
|
|
226297
|
-
/dd\s+if=.*of=\/dev/,
|
|
226298
|
-
/mkfs/,
|
|
226299
|
-
/fdisk/,
|
|
226300
|
-
/passwd/,
|
|
226301
|
-
/sudo\s+passwd/,
|
|
226302
|
-
/chmod\s+777/,
|
|
226303
|
-
/curl.*\|\s*sh/,
|
|
226304
|
-
/wget.*\|\s*sh/,
|
|
226305
|
-
/exec\s+sh/,
|
|
226306
|
-
/\/etc\/passwd/,
|
|
226307
|
-
/\/etc\/shadow/
|
|
226308
|
-
];
|
|
226309
|
-
for (const pattern of dangerousPatterns) {
|
|
226310
|
-
if (pattern.test(command)) {
|
|
226311
|
-
blocked.push(`Potentially dangerous command pattern detected: ${pattern.source}`);
|
|
226312
|
-
}
|
|
226313
|
-
}
|
|
226314
|
-
const warningPatterns = [
|
|
226315
|
-
/sudo\s+/,
|
|
226316
|
-
/su\s+/,
|
|
226317
|
-
/systemctl/,
|
|
226318
|
-
/service\s+/,
|
|
226319
|
-
/mount/,
|
|
226320
|
-
/umount/,
|
|
226321
|
-
/iptables/,
|
|
226322
|
-
/crontab/
|
|
226323
|
-
];
|
|
226324
|
-
for (const pattern of warningPatterns) {
|
|
226325
|
-
if (pattern.test(command)) {
|
|
226326
|
-
warnings.push(`Potentially privileged operation detected: ${pattern.source}`);
|
|
226327
|
-
}
|
|
226328
|
-
}
|
|
226329
|
-
if (command.includes("npx ") && !command.match(/npx\s+[^@#\s]+[@#]/)) {
|
|
226330
|
-
if (!command.includes("github:")) {
|
|
226331
|
-
warnings.push("NPX package not version-pinned - consider using @version or github:org/repo#commit");
|
|
226332
|
-
}
|
|
226333
|
-
}
|
|
226334
|
-
if (command.includes("uvx ") && !command.includes("git+") && !command.includes("@")) {
|
|
226335
|
-
warnings.push("UVX package not version-pinned - consider using @version or git+ URL");
|
|
226336
|
-
}
|
|
226337
|
-
if (command.includes("docker run") && !command.match(/:[^@\s]+(@sha256:|:\w)/)) {
|
|
226338
|
-
warnings.push("Docker image not version-pinned - consider using specific tags or digests");
|
|
226339
|
-
}
|
|
226340
|
-
if (tool.annotations?.openWorldHint !== true) {
|
|
226341
|
-
const networkPatterns = [
|
|
226342
|
-
/curl\s+/,
|
|
226343
|
-
/wget\s+/,
|
|
226344
|
-
/http[s]?:\/\//,
|
|
226345
|
-
/ftp:\/\//,
|
|
226346
|
-
/ssh\s+/,
|
|
226347
|
-
/scp\s+/,
|
|
226348
|
-
/rsync.*::/
|
|
226349
|
-
];
|
|
226350
|
-
for (const pattern of networkPatterns) {
|
|
226351
|
-
if (pattern.test(command)) {
|
|
226352
|
-
warnings.push("Network access detected but openWorldHint not set to true");
|
|
226353
|
-
break;
|
|
226354
|
-
}
|
|
226355
|
-
}
|
|
226356
|
-
}
|
|
226357
|
-
if (tool.annotations?.destructiveHint !== true) {
|
|
226358
|
-
const destructivePatterns = [
|
|
226359
|
-
/rm\s+/,
|
|
226360
|
-
/rmdir\s+/,
|
|
226361
|
-
/mv\s+.*\s+\/dev\//,
|
|
226362
|
-
/>\s*[^&]/,
|
|
226363
|
-
/tee\s+/
|
|
226364
|
-
];
|
|
226365
|
-
for (const pattern of destructivePatterns) {
|
|
226366
|
-
if (pattern.test(command)) {
|
|
226367
|
-
warnings.push("Potentially destructive operation detected but destructiveHint not set to true");
|
|
226368
|
-
break;
|
|
226369
|
-
}
|
|
226370
|
-
}
|
|
226371
|
-
}
|
|
226372
|
-
return {
|
|
226373
|
-
isSafe: blocked.length === 0,
|
|
226374
|
-
warnings,
|
|
226375
|
-
...blocked.length > 0 && { blocked }
|
|
226376
|
-
};
|
|
226377
|
-
}
|
|
226378
|
-
function sanitizeEnvironmentVariables(envVars) {
|
|
226379
|
-
const sanitized = {};
|
|
226380
|
-
for (const [key, value] of Object.entries(envVars)) {
|
|
226381
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
226382
|
-
logger_default.warn(`Invalid environment variable name: ${key}`);
|
|
226383
|
-
continue;
|
|
226384
|
-
}
|
|
226385
|
-
const strValue = String(value);
|
|
226386
|
-
if (strValue.includes(`
|
|
226387
|
-
`) || strValue.includes("\r")) {
|
|
226388
|
-
logger_default.warn(`Environment variable ${key} contains newline characters`);
|
|
226389
|
-
}
|
|
226390
|
-
if (strValue.includes("$(") || strValue.includes("`")) {
|
|
226391
|
-
logger_default.warn(`Environment variable ${key} contains command substitution patterns`);
|
|
226392
|
-
}
|
|
226393
|
-
sanitized[key] = strValue;
|
|
226394
|
-
}
|
|
226395
|
-
return sanitized;
|
|
226396
|
-
}
|
|
226397
|
-
|
|
226398
226241
|
// ../shared/dist/exec/validate.js
|
|
226399
226242
|
function validateAgainstSchema(value, schema, fieldName) {
|
|
226400
226243
|
const { type, format, enum: enumValues, minimum, maximum, pattern, required } = schema;
|
|
@@ -226520,24 +226363,6 @@ function validateInputs(tool, inputs) {
|
|
|
226520
226363
|
}
|
|
226521
226364
|
return validatedInputs;
|
|
226522
226365
|
}
|
|
226523
|
-
function validateOutput(tool, output) {
|
|
226524
|
-
if (!tool.outputSchema) {
|
|
226525
|
-
return output;
|
|
226526
|
-
}
|
|
226527
|
-
try {
|
|
226528
|
-
validateAgainstSchema(output, tool.outputSchema, "output");
|
|
226529
|
-
if (tool.outputSchema.required && Array.isArray(tool.outputSchema.required)) {
|
|
226530
|
-
for (const requiredField of tool.outputSchema.required) {
|
|
226531
|
-
if (output[requiredField] === undefined) {
|
|
226532
|
-
throw new Error(`Missing required output field: ${requiredField}`);
|
|
226533
|
-
}
|
|
226534
|
-
}
|
|
226535
|
-
}
|
|
226536
|
-
return output;
|
|
226537
|
-
} catch (error) {
|
|
226538
|
-
throw new Error(`Output validation failed: ${error.message}`);
|
|
226539
|
-
}
|
|
226540
|
-
}
|
|
226541
226366
|
|
|
226542
226367
|
// ../shared/dist/core/DirectExecutionProvider.js
|
|
226543
226368
|
import { spawn } from "child_process";
|
|
@@ -226546,6 +226371,54 @@ import { spawn } from "child_process";
|
|
|
226546
226371
|
class ExecutionProvider {
|
|
226547
226372
|
}
|
|
226548
226373
|
|
|
226374
|
+
// ../shared/dist/exec/logger.js
|
|
226375
|
+
var import_pino = __toESM(require_pino(), 1);
|
|
226376
|
+
var isSilentMode = () => process.env.CI === "true" || false || process.env.ENACT_SILENT === "true" || process.env.ENACT_SKIP_INTERACTIVE === "true";
|
|
226377
|
+
var logger = import_pino.default({
|
|
226378
|
+
level: process.env.LOG_LEVEL || "info",
|
|
226379
|
+
...{
|
|
226380
|
+
transport: {
|
|
226381
|
+
target: "pino-pretty",
|
|
226382
|
+
options: {
|
|
226383
|
+
colorize: true,
|
|
226384
|
+
ignore: "pid,hostname",
|
|
226385
|
+
translateTime: "SYS:standard"
|
|
226386
|
+
}
|
|
226387
|
+
}
|
|
226388
|
+
}
|
|
226389
|
+
});
|
|
226390
|
+
var wrappedLogger = {
|
|
226391
|
+
info: (...args) => {
|
|
226392
|
+
if (!isSilentMode()) {
|
|
226393
|
+
logger.info(...args);
|
|
226394
|
+
}
|
|
226395
|
+
},
|
|
226396
|
+
warn: (...args) => {
|
|
226397
|
+
if (!isSilentMode()) {
|
|
226398
|
+
logger.warn(...args);
|
|
226399
|
+
}
|
|
226400
|
+
},
|
|
226401
|
+
error: (...args) => {
|
|
226402
|
+
if (!isSilentMode()) {
|
|
226403
|
+
logger.error(...args);
|
|
226404
|
+
}
|
|
226405
|
+
},
|
|
226406
|
+
debug: (...args) => {
|
|
226407
|
+
if (!isSilentMode() && (process.env.DEBUG || process.env.VERBOSE)) {
|
|
226408
|
+
logger.debug(...args);
|
|
226409
|
+
}
|
|
226410
|
+
},
|
|
226411
|
+
clientLoggingEnabled: () => !process.env.ENACT_MCP_CLIENT,
|
|
226412
|
+
isLevelEnabled: (level) => {
|
|
226413
|
+
if (isSilentMode()) {
|
|
226414
|
+
return false;
|
|
226415
|
+
}
|
|
226416
|
+
return logger.isLevelEnabled(level);
|
|
226417
|
+
},
|
|
226418
|
+
pino: logger
|
|
226419
|
+
};
|
|
226420
|
+
var logger_default = wrappedLogger;
|
|
226421
|
+
|
|
226549
226422
|
// ../shared/dist/utils/timeout.js
|
|
226550
226423
|
function parseTimeout(timeout) {
|
|
226551
226424
|
const match = timeout.match(/^(\d+)([smh])$/);
|
|
@@ -235379,7 +235252,7 @@ class DaggerExecutionProvider extends ExecutionProvider {
|
|
|
235379
235252
|
logger_default.warn(`Attempt ${attempt}: Engine unhealthy, resetting...`);
|
|
235380
235253
|
await this.resetEngineContainer();
|
|
235381
235254
|
}
|
|
235382
|
-
const result = await this.executeCommand(tool.command, inputs, environment, tool.timeout);
|
|
235255
|
+
const result = await this.executeCommand(tool.command, inputs, environment, tool.timeout, undefined, tool);
|
|
235383
235256
|
logger_default.debug(`Command result: exitCode=${result.exitCode}, stdout length=${result.stdout?.length || 0}, stderr length=${result.stderr?.length || 0}`);
|
|
235384
235257
|
const output = this.parseOutput(result.stdout, tool);
|
|
235385
235258
|
return {
|
|
@@ -235462,7 +235335,7 @@ class DaggerExecutionProvider extends ExecutionProvider {
|
|
|
235462
235335
|
}
|
|
235463
235336
|
return "EXECUTION_ERROR";
|
|
235464
235337
|
}
|
|
235465
|
-
async executeCommand(command, inputs, environment, timeout, options) {
|
|
235338
|
+
async executeCommand(command, inputs, environment, timeout, options, tool) {
|
|
235466
235339
|
const verbose = options?.verbose ?? false;
|
|
235467
235340
|
const showSpinner = options?.showSpinner ?? false;
|
|
235468
235341
|
this.abortController = new AbortController;
|
|
@@ -235479,24 +235352,25 @@ class DaggerExecutionProvider extends ExecutionProvider {
|
|
|
235479
235352
|
try {
|
|
235480
235353
|
const substitutedCommand = this.substituteCommandVariables(command, inputs);
|
|
235481
235354
|
if (verbose) {
|
|
235355
|
+
const containerImage = tool?.from || this.options.baseImage;
|
|
235482
235356
|
try {
|
|
235483
235357
|
const pc = require_picocolors();
|
|
235484
235358
|
console.error(pc.cyan(`
|
|
235485
235359
|
\uD83D\uDC33 Executing Enact command in Dagger container:`));
|
|
235486
235360
|
console.error(pc.white(substitutedCommand));
|
|
235487
|
-
console.error(pc.gray(`
|
|
235361
|
+
console.error(pc.gray(`Container image: ${containerImage}${tool?.from ? " (from tool.from)" : " (default baseImage)"}`));
|
|
235488
235362
|
} catch (e2) {
|
|
235489
235363
|
console.error(`
|
|
235490
235364
|
\uD83D\uDC33 Executing Enact command in Dagger container:`);
|
|
235491
235365
|
console.error(substitutedCommand);
|
|
235492
|
-
console.error(`
|
|
235366
|
+
console.error(`Container image: ${containerImage}${tool?.from ? " (from tool.from)" : " (default baseImage)"}`);
|
|
235493
235367
|
}
|
|
235494
235368
|
}
|
|
235495
235369
|
const timeoutMs = timeout ? parseTimeout(timeout) : 30000;
|
|
235496
235370
|
const effectiveTimeout = Math.max(timeoutMs, this.options.engineTimeout);
|
|
235497
235371
|
logger_default.debug(`Parsed timeout: ${effectiveTimeout}ms (command: ${timeoutMs}ms, engine: ${this.options.engineTimeout}ms)`);
|
|
235498
235372
|
const result = await Promise.race([
|
|
235499
|
-
this.executeWithConnect(substitutedCommand, environment, inputs),
|
|
235373
|
+
this.executeWithConnect(substitutedCommand, environment, inputs, tool),
|
|
235500
235374
|
this.createTimeoutPromise(effectiveTimeout)
|
|
235501
235375
|
]);
|
|
235502
235376
|
if (spinner) {
|
|
@@ -235520,7 +235394,7 @@ class DaggerExecutionProvider extends ExecutionProvider {
|
|
|
235520
235394
|
this.abortController = null;
|
|
235521
235395
|
}
|
|
235522
235396
|
}
|
|
235523
|
-
async executeWithConnect(command, environment, inputs) {
|
|
235397
|
+
async executeWithConnect(command, environment, inputs, tool) {
|
|
235524
235398
|
return new Promise((resolve, reject) => {
|
|
235525
235399
|
const abortHandler = () => {
|
|
235526
235400
|
reject(new Error("Execution aborted"));
|
|
@@ -235531,7 +235405,7 @@ class DaggerExecutionProvider extends ExecutionProvider {
|
|
|
235531
235405
|
connect(async (client) => {
|
|
235532
235406
|
try {
|
|
235533
235407
|
logger_default.debug("\uD83D\uDD17 Connected to Dagger client");
|
|
235534
|
-
const container = await this.setupContainer(client, environment, inputs);
|
|
235408
|
+
const container = await this.setupContainer(client, environment, inputs, tool);
|
|
235535
235409
|
logger_default.debug("\uD83D\uDCE6 Container setup complete");
|
|
235536
235410
|
const commandResult = await this.executeInContainer(container, command);
|
|
235537
235411
|
logger_default.debug("⚡ Command execution complete");
|
|
@@ -235555,9 +235429,10 @@ class DaggerExecutionProvider extends ExecutionProvider {
|
|
|
235555
235429
|
});
|
|
235556
235430
|
});
|
|
235557
235431
|
}
|
|
235558
|
-
async setupContainer(client, environment, inputs) {
|
|
235559
|
-
|
|
235560
|
-
|
|
235432
|
+
async setupContainer(client, environment, inputs, tool) {
|
|
235433
|
+
const containerImage = tool?.from || this.options.baseImage;
|
|
235434
|
+
logger_default.debug(`\uD83D\uDE80 Setting up container with image: ${containerImage}${tool?.from ? " (from tool.from)" : " (default baseImage)"}`);
|
|
235435
|
+
let container = client.container().from(containerImage);
|
|
235561
235436
|
logger_default.debug("\uD83D\uDCE6 Base container created");
|
|
235562
235437
|
container = container.withWorkdir(this.options.workdir);
|
|
235563
235438
|
logger_default.debug(`\uD83D\uDCC1 Working directory set to: ${this.options.workdir}`);
|
|
@@ -235566,7 +235441,7 @@ class DaggerExecutionProvider extends ExecutionProvider {
|
|
|
235566
235441
|
}
|
|
235567
235442
|
logger_default.debug(`\uD83C\uDF0D Added ${Object.keys(environment.vars).length} environment variables`);
|
|
235568
235443
|
if (this.options.enableNetwork) {
|
|
235569
|
-
container = await this.installCommonTools(container);
|
|
235444
|
+
container = await this.installCommonTools(container, containerImage);
|
|
235570
235445
|
logger_default.debug("\uD83D\uDD27 Common tools installed");
|
|
235571
235446
|
} else {
|
|
235572
235447
|
logger_default.debug("\uD83D\uDD27 Skipping common tools installation (network disabled)");
|
|
@@ -235580,15 +235455,15 @@ class DaggerExecutionProvider extends ExecutionProvider {
|
|
|
235580
235455
|
logger_default.debug("✅ Container setup complete");
|
|
235581
235456
|
return container;
|
|
235582
235457
|
}
|
|
235583
|
-
async installCommonTools(container) {
|
|
235584
|
-
logger_default.debug(`\uD83D\uDD27 Installing common tools for
|
|
235458
|
+
async installCommonTools(container, containerImage) {
|
|
235459
|
+
logger_default.debug(`\uD83D\uDD27 Installing common tools for container image: ${containerImage}`);
|
|
235585
235460
|
try {
|
|
235586
|
-
if (
|
|
235461
|
+
if (containerImage.includes("node:")) {
|
|
235587
235462
|
logger_default.debug("\uD83D\uDCE6 Node.js image detected, skipping tool installation (most tools already available)");
|
|
235588
235463
|
return container;
|
|
235589
235464
|
}
|
|
235590
|
-
const isAlpine =
|
|
235591
|
-
const isDebian =
|
|
235465
|
+
const isAlpine = containerImage.includes("alpine");
|
|
235466
|
+
const isDebian = containerImage.includes("debian") || containerImage.includes("ubuntu");
|
|
235592
235467
|
if (isAlpine) {
|
|
235593
235468
|
logger_default.debug("\uD83D\uDCE6 Detected Alpine Linux, installing basic tools");
|
|
235594
235469
|
container = container.withExec([
|
|
@@ -235604,7 +235479,7 @@ class DaggerExecutionProvider extends ExecutionProvider {
|
|
|
235604
235479
|
'timeout 60 apt-get update && timeout 60 apt-get install -y curl wget git && rm -rf /var/lib/apt/lists/* || echo "Package installation failed, continuing..."'
|
|
235605
235480
|
]);
|
|
235606
235481
|
} else {
|
|
235607
|
-
logger_default.warn(`Unknown
|
|
235482
|
+
logger_default.warn(`Unknown container image ${containerImage}, skipping tool installation`);
|
|
235608
235483
|
}
|
|
235609
235484
|
logger_default.debug("✅ Common tools installation complete");
|
|
235610
235485
|
return container;
|
|
@@ -235845,7 +235720,7 @@ class DaggerExecutionProvider extends ExecutionProvider {
|
|
|
235845
235720
|
verbose,
|
|
235846
235721
|
showSpinner: true,
|
|
235847
235722
|
streamOutput: false
|
|
235848
|
-
});
|
|
235723
|
+
}, undefined);
|
|
235849
235724
|
if (result.exitCode !== 0) {
|
|
235850
235725
|
throw new Error(`Command failed with exit code ${result.exitCode}: ${result.stderr}`);
|
|
235851
235726
|
}
|
|
@@ -236095,460 +235970,2558 @@ function generateConfigLink(missingVars, toolName) {
|
|
|
236095
235970
|
}
|
|
236096
235971
|
|
|
236097
235972
|
// ../shared/dist/core/EnactCore.js
|
|
236098
|
-
var import_yaml2 = __toESM(require_dist3(), 1);
|
|
236099
|
-
|
|
236100
|
-
// ../shared/dist/security/sign.js
|
|
236101
235973
|
var import_yaml = __toESM(require_dist3(), 1);
|
|
236102
|
-
|
|
236103
|
-
|
|
236104
|
-
import * as
|
|
236105
|
-
|
|
236106
|
-
|
|
236107
|
-
|
|
236108
|
-
|
|
236109
|
-
|
|
236110
|
-
|
|
236111
|
-
|
|
236112
|
-
|
|
236113
|
-
|
|
236114
|
-
|
|
236115
|
-
"
|
|
236116
|
-
|
|
236117
|
-
|
|
236118
|
-
|
|
236119
|
-
"
|
|
236120
|
-
|
|
236121
|
-
"
|
|
236122
|
-
|
|
236123
|
-
|
|
236124
|
-
|
|
236125
|
-
|
|
236126
|
-
|
|
236127
|
-
|
|
236128
|
-
|
|
235974
|
+
|
|
235975
|
+
// ../shared/node_modules/@enactprotocol/security/dist/index.js
|
|
235976
|
+
import * as nc from "node:crypto";
|
|
235977
|
+
import fs4 from "fs";
|
|
235978
|
+
import path7 from "path";
|
|
235979
|
+
import os4 from "os";
|
|
235980
|
+
var crypto4 = nc && typeof nc === "object" && "webcrypto" in nc ? nc.webcrypto : nc && typeof nc === "object" && ("randomBytes" in nc) ? nc : undefined;
|
|
235981
|
+
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
235982
|
+
function isBytes(a) {
|
|
235983
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
235984
|
+
}
|
|
235985
|
+
function anumber(n) {
|
|
235986
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
235987
|
+
throw new Error("positive integer expected, got " + n);
|
|
235988
|
+
}
|
|
235989
|
+
function abytes(b, ...lengths) {
|
|
235990
|
+
if (!isBytes(b))
|
|
235991
|
+
throw new Error("Uint8Array expected");
|
|
235992
|
+
if (lengths.length > 0 && !lengths.includes(b.length))
|
|
235993
|
+
throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
|
|
235994
|
+
}
|
|
235995
|
+
function ahash(h2) {
|
|
235996
|
+
if (typeof h2 !== "function" || typeof h2.create !== "function")
|
|
235997
|
+
throw new Error("Hash should be wrapped by utils.createHasher");
|
|
235998
|
+
anumber(h2.outputLen);
|
|
235999
|
+
anumber(h2.blockLen);
|
|
236000
|
+
}
|
|
236001
|
+
function aexists(instance, checkFinished = true) {
|
|
236002
|
+
if (instance.destroyed)
|
|
236003
|
+
throw new Error("Hash instance has been destroyed");
|
|
236004
|
+
if (checkFinished && instance.finished)
|
|
236005
|
+
throw new Error("Hash#digest() has already been called");
|
|
236006
|
+
}
|
|
236007
|
+
function aoutput(out, instance) {
|
|
236008
|
+
abytes(out);
|
|
236009
|
+
const min = instance.outputLen;
|
|
236010
|
+
if (out.length < min) {
|
|
236011
|
+
throw new Error("digestInto() expects output buffer of length at least " + min);
|
|
236129
236012
|
}
|
|
236130
|
-
|
|
236131
|
-
|
|
236132
|
-
|
|
236133
|
-
|
|
236134
|
-
}
|
|
236013
|
+
}
|
|
236014
|
+
function clean(...arrays) {
|
|
236015
|
+
for (let i2 = 0;i2 < arrays.length; i2++) {
|
|
236016
|
+
arrays[i2].fill(0);
|
|
236135
236017
|
}
|
|
236136
|
-
return canonical;
|
|
236137
236018
|
}
|
|
236138
|
-
function
|
|
236139
|
-
|
|
236140
|
-
name: toolData.name,
|
|
236141
|
-
description: toolData.description,
|
|
236142
|
-
command: toolData.command,
|
|
236143
|
-
protocol_version: toolData.protocol_version,
|
|
236144
|
-
version: toolData.version,
|
|
236145
|
-
timeout: toolData.timeout,
|
|
236146
|
-
tags: toolData.tags,
|
|
236147
|
-
input_schema: toolData.input_schema,
|
|
236148
|
-
output_schema: toolData.output_schema,
|
|
236149
|
-
annotations: toolData.annotations,
|
|
236150
|
-
env_vars: toolData.env_vars,
|
|
236151
|
-
examples: toolData.examples,
|
|
236152
|
-
resources: toolData.resources,
|
|
236153
|
-
doc: toolData.doc,
|
|
236154
|
-
authors: toolData.authors,
|
|
236155
|
-
enact: toolData.enact || "1.0.0"
|
|
236156
|
-
};
|
|
236157
|
-
const canonical = createCanonicalToolDefinition(toolRecord);
|
|
236158
|
-
return JSON.stringify(canonical, Object.keys(canonical).sort());
|
|
236019
|
+
function createView(arr) {
|
|
236020
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
236159
236021
|
}
|
|
236160
|
-
|
|
236161
|
-
|
|
236162
|
-
allowedAlgorithms: ["sha256"]
|
|
236163
|
-
};
|
|
236164
|
-
var TRUSTED_KEYS_DIR = path7.join(process.env.HOME || ".", ".enact", "trusted-keys");
|
|
236165
|
-
function getTrustedPublicKeysMap() {
|
|
236166
|
-
const trustedKeys = new Map;
|
|
236167
|
-
if (fs4.existsSync(TRUSTED_KEYS_DIR)) {
|
|
236168
|
-
try {
|
|
236169
|
-
const files = fs4.readdirSync(TRUSTED_KEYS_DIR);
|
|
236170
|
-
for (const file of files) {
|
|
236171
|
-
if (file.endsWith(".pem")) {
|
|
236172
|
-
const keyPath = path7.join(TRUSTED_KEYS_DIR, file);
|
|
236173
|
-
const pemContent = fs4.readFileSync(keyPath, "utf8");
|
|
236174
|
-
const base64Key = pemToBase64(pemContent);
|
|
236175
|
-
trustedKeys.set(base64Key, pemContent);
|
|
236176
|
-
}
|
|
236177
|
-
}
|
|
236178
|
-
} catch (error) {
|
|
236179
|
-
console.error(`Error reading trusted keys: ${error.message}`);
|
|
236180
|
-
}
|
|
236181
|
-
}
|
|
236182
|
-
return trustedKeys;
|
|
236022
|
+
function rotr(word, shift) {
|
|
236023
|
+
return word << 32 - shift | word >>> shift;
|
|
236183
236024
|
}
|
|
236184
|
-
function
|
|
236185
|
-
|
|
236025
|
+
var hasHexBuiltin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function")();
|
|
236026
|
+
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i2) => i2.toString(16).padStart(2, "0"));
|
|
236027
|
+
function bytesToHex(bytes) {
|
|
236028
|
+
abytes(bytes);
|
|
236029
|
+
if (hasHexBuiltin)
|
|
236030
|
+
return bytes.toHex();
|
|
236031
|
+
let hex = "";
|
|
236032
|
+
for (let i2 = 0;i2 < bytes.length; i2++) {
|
|
236033
|
+
hex += hexes[bytes[i2]];
|
|
236034
|
+
}
|
|
236035
|
+
return hex;
|
|
236186
236036
|
}
|
|
236187
|
-
|
|
236188
|
-
|
|
236189
|
-
|
|
236190
|
-
|
|
236191
|
-
|
|
236037
|
+
var asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
|
|
236038
|
+
function asciiToBase16(ch) {
|
|
236039
|
+
if (ch >= asciis._0 && ch <= asciis._9)
|
|
236040
|
+
return ch - asciis._0;
|
|
236041
|
+
if (ch >= asciis.A && ch <= asciis.F)
|
|
236042
|
+
return ch - (asciis.A - 10);
|
|
236043
|
+
if (ch >= asciis.a && ch <= asciis.f)
|
|
236044
|
+
return ch - (asciis.a - 10);
|
|
236045
|
+
return;
|
|
236192
236046
|
}
|
|
236193
|
-
|
|
236194
|
-
|
|
236195
|
-
|
|
236196
|
-
|
|
236197
|
-
|
|
236198
|
-
|
|
236199
|
-
const
|
|
236200
|
-
|
|
236201
|
-
|
|
236202
|
-
const
|
|
236203
|
-
|
|
236204
|
-
|
|
236205
|
-
|
|
236047
|
+
function hexToBytes(hex) {
|
|
236048
|
+
if (typeof hex !== "string")
|
|
236049
|
+
throw new Error("hex string expected, got " + typeof hex);
|
|
236050
|
+
if (hasHexBuiltin)
|
|
236051
|
+
return Uint8Array.fromHex(hex);
|
|
236052
|
+
const hl = hex.length;
|
|
236053
|
+
const al = hl / 2;
|
|
236054
|
+
if (hl % 2)
|
|
236055
|
+
throw new Error("hex string expected, got unpadded hex of length " + hl);
|
|
236056
|
+
const array2 = new Uint8Array(al);
|
|
236057
|
+
for (let ai = 0, hi = 0;ai < al; ai++, hi += 2) {
|
|
236058
|
+
const n1 = asciiToBase16(hex.charCodeAt(hi));
|
|
236059
|
+
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
|
|
236060
|
+
if (n1 === undefined || n2 === undefined) {
|
|
236061
|
+
const char = hex[hi] + hex[hi + 1];
|
|
236062
|
+
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
|
|
236063
|
+
}
|
|
236064
|
+
array2[ai] = n1 * 16 + n2;
|
|
236065
|
+
}
|
|
236066
|
+
return array2;
|
|
236206
236067
|
}
|
|
236207
|
-
|
|
236208
|
-
|
|
236209
|
-
|
|
236210
|
-
|
|
236211
|
-
console.error("\uD83D\uDD0D Tool hash byte length:", toolHash.length, "(should be 32 for SHA-256)");
|
|
236212
|
-
console.error("\uD83D\uDD0D Signature bytes length:", signatureBytes.length, "(should be 64 for P-256)");
|
|
236213
|
-
const { webcrypto } = await import("node:crypto");
|
|
236214
|
-
const isValid2 = await webcrypto.subtle.verify({ name: "ECDSA", hash: { name: "SHA-256" } }, publicKeyObj, signatureBytes, toolHash);
|
|
236215
|
-
console.error("\uD83C\uDFAF Web Crypto API verification result:", isValid2);
|
|
236216
|
-
return isValid2;
|
|
236217
|
-
} catch (error) {
|
|
236218
|
-
console.error("❌ Verification error:", error);
|
|
236219
|
-
return false;
|
|
236220
|
-
}
|
|
236068
|
+
function utf8ToBytes(str) {
|
|
236069
|
+
if (typeof str !== "string")
|
|
236070
|
+
throw new Error("string expected");
|
|
236071
|
+
return new Uint8Array(new TextEncoder().encode(str));
|
|
236221
236072
|
}
|
|
236222
|
-
|
|
236223
|
-
|
|
236224
|
-
|
|
236225
|
-
|
|
236226
|
-
|
|
236227
|
-
if (trustedKeys.size === 0) {
|
|
236228
|
-
return {
|
|
236229
|
-
isValid: false,
|
|
236230
|
-
message: "No trusted public keys available",
|
|
236231
|
-
validSignatures: 0,
|
|
236232
|
-
totalSignatures: 0,
|
|
236233
|
-
verifiedSigners: [],
|
|
236234
|
-
errors: ["No trusted keys configured"]
|
|
236235
|
-
};
|
|
236236
|
-
}
|
|
236237
|
-
if (process.env.DEBUG) {
|
|
236238
|
-
console.error("Trusted keys available:");
|
|
236239
|
-
for (const [key, pem] of trustedKeys.entries()) {
|
|
236240
|
-
console.error(` Key: ${key.substring(0, 20)}...`);
|
|
236241
|
-
}
|
|
236242
|
-
}
|
|
236243
|
-
const tool = typeof toolYaml === "string" ? import_yaml.parse(toolYaml) : toolYaml;
|
|
236244
|
-
if (!tool.signatures || Object.keys(tool.signatures).length === 0) {
|
|
236245
|
-
return {
|
|
236246
|
-
isValid: false,
|
|
236247
|
-
message: "No signatures found in the tool",
|
|
236248
|
-
validSignatures: 0,
|
|
236249
|
-
totalSignatures: 0,
|
|
236250
|
-
verifiedSigners: [],
|
|
236251
|
-
errors: ["No signatures found"]
|
|
236252
|
-
};
|
|
236253
|
-
}
|
|
236254
|
-
const totalSignatures = Object.keys(tool.signatures).length;
|
|
236255
|
-
const toolForVerification = { ...tool };
|
|
236256
|
-
delete toolForVerification.signatures;
|
|
236257
|
-
const toolHashBytes = await hashTool(toolForVerification);
|
|
236258
|
-
if (true) {
|
|
236259
|
-
console.error("=== VERIFICATION DEBUG (WEBAPP COMPATIBLE) ===");
|
|
236260
|
-
console.error("Original tool signature field:", Object.keys(tool.signatures || {}));
|
|
236261
|
-
console.error("Tool before removing signatures:", JSON.stringify(tool, null, 2));
|
|
236262
|
-
console.error("Tool for verification:", JSON.stringify(toolForVerification, null, 2));
|
|
236263
|
-
console.error("Tool hash bytes length:", toolHashBytes.length, "(should be 32 for SHA-256)");
|
|
236264
|
-
console.error("==============================================");
|
|
236265
|
-
}
|
|
236266
|
-
let validSignatures = 0;
|
|
236267
|
-
for (const [publicKeyBase64, signatureData] of Object.entries(tool.signatures)) {
|
|
236268
|
-
try {
|
|
236269
|
-
if (policy.allowedAlgorithms && !policy.allowedAlgorithms.includes(signatureData.algorithm)) {
|
|
236270
|
-
errors3.push(`Signature by ${signatureData.signer}: unsupported algorithm ${signatureData.algorithm}`);
|
|
236271
|
-
continue;
|
|
236272
|
-
}
|
|
236273
|
-
if (policy.trustedSigners && !policy.trustedSigners.includes(signatureData.signer)) {
|
|
236274
|
-
errors3.push(`Signature by ${signatureData.signer}: signer not in trusted list`);
|
|
236275
|
-
continue;
|
|
236276
|
-
}
|
|
236277
|
-
const publicKeyPem = trustedKeys.get(publicKeyBase64);
|
|
236278
|
-
if (!publicKeyPem) {
|
|
236279
|
-
const reconstructedPem = base64ToPem(publicKeyBase64);
|
|
236280
|
-
if (!trustedKeys.has(pemToBase64(reconstructedPem))) {
|
|
236281
|
-
errors3.push(`Signature by ${signatureData.signer}: public key not trusted`);
|
|
236282
|
-
continue;
|
|
236283
|
-
}
|
|
236284
|
-
}
|
|
236285
|
-
if (process.env.DEBUG) {
|
|
236286
|
-
console.error("Looking for public key:", publicKeyBase64);
|
|
236287
|
-
console.error("Key found in trusted keys:", !!publicKeyPem);
|
|
236288
|
-
}
|
|
236289
|
-
let isValid3 = false;
|
|
236290
|
-
try {
|
|
236291
|
-
const publicKeyToUse = publicKeyPem || base64ToPem(publicKeyBase64);
|
|
236292
|
-
if (process.env.DEBUG) {
|
|
236293
|
-
console.error("Signature base64:", signatureData.value);
|
|
236294
|
-
console.error("Signature buffer length (should be 64):", Buffer.from(signatureData.value, "base64").length);
|
|
236295
|
-
console.error("Public key base64:", publicKeyBase64);
|
|
236296
|
-
}
|
|
236297
|
-
if (signatureData.type === "ecdsa-p256") {
|
|
236298
|
-
const { webcrypto } = await import("node:crypto");
|
|
236299
|
-
const publicKeyData = crypto4.createPublicKey({
|
|
236300
|
-
key: publicKeyToUse,
|
|
236301
|
-
format: "pem",
|
|
236302
|
-
type: "spki"
|
|
236303
|
-
}).export({ format: "der", type: "spki" });
|
|
236304
|
-
const publicKeyObj = await webcrypto.subtle.importKey("spki", publicKeyData, { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"]);
|
|
236305
|
-
isValid3 = await verifyToolSignature(toolForVerification, signatureData.value, publicKeyObj);
|
|
236306
|
-
if (process.env.DEBUG) {
|
|
236307
|
-
console.error("Web Crypto API verification result (webapp compatible):", isValid3);
|
|
236308
|
-
}
|
|
236309
|
-
} else {
|
|
236310
|
-
const verify = crypto4.createVerify("SHA256");
|
|
236311
|
-
const canonicalJson = createCanonicalToolJson(toolForVerification);
|
|
236312
|
-
verify.update(canonicalJson, "utf8");
|
|
236313
|
-
const signature = Buffer.from(signatureData.value, "base64");
|
|
236314
|
-
isValid3 = verify.verify(publicKeyToUse, signature);
|
|
236315
|
-
}
|
|
236316
|
-
} catch (verifyError) {
|
|
236317
|
-
errors3.push(`Signature by ${signatureData.signer}: verification error - ${verifyError.message}`);
|
|
236318
|
-
continue;
|
|
236319
|
-
}
|
|
236320
|
-
if (isValid3) {
|
|
236321
|
-
validSignatures++;
|
|
236322
|
-
verifiedSigners.push({
|
|
236323
|
-
signer: signatureData.signer,
|
|
236324
|
-
role: signatureData.role,
|
|
236325
|
-
keyId: publicKeyBase64.substring(0, 8)
|
|
236326
|
-
});
|
|
236327
|
-
} else {
|
|
236328
|
-
errors3.push(`Signature by ${signatureData.signer}: cryptographic verification failed`);
|
|
236329
|
-
}
|
|
236330
|
-
} catch (error) {
|
|
236331
|
-
errors3.push(`Signature by ${signatureData.signer}: verification error - ${error.message}`);
|
|
236332
|
-
}
|
|
236333
|
-
}
|
|
236334
|
-
const policyErrors = [];
|
|
236335
|
-
if (policy.minimumSignatures && validSignatures < policy.minimumSignatures) {
|
|
236336
|
-
policyErrors.push(`Policy requires ${policy.minimumSignatures} signatures, but only ${validSignatures} valid`);
|
|
236337
|
-
}
|
|
236338
|
-
if (policy.requireRoles && policy.requireRoles.length > 0) {
|
|
236339
|
-
const verifiedRoles = verifiedSigners.map((s2) => s2.role).filter(Boolean);
|
|
236340
|
-
const missingRoles = policy.requireRoles.filter((role) => !verifiedRoles.includes(role));
|
|
236341
|
-
if (missingRoles.length > 0) {
|
|
236342
|
-
policyErrors.push(`Policy requires roles: ${missingRoles.join(", ")}`);
|
|
236343
|
-
}
|
|
236344
|
-
}
|
|
236345
|
-
const isValid2 = policyErrors.length === 0 && validSignatures > 0;
|
|
236346
|
-
const allErrors = [...errors3, ...policyErrors];
|
|
236347
|
-
let message;
|
|
236348
|
-
if (isValid2) {
|
|
236349
|
-
message = `Tool "${tool.name}" verified with ${validSignatures}/${totalSignatures} valid signatures`;
|
|
236350
|
-
if (verifiedSigners.length > 0) {
|
|
236351
|
-
const signerInfo = verifiedSigners.map((s2) => `${s2.signer}${s2.role ? ` (${s2.role})` : ""}`).join(", ");
|
|
236352
|
-
message += ` from: ${signerInfo}`;
|
|
236353
|
-
}
|
|
236354
|
-
} else {
|
|
236355
|
-
message = `Tool "${tool.name}" verification failed: ${allErrors[0] || "Unknown error"}`;
|
|
236356
|
-
}
|
|
236357
|
-
return {
|
|
236358
|
-
isValid: isValid2,
|
|
236359
|
-
message,
|
|
236360
|
-
validSignatures,
|
|
236361
|
-
totalSignatures,
|
|
236362
|
-
verifiedSigners,
|
|
236363
|
-
errors: allErrors
|
|
236364
|
-
};
|
|
236365
|
-
} catch (error) {
|
|
236366
|
-
return {
|
|
236367
|
-
isValid: false,
|
|
236368
|
-
message: `Verification error: ${error.message}`,
|
|
236369
|
-
validSignatures: 0,
|
|
236370
|
-
totalSignatures: 0,
|
|
236371
|
-
verifiedSigners: [],
|
|
236372
|
-
errors: [error.message]
|
|
236373
|
-
};
|
|
236374
|
-
}
|
|
236073
|
+
function toBytes(data) {
|
|
236074
|
+
if (typeof data === "string")
|
|
236075
|
+
data = utf8ToBytes(data);
|
|
236076
|
+
abytes(data);
|
|
236077
|
+
return data;
|
|
236375
236078
|
}
|
|
236376
|
-
|
|
236377
|
-
|
|
236378
|
-
|
|
236379
|
-
|
|
236380
|
-
|
|
236381
|
-
|
|
236382
|
-
|
|
236383
|
-
|
|
236384
|
-
|
|
236385
|
-
|
|
236386
|
-
|
|
236387
|
-
|
|
236388
|
-
requireRoles: ["author", "reviewer", "approver"],
|
|
236389
|
-
allowedAlgorithms: ["sha256"]
|
|
236079
|
+
function concatBytes(...arrays) {
|
|
236080
|
+
let sum = 0;
|
|
236081
|
+
for (let i2 = 0;i2 < arrays.length; i2++) {
|
|
236082
|
+
const a = arrays[i2];
|
|
236083
|
+
abytes(a);
|
|
236084
|
+
sum += a.length;
|
|
236085
|
+
}
|
|
236086
|
+
const res = new Uint8Array(sum);
|
|
236087
|
+
for (let i2 = 0, pad = 0;i2 < arrays.length; i2++) {
|
|
236088
|
+
const a = arrays[i2];
|
|
236089
|
+
res.set(a, pad);
|
|
236090
|
+
pad += a.length;
|
|
236390
236091
|
}
|
|
236391
|
-
|
|
236092
|
+
return res;
|
|
236093
|
+
}
|
|
236392
236094
|
|
|
236393
|
-
|
|
236394
|
-
|
|
236395
|
-
|
|
236396
|
-
|
|
236397
|
-
|
|
236398
|
-
|
|
236399
|
-
|
|
236400
|
-
|
|
236401
|
-
|
|
236402
|
-
|
|
236403
|
-
|
|
236404
|
-
|
|
236405
|
-
|
|
236406
|
-
totalSignatures: 0,
|
|
236407
|
-
verifiedSigners: [],
|
|
236408
|
-
errors: ["Signature verification was explicitly skipped"]
|
|
236409
|
-
}
|
|
236410
|
-
};
|
|
236095
|
+
class Hash {
|
|
236096
|
+
}
|
|
236097
|
+
function createHasher(hashCons) {
|
|
236098
|
+
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
|
|
236099
|
+
const tmp = hashCons();
|
|
236100
|
+
hashC.outputLen = tmp.outputLen;
|
|
236101
|
+
hashC.blockLen = tmp.blockLen;
|
|
236102
|
+
hashC.create = () => hashCons();
|
|
236103
|
+
return hashC;
|
|
236104
|
+
}
|
|
236105
|
+
function randomBytes(bytesLength = 32) {
|
|
236106
|
+
if (crypto4 && typeof crypto4.getRandomValues === "function") {
|
|
236107
|
+
return crypto4.getRandomValues(new Uint8Array(bytesLength));
|
|
236411
236108
|
}
|
|
236412
|
-
|
|
236413
|
-
|
|
236414
|
-
logger_default.warn(`⚠️ Tool has no signatures: ${toolName}`);
|
|
236415
|
-
if (options.allowUnsigned) {
|
|
236416
|
-
logger_default.warn(` Allowing unsigned tool execution due to allowUnsigned flag (DEV/TEST ONLY)`);
|
|
236417
|
-
return {
|
|
236418
|
-
allowed: true,
|
|
236419
|
-
reason: `Unsigned tool allowed by explicit permission: ${toolName}`,
|
|
236420
|
-
verificationResult: {
|
|
236421
|
-
isValid: false,
|
|
236422
|
-
message: "No signatures found, but execution allowed",
|
|
236423
|
-
validSignatures: 0,
|
|
236424
|
-
totalSignatures: 0,
|
|
236425
|
-
verifiedSigners: [],
|
|
236426
|
-
errors: [
|
|
236427
|
-
"Tool has no signatures but execution was explicitly allowed"
|
|
236428
|
-
]
|
|
236429
|
-
}
|
|
236430
|
-
};
|
|
236431
|
-
}
|
|
236432
|
-
return {
|
|
236433
|
-
allowed: false,
|
|
236434
|
-
reason: `Tool has no signatures and unsigned execution is not permitted: ${toolName}`,
|
|
236435
|
-
error: {
|
|
236436
|
-
message: `Tool "${toolName}" has no cryptographic signatures. For security, only signed tools can be executed.`,
|
|
236437
|
-
code: "NO_SIGNATURES_FOUND",
|
|
236438
|
-
details: {
|
|
236439
|
-
toolName,
|
|
236440
|
-
hasSignature: !!tool.signature,
|
|
236441
|
-
hasSignatures: !!tool.signatures,
|
|
236442
|
-
signatureCount: tool.signatures ? Object.keys(tool.signatures).length : 0
|
|
236443
|
-
}
|
|
236444
|
-
}
|
|
236445
|
-
};
|
|
236109
|
+
if (crypto4 && typeof crypto4.randomBytes === "function") {
|
|
236110
|
+
return Uint8Array.from(crypto4.randomBytes(bytesLength));
|
|
236446
236111
|
}
|
|
236447
|
-
|
|
236448
|
-
|
|
236449
|
-
|
|
236450
|
-
|
|
236451
|
-
|
|
236452
|
-
|
|
236453
|
-
|
|
236454
|
-
|
|
236455
|
-
|
|
236456
|
-
|
|
236457
|
-
|
|
236458
|
-
|
|
236459
|
-
|
|
236460
|
-
|
|
236461
|
-
|
|
236462
|
-
|
|
236463
|
-
|
|
236112
|
+
throw new Error("crypto.getRandomValues must be defined");
|
|
236113
|
+
}
|
|
236114
|
+
function setBigUint64(view, byteOffset, value, isLE) {
|
|
236115
|
+
if (typeof view.setBigUint64 === "function")
|
|
236116
|
+
return view.setBigUint64(byteOffset, value, isLE);
|
|
236117
|
+
const _32n = BigInt(32);
|
|
236118
|
+
const _u32_max = BigInt(4294967295);
|
|
236119
|
+
const wh = Number(value >> _32n & _u32_max);
|
|
236120
|
+
const wl = Number(value & _u32_max);
|
|
236121
|
+
const h2 = isLE ? 4 : 0;
|
|
236122
|
+
const l = isLE ? 0 : 4;
|
|
236123
|
+
view.setUint32(byteOffset + h2, wh, isLE);
|
|
236124
|
+
view.setUint32(byteOffset + l, wl, isLE);
|
|
236125
|
+
}
|
|
236126
|
+
function Chi(a, b, c) {
|
|
236127
|
+
return a & b ^ ~a & c;
|
|
236128
|
+
}
|
|
236129
|
+
function Maj(a, b, c) {
|
|
236130
|
+
return a & b ^ a & c ^ b & c;
|
|
236131
|
+
}
|
|
236132
|
+
|
|
236133
|
+
class HashMD extends Hash {
|
|
236134
|
+
constructor(blockLen, outputLen, padOffset, isLE) {
|
|
236135
|
+
super();
|
|
236136
|
+
this.finished = false;
|
|
236137
|
+
this.length = 0;
|
|
236138
|
+
this.pos = 0;
|
|
236139
|
+
this.destroyed = false;
|
|
236140
|
+
this.blockLen = blockLen;
|
|
236141
|
+
this.outputLen = outputLen;
|
|
236142
|
+
this.padOffset = padOffset;
|
|
236143
|
+
this.isLE = isLE;
|
|
236144
|
+
this.buffer = new Uint8Array(blockLen);
|
|
236145
|
+
this.view = createView(this.buffer);
|
|
236146
|
+
}
|
|
236147
|
+
update(data) {
|
|
236148
|
+
aexists(this);
|
|
236149
|
+
data = toBytes(data);
|
|
236150
|
+
abytes(data);
|
|
236151
|
+
const { view, buffer, blockLen } = this;
|
|
236152
|
+
const len = data.length;
|
|
236153
|
+
for (let pos = 0;pos < len; ) {
|
|
236154
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
236155
|
+
if (take === blockLen) {
|
|
236156
|
+
const dataView = createView(data);
|
|
236157
|
+
for (;blockLen <= len - pos; pos += blockLen)
|
|
236158
|
+
this.process(dataView, pos);
|
|
236159
|
+
continue;
|
|
236464
236160
|
}
|
|
236465
|
-
|
|
236466
|
-
|
|
236467
|
-
|
|
236468
|
-
|
|
236469
|
-
|
|
236470
|
-
|
|
236471
|
-
logger_default.error(`❌ Signature verification failed for tool: ${toolName}`);
|
|
236472
|
-
logger_default.error(` Policy: ${policyKey.toLowerCase()}`);
|
|
236473
|
-
logger_default.error(` Valid signatures: ${verificationResult.validSignatures}/${verificationResult.totalSignatures}`);
|
|
236474
|
-
if (verificationResult.errors.length > 0) {
|
|
236475
|
-
logger_default.error(` Errors:`);
|
|
236476
|
-
verificationResult.errors.forEach((error) => logger_default.error(` - ${error}`));
|
|
236161
|
+
buffer.set(data.subarray(pos, pos + take), this.pos);
|
|
236162
|
+
this.pos += take;
|
|
236163
|
+
pos += take;
|
|
236164
|
+
if (this.pos === blockLen) {
|
|
236165
|
+
this.process(view, 0);
|
|
236166
|
+
this.pos = 0;
|
|
236477
236167
|
}
|
|
236478
|
-
return {
|
|
236479
|
-
allowed: false,
|
|
236480
|
-
reason: `Tool signature verification failed: ${verificationResult.message}`,
|
|
236481
|
-
verificationResult,
|
|
236482
|
-
error: {
|
|
236483
|
-
message: `Tool "${toolName}" failed signature verification. ${verificationResult.message}`,
|
|
236484
|
-
code: "SIGNATURE_VERIFICATION_FAILED",
|
|
236485
|
-
details: {
|
|
236486
|
-
toolName,
|
|
236487
|
-
policy: policyKey.toLowerCase(),
|
|
236488
|
-
validSignatures: verificationResult.validSignatures,
|
|
236489
|
-
totalSignatures: verificationResult.totalSignatures,
|
|
236490
|
-
errors: verificationResult.errors,
|
|
236491
|
-
verifiedSigners: verificationResult.verifiedSigners
|
|
236492
|
-
}
|
|
236493
|
-
}
|
|
236494
|
-
};
|
|
236495
236168
|
}
|
|
236496
|
-
|
|
236497
|
-
|
|
236498
|
-
|
|
236499
|
-
|
|
236500
|
-
|
|
236501
|
-
|
|
236502
|
-
|
|
236503
|
-
|
|
236504
|
-
|
|
236505
|
-
|
|
236506
|
-
|
|
236507
|
-
|
|
236169
|
+
this.length += data.length;
|
|
236170
|
+
this.roundClean();
|
|
236171
|
+
return this;
|
|
236172
|
+
}
|
|
236173
|
+
digestInto(out) {
|
|
236174
|
+
aexists(this);
|
|
236175
|
+
aoutput(out, this);
|
|
236176
|
+
this.finished = true;
|
|
236177
|
+
const { buffer, view, blockLen, isLE } = this;
|
|
236178
|
+
let { pos } = this;
|
|
236179
|
+
buffer[pos++] = 128;
|
|
236180
|
+
clean(this.buffer.subarray(pos));
|
|
236181
|
+
if (this.padOffset > blockLen - pos) {
|
|
236182
|
+
this.process(view, 0);
|
|
236183
|
+
pos = 0;
|
|
236184
|
+
}
|
|
236185
|
+
for (let i2 = pos;i2 < blockLen; i2++)
|
|
236186
|
+
buffer[i2] = 0;
|
|
236187
|
+
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
|
|
236188
|
+
this.process(view, 0);
|
|
236189
|
+
const oview = createView(out);
|
|
236190
|
+
const len = this.outputLen;
|
|
236191
|
+
if (len % 4)
|
|
236192
|
+
throw new Error("_sha2: outputLen should be aligned to 32bit");
|
|
236193
|
+
const outLen = len / 4;
|
|
236194
|
+
const state = this.get();
|
|
236195
|
+
if (outLen > state.length)
|
|
236196
|
+
throw new Error("_sha2: outputLen bigger than state");
|
|
236197
|
+
for (let i2 = 0;i2 < outLen; i2++)
|
|
236198
|
+
oview.setUint32(4 * i2, state[i2], isLE);
|
|
236199
|
+
}
|
|
236200
|
+
digest() {
|
|
236201
|
+
const { buffer, outputLen } = this;
|
|
236202
|
+
this.digestInto(buffer);
|
|
236203
|
+
const res = buffer.slice(0, outputLen);
|
|
236204
|
+
this.destroy();
|
|
236205
|
+
return res;
|
|
236206
|
+
}
|
|
236207
|
+
_cloneInto(to) {
|
|
236208
|
+
to || (to = new this.constructor);
|
|
236209
|
+
to.set(...this.get());
|
|
236210
|
+
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
|
236211
|
+
to.destroyed = destroyed;
|
|
236212
|
+
to.finished = finished;
|
|
236213
|
+
to.length = length;
|
|
236214
|
+
to.pos = pos;
|
|
236215
|
+
if (length % blockLen)
|
|
236216
|
+
to.buffer.set(buffer);
|
|
236217
|
+
return to;
|
|
236218
|
+
}
|
|
236219
|
+
clone() {
|
|
236220
|
+
return this._cloneInto();
|
|
236508
236221
|
}
|
|
236509
236222
|
}
|
|
236510
|
-
|
|
236511
|
-
|
|
236512
|
-
|
|
236513
|
-
|
|
236514
|
-
|
|
236515
|
-
|
|
236516
|
-
|
|
236517
|
-
|
|
236518
|
-
|
|
236519
|
-
|
|
236520
|
-
|
|
236521
|
-
|
|
236522
|
-
|
|
236523
|
-
|
|
236524
|
-
|
|
236525
|
-
|
|
236526
|
-
|
|
236527
|
-
|
|
236528
|
-
|
|
236529
|
-
|
|
236530
|
-
|
|
236531
|
-
|
|
236532
|
-
|
|
236533
|
-
|
|
236534
|
-
|
|
236535
|
-
|
|
236536
|
-
|
|
236537
|
-
|
|
236538
|
-
|
|
236539
|
-
|
|
236540
|
-
|
|
236541
|
-
|
|
236542
|
-
|
|
236543
|
-
|
|
236544
|
-
|
|
236223
|
+
var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
|
|
236224
|
+
1779033703,
|
|
236225
|
+
3144134277,
|
|
236226
|
+
1013904242,
|
|
236227
|
+
2773480762,
|
|
236228
|
+
1359893119,
|
|
236229
|
+
2600822924,
|
|
236230
|
+
528734635,
|
|
236231
|
+
1541459225
|
|
236232
|
+
]);
|
|
236233
|
+
var SHA256_K = /* @__PURE__ */ Uint32Array.from([
|
|
236234
|
+
1116352408,
|
|
236235
|
+
1899447441,
|
|
236236
|
+
3049323471,
|
|
236237
|
+
3921009573,
|
|
236238
|
+
961987163,
|
|
236239
|
+
1508970993,
|
|
236240
|
+
2453635748,
|
|
236241
|
+
2870763221,
|
|
236242
|
+
3624381080,
|
|
236243
|
+
310598401,
|
|
236244
|
+
607225278,
|
|
236245
|
+
1426881987,
|
|
236246
|
+
1925078388,
|
|
236247
|
+
2162078206,
|
|
236248
|
+
2614888103,
|
|
236249
|
+
3248222580,
|
|
236250
|
+
3835390401,
|
|
236251
|
+
4022224774,
|
|
236252
|
+
264347078,
|
|
236253
|
+
604807628,
|
|
236254
|
+
770255983,
|
|
236255
|
+
1249150122,
|
|
236256
|
+
1555081692,
|
|
236257
|
+
1996064986,
|
|
236258
|
+
2554220882,
|
|
236259
|
+
2821834349,
|
|
236260
|
+
2952996808,
|
|
236261
|
+
3210313671,
|
|
236262
|
+
3336571891,
|
|
236263
|
+
3584528711,
|
|
236264
|
+
113926993,
|
|
236265
|
+
338241895,
|
|
236266
|
+
666307205,
|
|
236267
|
+
773529912,
|
|
236268
|
+
1294757372,
|
|
236269
|
+
1396182291,
|
|
236270
|
+
1695183700,
|
|
236271
|
+
1986661051,
|
|
236272
|
+
2177026350,
|
|
236273
|
+
2456956037,
|
|
236274
|
+
2730485921,
|
|
236275
|
+
2820302411,
|
|
236276
|
+
3259730800,
|
|
236277
|
+
3345764771,
|
|
236278
|
+
3516065817,
|
|
236279
|
+
3600352804,
|
|
236280
|
+
4094571909,
|
|
236281
|
+
275423344,
|
|
236282
|
+
430227734,
|
|
236283
|
+
506948616,
|
|
236284
|
+
659060556,
|
|
236285
|
+
883997877,
|
|
236286
|
+
958139571,
|
|
236287
|
+
1322822218,
|
|
236288
|
+
1537002063,
|
|
236289
|
+
1747873779,
|
|
236290
|
+
1955562222,
|
|
236291
|
+
2024104815,
|
|
236292
|
+
2227730452,
|
|
236293
|
+
2361852424,
|
|
236294
|
+
2428436474,
|
|
236295
|
+
2756734187,
|
|
236296
|
+
3204031479,
|
|
236297
|
+
3329325298
|
|
236298
|
+
]);
|
|
236299
|
+
var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
|
|
236300
|
+
|
|
236301
|
+
class SHA256 extends HashMD {
|
|
236302
|
+
constructor(outputLen = 32) {
|
|
236303
|
+
super(64, outputLen, 8, false);
|
|
236304
|
+
this.A = SHA256_IV[0] | 0;
|
|
236305
|
+
this.B = SHA256_IV[1] | 0;
|
|
236306
|
+
this.C = SHA256_IV[2] | 0;
|
|
236307
|
+
this.D = SHA256_IV[3] | 0;
|
|
236308
|
+
this.E = SHA256_IV[4] | 0;
|
|
236309
|
+
this.F = SHA256_IV[5] | 0;
|
|
236310
|
+
this.G = SHA256_IV[6] | 0;
|
|
236311
|
+
this.H = SHA256_IV[7] | 0;
|
|
236312
|
+
}
|
|
236313
|
+
get() {
|
|
236314
|
+
const { A: A2, B, C, D, E, F: F2, G, H } = this;
|
|
236315
|
+
return [A2, B, C, D, E, F2, G, H];
|
|
236316
|
+
}
|
|
236317
|
+
set(A2, B, C, D, E, F2, G, H) {
|
|
236318
|
+
this.A = A2 | 0;
|
|
236319
|
+
this.B = B | 0;
|
|
236320
|
+
this.C = C | 0;
|
|
236321
|
+
this.D = D | 0;
|
|
236322
|
+
this.E = E | 0;
|
|
236323
|
+
this.F = F2 | 0;
|
|
236324
|
+
this.G = G | 0;
|
|
236325
|
+
this.H = H | 0;
|
|
236326
|
+
}
|
|
236327
|
+
process(view, offset) {
|
|
236328
|
+
for (let i2 = 0;i2 < 16; i2++, offset += 4)
|
|
236329
|
+
SHA256_W[i2] = view.getUint32(offset, false);
|
|
236330
|
+
for (let i2 = 16;i2 < 64; i2++) {
|
|
236331
|
+
const W15 = SHA256_W[i2 - 15];
|
|
236332
|
+
const W2 = SHA256_W[i2 - 2];
|
|
236333
|
+
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
|
|
236334
|
+
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
|
|
236335
|
+
SHA256_W[i2] = s1 + SHA256_W[i2 - 7] + s0 + SHA256_W[i2 - 16] | 0;
|
|
236336
|
+
}
|
|
236337
|
+
let { A: A2, B, C, D, E, F: F2, G, H } = this;
|
|
236338
|
+
for (let i2 = 0;i2 < 64; i2++) {
|
|
236339
|
+
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
|
|
236340
|
+
const T1 = H + sigma1 + Chi(E, F2, G) + SHA256_K[i2] + SHA256_W[i2] | 0;
|
|
236341
|
+
const sigma0 = rotr(A2, 2) ^ rotr(A2, 13) ^ rotr(A2, 22);
|
|
236342
|
+
const T2 = sigma0 + Maj(A2, B, C) | 0;
|
|
236343
|
+
H = G;
|
|
236344
|
+
G = F2;
|
|
236345
|
+
F2 = E;
|
|
236346
|
+
E = D + T1 | 0;
|
|
236347
|
+
D = C;
|
|
236348
|
+
C = B;
|
|
236349
|
+
B = A2;
|
|
236350
|
+
A2 = T1 + T2 | 0;
|
|
236351
|
+
}
|
|
236352
|
+
A2 = A2 + this.A | 0;
|
|
236353
|
+
B = B + this.B | 0;
|
|
236354
|
+
C = C + this.C | 0;
|
|
236355
|
+
D = D + this.D | 0;
|
|
236356
|
+
E = E + this.E | 0;
|
|
236357
|
+
F2 = F2 + this.F | 0;
|
|
236358
|
+
G = G + this.G | 0;
|
|
236359
|
+
H = H + this.H | 0;
|
|
236360
|
+
this.set(A2, B, C, D, E, F2, G, H);
|
|
236361
|
+
}
|
|
236362
|
+
roundClean() {
|
|
236363
|
+
clean(SHA256_W);
|
|
236364
|
+
}
|
|
236365
|
+
destroy() {
|
|
236366
|
+
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
|
236367
|
+
clean(this.buffer);
|
|
236368
|
+
}
|
|
236545
236369
|
}
|
|
236370
|
+
var sha256 = /* @__PURE__ */ createHasher(() => new SHA256);
|
|
236371
|
+
var sha2562 = sha256;
|
|
236546
236372
|
|
|
236547
|
-
|
|
236548
|
-
|
|
236549
|
-
|
|
236550
|
-
|
|
236373
|
+
class HMAC extends Hash {
|
|
236374
|
+
constructor(hash, _key) {
|
|
236375
|
+
super();
|
|
236376
|
+
this.finished = false;
|
|
236377
|
+
this.destroyed = false;
|
|
236378
|
+
ahash(hash);
|
|
236379
|
+
const key = toBytes(_key);
|
|
236380
|
+
this.iHash = hash.create();
|
|
236381
|
+
if (typeof this.iHash.update !== "function")
|
|
236382
|
+
throw new Error("Expected instance of class which extends utils.Hash");
|
|
236383
|
+
this.blockLen = this.iHash.blockLen;
|
|
236384
|
+
this.outputLen = this.iHash.outputLen;
|
|
236385
|
+
const blockLen = this.blockLen;
|
|
236386
|
+
const pad = new Uint8Array(blockLen);
|
|
236387
|
+
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
236388
|
+
for (let i2 = 0;i2 < pad.length; i2++)
|
|
236389
|
+
pad[i2] ^= 54;
|
|
236390
|
+
this.iHash.update(pad);
|
|
236391
|
+
this.oHash = hash.create();
|
|
236392
|
+
for (let i2 = 0;i2 < pad.length; i2++)
|
|
236393
|
+
pad[i2] ^= 54 ^ 92;
|
|
236394
|
+
this.oHash.update(pad);
|
|
236395
|
+
clean(pad);
|
|
236396
|
+
}
|
|
236397
|
+
update(buf) {
|
|
236398
|
+
aexists(this);
|
|
236399
|
+
this.iHash.update(buf);
|
|
236400
|
+
return this;
|
|
236401
|
+
}
|
|
236402
|
+
digestInto(out) {
|
|
236403
|
+
aexists(this);
|
|
236404
|
+
abytes(out, this.outputLen);
|
|
236405
|
+
this.finished = true;
|
|
236406
|
+
this.iHash.digestInto(out);
|
|
236407
|
+
this.oHash.update(out);
|
|
236408
|
+
this.oHash.digestInto(out);
|
|
236409
|
+
this.destroy();
|
|
236410
|
+
}
|
|
236411
|
+
digest() {
|
|
236412
|
+
const out = new Uint8Array(this.oHash.outputLen);
|
|
236413
|
+
this.digestInto(out);
|
|
236414
|
+
return out;
|
|
236415
|
+
}
|
|
236416
|
+
_cloneInto(to) {
|
|
236417
|
+
to || (to = Object.create(Object.getPrototypeOf(this), {}));
|
|
236418
|
+
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
|
236419
|
+
to = to;
|
|
236420
|
+
to.finished = finished;
|
|
236421
|
+
to.destroyed = destroyed;
|
|
236422
|
+
to.blockLen = blockLen;
|
|
236423
|
+
to.outputLen = outputLen;
|
|
236424
|
+
to.oHash = oHash._cloneInto(to.oHash);
|
|
236425
|
+
to.iHash = iHash._cloneInto(to.iHash);
|
|
236426
|
+
return to;
|
|
236427
|
+
}
|
|
236428
|
+
clone() {
|
|
236429
|
+
return this._cloneInto();
|
|
236430
|
+
}
|
|
236431
|
+
destroy() {
|
|
236432
|
+
this.destroyed = true;
|
|
236433
|
+
this.oHash.destroy();
|
|
236434
|
+
this.iHash.destroy();
|
|
236435
|
+
}
|
|
236436
|
+
}
|
|
236437
|
+
var hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
|
|
236438
|
+
hmac.create = (hash, key) => new HMAC(hash, key);
|
|
236439
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
236440
|
+
var _0n = /* @__PURE__ */ BigInt(0);
|
|
236441
|
+
var _1n = /* @__PURE__ */ BigInt(1);
|
|
236442
|
+
function abool(title, value) {
|
|
236443
|
+
if (typeof value !== "boolean")
|
|
236444
|
+
throw new Error(title + " boolean expected, got " + value);
|
|
236445
|
+
}
|
|
236446
|
+
function numberToHexUnpadded(num) {
|
|
236447
|
+
const hex = num.toString(16);
|
|
236448
|
+
return hex.length & 1 ? "0" + hex : hex;
|
|
236449
|
+
}
|
|
236450
|
+
function hexToNumber(hex) {
|
|
236451
|
+
if (typeof hex !== "string")
|
|
236452
|
+
throw new Error("hex string expected, got " + typeof hex);
|
|
236453
|
+
return hex === "" ? _0n : BigInt("0x" + hex);
|
|
236454
|
+
}
|
|
236455
|
+
function bytesToNumberBE(bytes) {
|
|
236456
|
+
return hexToNumber(bytesToHex(bytes));
|
|
236457
|
+
}
|
|
236458
|
+
function bytesToNumberLE(bytes) {
|
|
236459
|
+
abytes(bytes);
|
|
236460
|
+
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
|
|
236461
|
+
}
|
|
236462
|
+
function numberToBytesBE(n, len) {
|
|
236463
|
+
return hexToBytes(n.toString(16).padStart(len * 2, "0"));
|
|
236464
|
+
}
|
|
236465
|
+
function numberToBytesLE(n, len) {
|
|
236466
|
+
return numberToBytesBE(n, len).reverse();
|
|
236467
|
+
}
|
|
236468
|
+
function ensureBytes(title, hex, expectedLength) {
|
|
236469
|
+
let res;
|
|
236470
|
+
if (typeof hex === "string") {
|
|
236471
|
+
try {
|
|
236472
|
+
res = hexToBytes(hex);
|
|
236473
|
+
} catch (e2) {
|
|
236474
|
+
throw new Error(title + " must be hex string or Uint8Array, cause: " + e2);
|
|
236475
|
+
}
|
|
236476
|
+
} else if (isBytes(hex)) {
|
|
236477
|
+
res = Uint8Array.from(hex);
|
|
236478
|
+
} else {
|
|
236479
|
+
throw new Error(title + " must be hex string or Uint8Array");
|
|
236480
|
+
}
|
|
236481
|
+
const len = res.length;
|
|
236482
|
+
if (typeof expectedLength === "number" && len !== expectedLength)
|
|
236483
|
+
throw new Error(title + " of length " + expectedLength + " expected, got " + len);
|
|
236484
|
+
return res;
|
|
236485
|
+
}
|
|
236486
|
+
var isPosBig = (n) => typeof n === "bigint" && _0n <= n;
|
|
236487
|
+
function inRange(n, min, max) {
|
|
236488
|
+
return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;
|
|
236489
|
+
}
|
|
236490
|
+
function aInRange(title, n, min, max) {
|
|
236491
|
+
if (!inRange(n, min, max))
|
|
236492
|
+
throw new Error("expected valid " + title + ": " + min + " <= n < " + max + ", got " + n);
|
|
236493
|
+
}
|
|
236494
|
+
function bitLen(n) {
|
|
236495
|
+
let len;
|
|
236496
|
+
for (len = 0;n > _0n; n >>= _1n, len += 1)
|
|
236497
|
+
;
|
|
236498
|
+
return len;
|
|
236499
|
+
}
|
|
236500
|
+
var bitMask = (n) => (_1n << BigInt(n)) - _1n;
|
|
236501
|
+
function createHmacDrbg(hashLen, qByteLen, hmacFn) {
|
|
236502
|
+
if (typeof hashLen !== "number" || hashLen < 2)
|
|
236503
|
+
throw new Error("hashLen must be a number");
|
|
236504
|
+
if (typeof qByteLen !== "number" || qByteLen < 2)
|
|
236505
|
+
throw new Error("qByteLen must be a number");
|
|
236506
|
+
if (typeof hmacFn !== "function")
|
|
236507
|
+
throw new Error("hmacFn must be a function");
|
|
236508
|
+
const u8n = (len) => new Uint8Array(len);
|
|
236509
|
+
const u8of = (byte) => Uint8Array.of(byte);
|
|
236510
|
+
let v = u8n(hashLen);
|
|
236511
|
+
let k = u8n(hashLen);
|
|
236512
|
+
let i2 = 0;
|
|
236513
|
+
const reset = () => {
|
|
236514
|
+
v.fill(1);
|
|
236515
|
+
k.fill(0);
|
|
236516
|
+
i2 = 0;
|
|
236517
|
+
};
|
|
236518
|
+
const h2 = (...b) => hmacFn(k, v, ...b);
|
|
236519
|
+
const reseed = (seed = u8n(0)) => {
|
|
236520
|
+
k = h2(u8of(0), seed);
|
|
236521
|
+
v = h2();
|
|
236522
|
+
if (seed.length === 0)
|
|
236523
|
+
return;
|
|
236524
|
+
k = h2(u8of(1), seed);
|
|
236525
|
+
v = h2();
|
|
236526
|
+
};
|
|
236527
|
+
const gen = () => {
|
|
236528
|
+
if (i2++ >= 1000)
|
|
236529
|
+
throw new Error("drbg: tried 1000 values");
|
|
236530
|
+
let len = 0;
|
|
236531
|
+
const out = [];
|
|
236532
|
+
while (len < qByteLen) {
|
|
236533
|
+
v = h2();
|
|
236534
|
+
const sl = v.slice();
|
|
236535
|
+
out.push(sl);
|
|
236536
|
+
len += v.length;
|
|
236537
|
+
}
|
|
236538
|
+
return concatBytes(...out);
|
|
236539
|
+
};
|
|
236540
|
+
const genUntil = (seed, pred) => {
|
|
236541
|
+
reset();
|
|
236542
|
+
reseed(seed);
|
|
236543
|
+
let res = undefined;
|
|
236544
|
+
while (!(res = pred(gen())))
|
|
236545
|
+
reseed();
|
|
236546
|
+
reset();
|
|
236547
|
+
return res;
|
|
236548
|
+
};
|
|
236549
|
+
return genUntil;
|
|
236550
|
+
}
|
|
236551
|
+
function _validateObject(object3, fields, optFields = {}) {
|
|
236552
|
+
if (!object3 || typeof object3 !== "object")
|
|
236553
|
+
throw new Error("expected valid options object");
|
|
236554
|
+
function checkField(fieldName, expectedType, isOpt) {
|
|
236555
|
+
const val = object3[fieldName];
|
|
236556
|
+
if (isOpt && val === undefined)
|
|
236557
|
+
return;
|
|
236558
|
+
const current = typeof val;
|
|
236559
|
+
if (current !== expectedType || val === null)
|
|
236560
|
+
throw new Error(`param "${fieldName}" is invalid: expected ${expectedType}, got ${current}`);
|
|
236561
|
+
}
|
|
236562
|
+
Object.entries(fields).forEach(([k, v]) => checkField(k, v, false));
|
|
236563
|
+
Object.entries(optFields).forEach(([k, v]) => checkField(k, v, true));
|
|
236564
|
+
}
|
|
236565
|
+
function memoized(fn) {
|
|
236566
|
+
const map2 = new WeakMap;
|
|
236567
|
+
return (arg, ...args) => {
|
|
236568
|
+
const val = map2.get(arg);
|
|
236569
|
+
if (val !== undefined)
|
|
236570
|
+
return val;
|
|
236571
|
+
const computed = fn(arg, ...args);
|
|
236572
|
+
map2.set(arg, computed);
|
|
236573
|
+
return computed;
|
|
236574
|
+
};
|
|
236575
|
+
}
|
|
236576
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
236577
|
+
var _0n2 = BigInt(0);
|
|
236578
|
+
var _1n2 = BigInt(1);
|
|
236579
|
+
var _2n = /* @__PURE__ */ BigInt(2);
|
|
236580
|
+
var _3n = /* @__PURE__ */ BigInt(3);
|
|
236581
|
+
var _4n = /* @__PURE__ */ BigInt(4);
|
|
236582
|
+
var _5n = /* @__PURE__ */ BigInt(5);
|
|
236583
|
+
var _8n = /* @__PURE__ */ BigInt(8);
|
|
236584
|
+
function mod(a, b) {
|
|
236585
|
+
const result = a % b;
|
|
236586
|
+
return result >= _0n2 ? result : b + result;
|
|
236587
|
+
}
|
|
236588
|
+
function pow2(x2, power, modulo) {
|
|
236589
|
+
let res = x2;
|
|
236590
|
+
while (power-- > _0n2) {
|
|
236591
|
+
res *= res;
|
|
236592
|
+
res %= modulo;
|
|
236593
|
+
}
|
|
236594
|
+
return res;
|
|
236595
|
+
}
|
|
236596
|
+
function invert(number2, modulo) {
|
|
236597
|
+
if (number2 === _0n2)
|
|
236598
|
+
throw new Error("invert: expected non-zero number");
|
|
236599
|
+
if (modulo <= _0n2)
|
|
236600
|
+
throw new Error("invert: expected positive modulus, got " + modulo);
|
|
236601
|
+
let a = mod(number2, modulo);
|
|
236602
|
+
let b = modulo;
|
|
236603
|
+
let x2 = _0n2, y = _1n2, u = _1n2, v = _0n2;
|
|
236604
|
+
while (a !== _0n2) {
|
|
236605
|
+
const q = b / a;
|
|
236606
|
+
const r2 = b % a;
|
|
236607
|
+
const m2 = x2 - u * q;
|
|
236608
|
+
const n = y - v * q;
|
|
236609
|
+
b = a, a = r2, x2 = u, y = v, u = m2, v = n;
|
|
236610
|
+
}
|
|
236611
|
+
const gcd = b;
|
|
236612
|
+
if (gcd !== _1n2)
|
|
236613
|
+
throw new Error("invert: does not exist");
|
|
236614
|
+
return mod(x2, modulo);
|
|
236615
|
+
}
|
|
236616
|
+
function sqrt3mod4(Fp, n) {
|
|
236617
|
+
const p1div4 = (Fp.ORDER + _1n2) / _4n;
|
|
236618
|
+
const root = Fp.pow(n, p1div4);
|
|
236619
|
+
if (!Fp.eql(Fp.sqr(root), n))
|
|
236620
|
+
throw new Error("Cannot find square root");
|
|
236621
|
+
return root;
|
|
236622
|
+
}
|
|
236623
|
+
function sqrt5mod8(Fp, n) {
|
|
236624
|
+
const p5div8 = (Fp.ORDER - _5n) / _8n;
|
|
236625
|
+
const n2 = Fp.mul(n, _2n);
|
|
236626
|
+
const v = Fp.pow(n2, p5div8);
|
|
236627
|
+
const nv = Fp.mul(n, v);
|
|
236628
|
+
const i2 = Fp.mul(Fp.mul(nv, _2n), v);
|
|
236629
|
+
const root = Fp.mul(nv, Fp.sub(i2, Fp.ONE));
|
|
236630
|
+
if (!Fp.eql(Fp.sqr(root), n))
|
|
236631
|
+
throw new Error("Cannot find square root");
|
|
236632
|
+
return root;
|
|
236633
|
+
}
|
|
236634
|
+
function tonelliShanks(P) {
|
|
236635
|
+
if (P < BigInt(3))
|
|
236636
|
+
throw new Error("sqrt is not defined for small field");
|
|
236637
|
+
let Q = P - _1n2;
|
|
236638
|
+
let S2 = 0;
|
|
236639
|
+
while (Q % _2n === _0n2) {
|
|
236640
|
+
Q /= _2n;
|
|
236641
|
+
S2++;
|
|
236642
|
+
}
|
|
236643
|
+
let Z2 = _2n;
|
|
236644
|
+
const _Fp = Field(P);
|
|
236645
|
+
while (FpLegendre(_Fp, Z2) === 1) {
|
|
236646
|
+
if (Z2++ > 1000)
|
|
236647
|
+
throw new Error("Cannot find square root: probably non-prime P");
|
|
236648
|
+
}
|
|
236649
|
+
if (S2 === 1)
|
|
236650
|
+
return sqrt3mod4;
|
|
236651
|
+
let cc = _Fp.pow(Z2, Q);
|
|
236652
|
+
const Q1div2 = (Q + _1n2) / _2n;
|
|
236653
|
+
return function tonelliSlow(Fp, n) {
|
|
236654
|
+
if (Fp.is0(n))
|
|
236655
|
+
return n;
|
|
236656
|
+
if (FpLegendre(Fp, n) !== 1)
|
|
236657
|
+
throw new Error("Cannot find square root");
|
|
236658
|
+
let M = S2;
|
|
236659
|
+
let c = Fp.mul(Fp.ONE, cc);
|
|
236660
|
+
let t2 = Fp.pow(n, Q);
|
|
236661
|
+
let R = Fp.pow(n, Q1div2);
|
|
236662
|
+
while (!Fp.eql(t2, Fp.ONE)) {
|
|
236663
|
+
if (Fp.is0(t2))
|
|
236664
|
+
return Fp.ZERO;
|
|
236665
|
+
let i2 = 1;
|
|
236666
|
+
let t_tmp = Fp.sqr(t2);
|
|
236667
|
+
while (!Fp.eql(t_tmp, Fp.ONE)) {
|
|
236668
|
+
i2++;
|
|
236669
|
+
t_tmp = Fp.sqr(t_tmp);
|
|
236670
|
+
if (i2 === M)
|
|
236671
|
+
throw new Error("Cannot find square root");
|
|
236672
|
+
}
|
|
236673
|
+
const exponent = _1n2 << BigInt(M - i2 - 1);
|
|
236674
|
+
const b = Fp.pow(c, exponent);
|
|
236675
|
+
M = i2;
|
|
236676
|
+
c = Fp.sqr(b);
|
|
236677
|
+
t2 = Fp.mul(t2, c);
|
|
236678
|
+
R = Fp.mul(R, b);
|
|
236679
|
+
}
|
|
236680
|
+
return R;
|
|
236681
|
+
};
|
|
236682
|
+
}
|
|
236683
|
+
function FpSqrt(P) {
|
|
236684
|
+
if (P % _4n === _3n)
|
|
236685
|
+
return sqrt3mod4;
|
|
236686
|
+
if (P % _8n === _5n)
|
|
236687
|
+
return sqrt5mod8;
|
|
236688
|
+
return tonelliShanks(P);
|
|
236689
|
+
}
|
|
236690
|
+
var FIELD_FIELDS = [
|
|
236691
|
+
"create",
|
|
236692
|
+
"isValid",
|
|
236693
|
+
"is0",
|
|
236694
|
+
"neg",
|
|
236695
|
+
"inv",
|
|
236696
|
+
"sqrt",
|
|
236697
|
+
"sqr",
|
|
236698
|
+
"eql",
|
|
236699
|
+
"add",
|
|
236700
|
+
"sub",
|
|
236701
|
+
"mul",
|
|
236702
|
+
"pow",
|
|
236703
|
+
"div",
|
|
236704
|
+
"addN",
|
|
236705
|
+
"subN",
|
|
236706
|
+
"mulN",
|
|
236707
|
+
"sqrN"
|
|
236708
|
+
];
|
|
236709
|
+
function validateField(field2) {
|
|
236710
|
+
const initial = {
|
|
236711
|
+
ORDER: "bigint",
|
|
236712
|
+
MASK: "bigint",
|
|
236713
|
+
BYTES: "number",
|
|
236714
|
+
BITS: "number"
|
|
236715
|
+
};
|
|
236716
|
+
const opts = FIELD_FIELDS.reduce((map2, val) => {
|
|
236717
|
+
map2[val] = "function";
|
|
236718
|
+
return map2;
|
|
236719
|
+
}, initial);
|
|
236720
|
+
_validateObject(field2, opts);
|
|
236721
|
+
return field2;
|
|
236722
|
+
}
|
|
236723
|
+
function FpPow(Fp, num, power) {
|
|
236724
|
+
if (power < _0n2)
|
|
236725
|
+
throw new Error("invalid exponent, negatives unsupported");
|
|
236726
|
+
if (power === _0n2)
|
|
236727
|
+
return Fp.ONE;
|
|
236728
|
+
if (power === _1n2)
|
|
236729
|
+
return num;
|
|
236730
|
+
let p = Fp.ONE;
|
|
236731
|
+
let d = num;
|
|
236732
|
+
while (power > _0n2) {
|
|
236733
|
+
if (power & _1n2)
|
|
236734
|
+
p = Fp.mul(p, d);
|
|
236735
|
+
d = Fp.sqr(d);
|
|
236736
|
+
power >>= _1n2;
|
|
236737
|
+
}
|
|
236738
|
+
return p;
|
|
236739
|
+
}
|
|
236740
|
+
function FpInvertBatch(Fp, nums, passZero = false) {
|
|
236741
|
+
const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : undefined);
|
|
236742
|
+
const multipliedAcc = nums.reduce((acc, num, i2) => {
|
|
236743
|
+
if (Fp.is0(num))
|
|
236744
|
+
return acc;
|
|
236745
|
+
inverted[i2] = acc;
|
|
236746
|
+
return Fp.mul(acc, num);
|
|
236747
|
+
}, Fp.ONE);
|
|
236748
|
+
const invertedAcc = Fp.inv(multipliedAcc);
|
|
236749
|
+
nums.reduceRight((acc, num, i2) => {
|
|
236750
|
+
if (Fp.is0(num))
|
|
236751
|
+
return acc;
|
|
236752
|
+
inverted[i2] = Fp.mul(acc, inverted[i2]);
|
|
236753
|
+
return Fp.mul(acc, num);
|
|
236754
|
+
}, invertedAcc);
|
|
236755
|
+
return inverted;
|
|
236756
|
+
}
|
|
236757
|
+
function FpLegendre(Fp, n) {
|
|
236758
|
+
const p1mod2 = (Fp.ORDER - _1n2) / _2n;
|
|
236759
|
+
const powered = Fp.pow(n, p1mod2);
|
|
236760
|
+
const yes = Fp.eql(powered, Fp.ONE);
|
|
236761
|
+
const zero = Fp.eql(powered, Fp.ZERO);
|
|
236762
|
+
const no = Fp.eql(powered, Fp.neg(Fp.ONE));
|
|
236763
|
+
if (!yes && !zero && !no)
|
|
236764
|
+
throw new Error("invalid Legendre symbol result");
|
|
236765
|
+
return yes ? 1 : zero ? 0 : -1;
|
|
236766
|
+
}
|
|
236767
|
+
function nLength(n, nBitLength) {
|
|
236768
|
+
if (nBitLength !== undefined)
|
|
236769
|
+
anumber(nBitLength);
|
|
236770
|
+
const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
|
|
236771
|
+
const nByteLength = Math.ceil(_nBitLength / 8);
|
|
236772
|
+
return { nBitLength: _nBitLength, nByteLength };
|
|
236773
|
+
}
|
|
236774
|
+
function Field(ORDER, bitLenOrOpts, isLE = false, opts = {}) {
|
|
236775
|
+
if (ORDER <= _0n2)
|
|
236776
|
+
throw new Error("invalid field: expected ORDER > 0, got " + ORDER);
|
|
236777
|
+
let _nbitLength = undefined;
|
|
236778
|
+
let _sqrt = undefined;
|
|
236779
|
+
if (typeof bitLenOrOpts === "object" && bitLenOrOpts != null) {
|
|
236780
|
+
if (opts.sqrt || isLE)
|
|
236781
|
+
throw new Error("cannot specify opts in two arguments");
|
|
236782
|
+
const _opts = bitLenOrOpts;
|
|
236783
|
+
if (_opts.BITS)
|
|
236784
|
+
_nbitLength = _opts.BITS;
|
|
236785
|
+
if (_opts.sqrt)
|
|
236786
|
+
_sqrt = _opts.sqrt;
|
|
236787
|
+
if (typeof _opts.isLE === "boolean")
|
|
236788
|
+
isLE = _opts.isLE;
|
|
236789
|
+
} else {
|
|
236790
|
+
if (typeof bitLenOrOpts === "number")
|
|
236791
|
+
_nbitLength = bitLenOrOpts;
|
|
236792
|
+
if (opts.sqrt)
|
|
236793
|
+
_sqrt = opts.sqrt;
|
|
236794
|
+
}
|
|
236795
|
+
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, _nbitLength);
|
|
236796
|
+
if (BYTES > 2048)
|
|
236797
|
+
throw new Error("invalid field: expected ORDER of <= 2048 bytes");
|
|
236798
|
+
let sqrtP;
|
|
236799
|
+
const f3 = Object.freeze({
|
|
236800
|
+
ORDER,
|
|
236801
|
+
isLE,
|
|
236802
|
+
BITS,
|
|
236803
|
+
BYTES,
|
|
236804
|
+
MASK: bitMask(BITS),
|
|
236805
|
+
ZERO: _0n2,
|
|
236806
|
+
ONE: _1n2,
|
|
236807
|
+
create: (num) => mod(num, ORDER),
|
|
236808
|
+
isValid: (num) => {
|
|
236809
|
+
if (typeof num !== "bigint")
|
|
236810
|
+
throw new Error("invalid field element: expected bigint, got " + typeof num);
|
|
236811
|
+
return _0n2 <= num && num < ORDER;
|
|
236812
|
+
},
|
|
236813
|
+
is0: (num) => num === _0n2,
|
|
236814
|
+
isValidNot0: (num) => !f3.is0(num) && f3.isValid(num),
|
|
236815
|
+
isOdd: (num) => (num & _1n2) === _1n2,
|
|
236816
|
+
neg: (num) => mod(-num, ORDER),
|
|
236817
|
+
eql: (lhs, rhs) => lhs === rhs,
|
|
236818
|
+
sqr: (num) => mod(num * num, ORDER),
|
|
236819
|
+
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
|
|
236820
|
+
sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
|
|
236821
|
+
mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
|
|
236822
|
+
pow: (num, power) => FpPow(f3, num, power),
|
|
236823
|
+
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
|
|
236824
|
+
sqrN: (num) => num * num,
|
|
236825
|
+
addN: (lhs, rhs) => lhs + rhs,
|
|
236826
|
+
subN: (lhs, rhs) => lhs - rhs,
|
|
236827
|
+
mulN: (lhs, rhs) => lhs * rhs,
|
|
236828
|
+
inv: (num) => invert(num, ORDER),
|
|
236829
|
+
sqrt: _sqrt || ((n) => {
|
|
236830
|
+
if (!sqrtP)
|
|
236831
|
+
sqrtP = FpSqrt(ORDER);
|
|
236832
|
+
return sqrtP(f3, n);
|
|
236833
|
+
}),
|
|
236834
|
+
toBytes: (num) => isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES),
|
|
236835
|
+
fromBytes: (bytes) => {
|
|
236836
|
+
if (bytes.length !== BYTES)
|
|
236837
|
+
throw new Error("Field.fromBytes: expected " + BYTES + " bytes, got " + bytes.length);
|
|
236838
|
+
return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
|
236839
|
+
},
|
|
236840
|
+
invertBatch: (lst) => FpInvertBatch(f3, lst),
|
|
236841
|
+
cmov: (a, b, c) => c ? b : a
|
|
236842
|
+
});
|
|
236843
|
+
return Object.freeze(f3);
|
|
236844
|
+
}
|
|
236845
|
+
function getFieldBytesLength(fieldOrder) {
|
|
236846
|
+
if (typeof fieldOrder !== "bigint")
|
|
236847
|
+
throw new Error("field order must be bigint");
|
|
236848
|
+
const bitLength = fieldOrder.toString(2).length;
|
|
236849
|
+
return Math.ceil(bitLength / 8);
|
|
236850
|
+
}
|
|
236851
|
+
function getMinHashLength(fieldOrder) {
|
|
236852
|
+
const length = getFieldBytesLength(fieldOrder);
|
|
236853
|
+
return length + Math.ceil(length / 2);
|
|
236854
|
+
}
|
|
236855
|
+
function mapHashToField(key, fieldOrder, isLE = false) {
|
|
236856
|
+
const len = key.length;
|
|
236857
|
+
const fieldLen = getFieldBytesLength(fieldOrder);
|
|
236858
|
+
const minLen = getMinHashLength(fieldOrder);
|
|
236859
|
+
if (len < 16 || len < minLen || len > 1024)
|
|
236860
|
+
throw new Error("expected " + minLen + "-1024 bytes of input, got " + len);
|
|
236861
|
+
const num = isLE ? bytesToNumberLE(key) : bytesToNumberBE(key);
|
|
236862
|
+
const reduced = mod(num, fieldOrder - _1n2) + _1n2;
|
|
236863
|
+
return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
|
|
236864
|
+
}
|
|
236865
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
236866
|
+
var _0n3 = BigInt(0);
|
|
236867
|
+
var _1n3 = BigInt(1);
|
|
236868
|
+
function negateCt(condition, item) {
|
|
236869
|
+
const neg = item.negate();
|
|
236870
|
+
return condition ? neg : item;
|
|
236871
|
+
}
|
|
236872
|
+
function normalizeZ(c, property, points) {
|
|
236873
|
+
const getz = property === "pz" ? (p) => p.pz : (p) => p.ez;
|
|
236874
|
+
const toInv = FpInvertBatch(c.Fp, points.map(getz));
|
|
236875
|
+
const affined = points.map((p, i2) => p.toAffine(toInv[i2]));
|
|
236876
|
+
return affined.map(c.fromAffine);
|
|
236877
|
+
}
|
|
236878
|
+
function validateW(W, bits) {
|
|
236879
|
+
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
|
|
236880
|
+
throw new Error("invalid window size, expected [1.." + bits + "], got W=" + W);
|
|
236881
|
+
}
|
|
236882
|
+
function calcWOpts(W, scalarBits) {
|
|
236883
|
+
validateW(W, scalarBits);
|
|
236884
|
+
const windows2 = Math.ceil(scalarBits / W) + 1;
|
|
236885
|
+
const windowSize = 2 ** (W - 1);
|
|
236886
|
+
const maxNumber = 2 ** W;
|
|
236887
|
+
const mask = bitMask(W);
|
|
236888
|
+
const shiftBy = BigInt(W);
|
|
236889
|
+
return { windows: windows2, windowSize, mask, maxNumber, shiftBy };
|
|
236890
|
+
}
|
|
236891
|
+
function calcOffsets(n, window, wOpts) {
|
|
236892
|
+
const { windowSize, mask, maxNumber, shiftBy } = wOpts;
|
|
236893
|
+
let wbits = Number(n & mask);
|
|
236894
|
+
let nextN = n >> shiftBy;
|
|
236895
|
+
if (wbits > windowSize) {
|
|
236896
|
+
wbits -= maxNumber;
|
|
236897
|
+
nextN += _1n3;
|
|
236898
|
+
}
|
|
236899
|
+
const offsetStart = window * windowSize;
|
|
236900
|
+
const offset = offsetStart + Math.abs(wbits) - 1;
|
|
236901
|
+
const isZero = wbits === 0;
|
|
236902
|
+
const isNeg = wbits < 0;
|
|
236903
|
+
const isNegF = window % 2 !== 0;
|
|
236904
|
+
const offsetF = offsetStart;
|
|
236905
|
+
return { nextN, offset, isZero, isNeg, isNegF, offsetF };
|
|
236906
|
+
}
|
|
236907
|
+
function validateMSMPoints(points, c) {
|
|
236908
|
+
if (!Array.isArray(points))
|
|
236909
|
+
throw new Error("array expected");
|
|
236910
|
+
points.forEach((p, i2) => {
|
|
236911
|
+
if (!(p instanceof c))
|
|
236912
|
+
throw new Error("invalid point at index " + i2);
|
|
236913
|
+
});
|
|
236914
|
+
}
|
|
236915
|
+
function validateMSMScalars(scalars, field2) {
|
|
236916
|
+
if (!Array.isArray(scalars))
|
|
236917
|
+
throw new Error("array of scalars expected");
|
|
236918
|
+
scalars.forEach((s2, i2) => {
|
|
236919
|
+
if (!field2.isValid(s2))
|
|
236920
|
+
throw new Error("invalid scalar at index " + i2);
|
|
236921
|
+
});
|
|
236922
|
+
}
|
|
236923
|
+
var pointPrecomputes = new WeakMap;
|
|
236924
|
+
var pointWindowSizes = new WeakMap;
|
|
236925
|
+
function getW(P) {
|
|
236926
|
+
return pointWindowSizes.get(P) || 1;
|
|
236927
|
+
}
|
|
236928
|
+
function assert0(n) {
|
|
236929
|
+
if (n !== _0n3)
|
|
236930
|
+
throw new Error("invalid wNAF");
|
|
236931
|
+
}
|
|
236932
|
+
function wNAF(c, bits) {
|
|
236933
|
+
return {
|
|
236934
|
+
constTimeNegate: negateCt,
|
|
236935
|
+
hasPrecomputes(elm) {
|
|
236936
|
+
return getW(elm) !== 1;
|
|
236937
|
+
},
|
|
236938
|
+
unsafeLadder(elm, n, p = c.ZERO) {
|
|
236939
|
+
let d = elm;
|
|
236940
|
+
while (n > _0n3) {
|
|
236941
|
+
if (n & _1n3)
|
|
236942
|
+
p = p.add(d);
|
|
236943
|
+
d = d.double();
|
|
236944
|
+
n >>= _1n3;
|
|
236945
|
+
}
|
|
236946
|
+
return p;
|
|
236947
|
+
},
|
|
236948
|
+
precomputeWindow(elm, W) {
|
|
236949
|
+
const { windows: windows2, windowSize } = calcWOpts(W, bits);
|
|
236950
|
+
const points = [];
|
|
236951
|
+
let p = elm;
|
|
236952
|
+
let base = p;
|
|
236953
|
+
for (let window = 0;window < windows2; window++) {
|
|
236954
|
+
base = p;
|
|
236955
|
+
points.push(base);
|
|
236956
|
+
for (let i2 = 1;i2 < windowSize; i2++) {
|
|
236957
|
+
base = base.add(p);
|
|
236958
|
+
points.push(base);
|
|
236959
|
+
}
|
|
236960
|
+
p = base.double();
|
|
236961
|
+
}
|
|
236962
|
+
return points;
|
|
236963
|
+
},
|
|
236964
|
+
wNAF(W, precomputes, n) {
|
|
236965
|
+
let p = c.ZERO;
|
|
236966
|
+
let f3 = c.BASE;
|
|
236967
|
+
const wo = calcWOpts(W, bits);
|
|
236968
|
+
for (let window = 0;window < wo.windows; window++) {
|
|
236969
|
+
const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo);
|
|
236970
|
+
n = nextN;
|
|
236971
|
+
if (isZero) {
|
|
236972
|
+
f3 = f3.add(negateCt(isNegF, precomputes[offsetF]));
|
|
236973
|
+
} else {
|
|
236974
|
+
p = p.add(negateCt(isNeg, precomputes[offset]));
|
|
236975
|
+
}
|
|
236976
|
+
}
|
|
236977
|
+
assert0(n);
|
|
236978
|
+
return { p, f: f3 };
|
|
236979
|
+
},
|
|
236980
|
+
wNAFUnsafe(W, precomputes, n, acc = c.ZERO) {
|
|
236981
|
+
const wo = calcWOpts(W, bits);
|
|
236982
|
+
for (let window = 0;window < wo.windows; window++) {
|
|
236983
|
+
if (n === _0n3)
|
|
236984
|
+
break;
|
|
236985
|
+
const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
|
|
236986
|
+
n = nextN;
|
|
236987
|
+
if (isZero) {
|
|
236988
|
+
continue;
|
|
236989
|
+
} else {
|
|
236990
|
+
const item = precomputes[offset];
|
|
236991
|
+
acc = acc.add(isNeg ? item.negate() : item);
|
|
236992
|
+
}
|
|
236993
|
+
}
|
|
236994
|
+
assert0(n);
|
|
236995
|
+
return acc;
|
|
236996
|
+
},
|
|
236997
|
+
getPrecomputes(W, P, transform) {
|
|
236998
|
+
let comp = pointPrecomputes.get(P);
|
|
236999
|
+
if (!comp) {
|
|
237000
|
+
comp = this.precomputeWindow(P, W);
|
|
237001
|
+
if (W !== 1) {
|
|
237002
|
+
if (typeof transform === "function")
|
|
237003
|
+
comp = transform(comp);
|
|
237004
|
+
pointPrecomputes.set(P, comp);
|
|
237005
|
+
}
|
|
237006
|
+
}
|
|
237007
|
+
return comp;
|
|
237008
|
+
},
|
|
237009
|
+
wNAFCached(P, n, transform) {
|
|
237010
|
+
const W = getW(P);
|
|
237011
|
+
return this.wNAF(W, this.getPrecomputes(W, P, transform), n);
|
|
237012
|
+
},
|
|
237013
|
+
wNAFCachedUnsafe(P, n, transform, prev) {
|
|
237014
|
+
const W = getW(P);
|
|
237015
|
+
if (W === 1)
|
|
237016
|
+
return this.unsafeLadder(P, n, prev);
|
|
237017
|
+
return this.wNAFUnsafe(W, this.getPrecomputes(W, P, transform), n, prev);
|
|
237018
|
+
},
|
|
237019
|
+
setWindowSize(P, W) {
|
|
237020
|
+
validateW(W, bits);
|
|
237021
|
+
pointWindowSizes.set(P, W);
|
|
237022
|
+
pointPrecomputes.delete(P);
|
|
237023
|
+
}
|
|
237024
|
+
};
|
|
237025
|
+
}
|
|
237026
|
+
function mulEndoUnsafe(c, point, k1, k2) {
|
|
237027
|
+
let acc = point;
|
|
237028
|
+
let p1 = c.ZERO;
|
|
237029
|
+
let p2 = c.ZERO;
|
|
237030
|
+
while (k1 > _0n3 || k2 > _0n3) {
|
|
237031
|
+
if (k1 & _1n3)
|
|
237032
|
+
p1 = p1.add(acc);
|
|
237033
|
+
if (k2 & _1n3)
|
|
237034
|
+
p2 = p2.add(acc);
|
|
237035
|
+
acc = acc.double();
|
|
237036
|
+
k1 >>= _1n3;
|
|
237037
|
+
k2 >>= _1n3;
|
|
237038
|
+
}
|
|
237039
|
+
return { p1, p2 };
|
|
237040
|
+
}
|
|
237041
|
+
function pippenger(c, fieldN, points, scalars) {
|
|
237042
|
+
validateMSMPoints(points, c);
|
|
237043
|
+
validateMSMScalars(scalars, fieldN);
|
|
237044
|
+
const plength = points.length;
|
|
237045
|
+
const slength = scalars.length;
|
|
237046
|
+
if (plength !== slength)
|
|
237047
|
+
throw new Error("arrays of points and scalars must have equal length");
|
|
237048
|
+
const zero = c.ZERO;
|
|
237049
|
+
const wbits = bitLen(BigInt(plength));
|
|
237050
|
+
let windowSize = 1;
|
|
237051
|
+
if (wbits > 12)
|
|
237052
|
+
windowSize = wbits - 3;
|
|
237053
|
+
else if (wbits > 4)
|
|
237054
|
+
windowSize = wbits - 2;
|
|
237055
|
+
else if (wbits > 0)
|
|
237056
|
+
windowSize = 2;
|
|
237057
|
+
const MASK = bitMask(windowSize);
|
|
237058
|
+
const buckets = new Array(Number(MASK) + 1).fill(zero);
|
|
237059
|
+
const lastBits = Math.floor((fieldN.BITS - 1) / windowSize) * windowSize;
|
|
237060
|
+
let sum = zero;
|
|
237061
|
+
for (let i2 = lastBits;i2 >= 0; i2 -= windowSize) {
|
|
237062
|
+
buckets.fill(zero);
|
|
237063
|
+
for (let j = 0;j < slength; j++) {
|
|
237064
|
+
const scalar = scalars[j];
|
|
237065
|
+
const wbits2 = Number(scalar >> BigInt(i2) & MASK);
|
|
237066
|
+
buckets[wbits2] = buckets[wbits2].add(points[j]);
|
|
237067
|
+
}
|
|
237068
|
+
let resI = zero;
|
|
237069
|
+
for (let j = buckets.length - 1, sumI = zero;j > 0; j--) {
|
|
237070
|
+
sumI = sumI.add(buckets[j]);
|
|
237071
|
+
resI = resI.add(sumI);
|
|
237072
|
+
}
|
|
237073
|
+
sum = sum.add(resI);
|
|
237074
|
+
if (i2 !== 0)
|
|
237075
|
+
for (let j = 0;j < windowSize; j++)
|
|
237076
|
+
sum = sum.double();
|
|
237077
|
+
}
|
|
237078
|
+
return sum;
|
|
237079
|
+
}
|
|
237080
|
+
function createField(order, field2) {
|
|
237081
|
+
if (field2) {
|
|
237082
|
+
if (field2.ORDER !== order)
|
|
237083
|
+
throw new Error("Field.ORDER must match order: Fp == p, Fn == n");
|
|
237084
|
+
validateField(field2);
|
|
237085
|
+
return field2;
|
|
237086
|
+
} else {
|
|
237087
|
+
return Field(order);
|
|
237088
|
+
}
|
|
237089
|
+
}
|
|
237090
|
+
function _createCurveFields(type, CURVE, curveOpts = {}) {
|
|
237091
|
+
if (!CURVE || typeof CURVE !== "object")
|
|
237092
|
+
throw new Error(`expected valid ${type} CURVE object`);
|
|
237093
|
+
for (const p of ["p", "n", "h"]) {
|
|
237094
|
+
const val = CURVE[p];
|
|
237095
|
+
if (!(typeof val === "bigint" && val > _0n3))
|
|
237096
|
+
throw new Error(`CURVE.${p} must be positive bigint`);
|
|
237097
|
+
}
|
|
237098
|
+
const Fp = createField(CURVE.p, curveOpts.Fp);
|
|
237099
|
+
const Fn = createField(CURVE.n, curveOpts.Fn);
|
|
237100
|
+
const _b = type === "weierstrass" ? "b" : "d";
|
|
237101
|
+
const params = ["Gx", "Gy", "a", _b];
|
|
237102
|
+
for (const p of params) {
|
|
237103
|
+
if (!Fp.isValid(CURVE[p]))
|
|
237104
|
+
throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`);
|
|
237105
|
+
}
|
|
237106
|
+
return { Fp, Fn };
|
|
237107
|
+
}
|
|
237108
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
237109
|
+
function validateSigVerOpts(opts) {
|
|
237110
|
+
if (opts.lowS !== undefined)
|
|
237111
|
+
abool("lowS", opts.lowS);
|
|
237112
|
+
if (opts.prehash !== undefined)
|
|
237113
|
+
abool("prehash", opts.prehash);
|
|
237114
|
+
}
|
|
237115
|
+
|
|
237116
|
+
class DERErr extends Error {
|
|
237117
|
+
constructor(m2 = "") {
|
|
237118
|
+
super(m2);
|
|
237119
|
+
}
|
|
237120
|
+
}
|
|
237121
|
+
var DER = {
|
|
237122
|
+
Err: DERErr,
|
|
237123
|
+
_tlv: {
|
|
237124
|
+
encode: (tag, data) => {
|
|
237125
|
+
const { Err: E } = DER;
|
|
237126
|
+
if (tag < 0 || tag > 256)
|
|
237127
|
+
throw new E("tlv.encode: wrong tag");
|
|
237128
|
+
if (data.length & 1)
|
|
237129
|
+
throw new E("tlv.encode: unpadded data");
|
|
237130
|
+
const dataLen = data.length / 2;
|
|
237131
|
+
const len = numberToHexUnpadded(dataLen);
|
|
237132
|
+
if (len.length / 2 & 128)
|
|
237133
|
+
throw new E("tlv.encode: long form length too big");
|
|
237134
|
+
const lenLen = dataLen > 127 ? numberToHexUnpadded(len.length / 2 | 128) : "";
|
|
237135
|
+
const t2 = numberToHexUnpadded(tag);
|
|
237136
|
+
return t2 + lenLen + len + data;
|
|
237137
|
+
},
|
|
237138
|
+
decode(tag, data) {
|
|
237139
|
+
const { Err: E } = DER;
|
|
237140
|
+
let pos = 0;
|
|
237141
|
+
if (tag < 0 || tag > 256)
|
|
237142
|
+
throw new E("tlv.encode: wrong tag");
|
|
237143
|
+
if (data.length < 2 || data[pos++] !== tag)
|
|
237144
|
+
throw new E("tlv.decode: wrong tlv");
|
|
237145
|
+
const first = data[pos++];
|
|
237146
|
+
const isLong = !!(first & 128);
|
|
237147
|
+
let length = 0;
|
|
237148
|
+
if (!isLong)
|
|
237149
|
+
length = first;
|
|
237150
|
+
else {
|
|
237151
|
+
const lenLen = first & 127;
|
|
237152
|
+
if (!lenLen)
|
|
237153
|
+
throw new E("tlv.decode(long): indefinite length not supported");
|
|
237154
|
+
if (lenLen > 4)
|
|
237155
|
+
throw new E("tlv.decode(long): byte length is too big");
|
|
237156
|
+
const lengthBytes = data.subarray(pos, pos + lenLen);
|
|
237157
|
+
if (lengthBytes.length !== lenLen)
|
|
237158
|
+
throw new E("tlv.decode: length bytes not complete");
|
|
237159
|
+
if (lengthBytes[0] === 0)
|
|
237160
|
+
throw new E("tlv.decode(long): zero leftmost byte");
|
|
237161
|
+
for (const b of lengthBytes)
|
|
237162
|
+
length = length << 8 | b;
|
|
237163
|
+
pos += lenLen;
|
|
237164
|
+
if (length < 128)
|
|
237165
|
+
throw new E("tlv.decode(long): not minimal encoding");
|
|
237166
|
+
}
|
|
237167
|
+
const v = data.subarray(pos, pos + length);
|
|
237168
|
+
if (v.length !== length)
|
|
237169
|
+
throw new E("tlv.decode: wrong value length");
|
|
237170
|
+
return { v, l: data.subarray(pos + length) };
|
|
237171
|
+
}
|
|
237172
|
+
},
|
|
237173
|
+
_int: {
|
|
237174
|
+
encode(num) {
|
|
237175
|
+
const { Err: E } = DER;
|
|
237176
|
+
if (num < _0n4)
|
|
237177
|
+
throw new E("integer: negative integers are not allowed");
|
|
237178
|
+
let hex = numberToHexUnpadded(num);
|
|
237179
|
+
if (Number.parseInt(hex[0], 16) & 8)
|
|
237180
|
+
hex = "00" + hex;
|
|
237181
|
+
if (hex.length & 1)
|
|
237182
|
+
throw new E("unexpected DER parsing assertion: unpadded hex");
|
|
237183
|
+
return hex;
|
|
237184
|
+
},
|
|
237185
|
+
decode(data) {
|
|
237186
|
+
const { Err: E } = DER;
|
|
237187
|
+
if (data[0] & 128)
|
|
237188
|
+
throw new E("invalid signature integer: negative");
|
|
237189
|
+
if (data[0] === 0 && !(data[1] & 128))
|
|
237190
|
+
throw new E("invalid signature integer: unnecessary leading zero");
|
|
237191
|
+
return bytesToNumberBE(data);
|
|
237192
|
+
}
|
|
237193
|
+
},
|
|
237194
|
+
toSig(hex) {
|
|
237195
|
+
const { Err: E, _int: int, _tlv: tlv } = DER;
|
|
237196
|
+
const data = ensureBytes("signature", hex);
|
|
237197
|
+
const { v: seqBytes, l: seqLeftBytes } = tlv.decode(48, data);
|
|
237198
|
+
if (seqLeftBytes.length)
|
|
237199
|
+
throw new E("invalid signature: left bytes after parsing");
|
|
237200
|
+
const { v: rBytes, l: rLeftBytes } = tlv.decode(2, seqBytes);
|
|
237201
|
+
const { v: sBytes, l: sLeftBytes } = tlv.decode(2, rLeftBytes);
|
|
237202
|
+
if (sLeftBytes.length)
|
|
237203
|
+
throw new E("invalid signature: left bytes after parsing");
|
|
237204
|
+
return { r: int.decode(rBytes), s: int.decode(sBytes) };
|
|
237205
|
+
},
|
|
237206
|
+
hexFromSig(sig) {
|
|
237207
|
+
const { _tlv: tlv, _int: int } = DER;
|
|
237208
|
+
const rs = tlv.encode(2, int.encode(sig.r));
|
|
237209
|
+
const ss = tlv.encode(2, int.encode(sig.s));
|
|
237210
|
+
const seq = rs + ss;
|
|
237211
|
+
return tlv.encode(48, seq);
|
|
237212
|
+
}
|
|
237213
|
+
};
|
|
237214
|
+
var _0n4 = BigInt(0);
|
|
237215
|
+
var _1n4 = BigInt(1);
|
|
237216
|
+
var _2n2 = BigInt(2);
|
|
237217
|
+
var _3n2 = BigInt(3);
|
|
237218
|
+
var _4n2 = BigInt(4);
|
|
237219
|
+
function _legacyHelperEquat(Fp, a, b) {
|
|
237220
|
+
function weierstrassEquation(x2) {
|
|
237221
|
+
const x22 = Fp.sqr(x2);
|
|
237222
|
+
const x3 = Fp.mul(x22, x2);
|
|
237223
|
+
return Fp.add(Fp.add(x3, Fp.mul(x2, a)), b);
|
|
237224
|
+
}
|
|
237225
|
+
return weierstrassEquation;
|
|
237226
|
+
}
|
|
237227
|
+
function _legacyHelperNormPriv(Fn, allowedPrivateKeyLengths, wrapPrivateKey) {
|
|
237228
|
+
const { BYTES: expected } = Fn;
|
|
237229
|
+
function normPrivateKeyToScalar(key) {
|
|
237230
|
+
let num;
|
|
237231
|
+
if (typeof key === "bigint") {
|
|
237232
|
+
num = key;
|
|
237233
|
+
} else {
|
|
237234
|
+
let bytes = ensureBytes("private key", key);
|
|
237235
|
+
if (allowedPrivateKeyLengths) {
|
|
237236
|
+
if (!allowedPrivateKeyLengths.includes(bytes.length * 2))
|
|
237237
|
+
throw new Error("invalid private key");
|
|
237238
|
+
const padded = new Uint8Array(expected);
|
|
237239
|
+
padded.set(bytes, padded.length - bytes.length);
|
|
237240
|
+
bytes = padded;
|
|
237241
|
+
}
|
|
237242
|
+
try {
|
|
237243
|
+
num = Fn.fromBytes(bytes);
|
|
237244
|
+
} catch (error) {
|
|
237245
|
+
throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
|
|
237246
|
+
}
|
|
237247
|
+
}
|
|
237248
|
+
if (wrapPrivateKey)
|
|
237249
|
+
num = Fn.create(num);
|
|
237250
|
+
if (!Fn.isValidNot0(num))
|
|
237251
|
+
throw new Error("invalid private key: out of range [1..N-1]");
|
|
237252
|
+
return num;
|
|
237253
|
+
}
|
|
237254
|
+
return normPrivateKeyToScalar;
|
|
237255
|
+
}
|
|
237256
|
+
function weierstrassN(CURVE, curveOpts = {}) {
|
|
237257
|
+
const { Fp, Fn } = _createCurveFields("weierstrass", CURVE, curveOpts);
|
|
237258
|
+
const { h: cofactor, n: CURVE_ORDER } = CURVE;
|
|
237259
|
+
_validateObject(curveOpts, {}, {
|
|
237260
|
+
allowInfinityPoint: "boolean",
|
|
237261
|
+
clearCofactor: "function",
|
|
237262
|
+
isTorsionFree: "function",
|
|
237263
|
+
fromBytes: "function",
|
|
237264
|
+
toBytes: "function",
|
|
237265
|
+
endo: "object",
|
|
237266
|
+
wrapPrivateKey: "boolean"
|
|
237267
|
+
});
|
|
237268
|
+
const { endo } = curveOpts;
|
|
237269
|
+
if (endo) {
|
|
237270
|
+
if (!Fp.is0(CURVE.a) || typeof endo.beta !== "bigint" || typeof endo.splitScalar !== "function") {
|
|
237271
|
+
throw new Error('invalid endo: expected "beta": bigint and "splitScalar": function');
|
|
237272
|
+
}
|
|
237273
|
+
}
|
|
237274
|
+
function assertCompressionIsSupported() {
|
|
237275
|
+
if (!Fp.isOdd)
|
|
237276
|
+
throw new Error("compression is not supported: Field does not have .isOdd()");
|
|
237277
|
+
}
|
|
237278
|
+
function pointToBytes(_c, point, isCompressed) {
|
|
237279
|
+
const { x: x2, y } = point.toAffine();
|
|
237280
|
+
const bx = Fp.toBytes(x2);
|
|
237281
|
+
abool("isCompressed", isCompressed);
|
|
237282
|
+
if (isCompressed) {
|
|
237283
|
+
assertCompressionIsSupported();
|
|
237284
|
+
const hasEvenY = !Fp.isOdd(y);
|
|
237285
|
+
return concatBytes(pprefix(hasEvenY), bx);
|
|
237286
|
+
} else {
|
|
237287
|
+
return concatBytes(Uint8Array.of(4), bx, Fp.toBytes(y));
|
|
237288
|
+
}
|
|
237289
|
+
}
|
|
237290
|
+
function pointFromBytes(bytes) {
|
|
237291
|
+
abytes(bytes);
|
|
237292
|
+
const L = Fp.BYTES;
|
|
237293
|
+
const LC = L + 1;
|
|
237294
|
+
const LU = 2 * L + 1;
|
|
237295
|
+
const length = bytes.length;
|
|
237296
|
+
const head = bytes[0];
|
|
237297
|
+
const tail = bytes.subarray(1);
|
|
237298
|
+
if (length === LC && (head === 2 || head === 3)) {
|
|
237299
|
+
const x2 = Fp.fromBytes(tail);
|
|
237300
|
+
if (!Fp.isValid(x2))
|
|
237301
|
+
throw new Error("bad point: is not on curve, wrong x");
|
|
237302
|
+
const y2 = weierstrassEquation(x2);
|
|
237303
|
+
let y;
|
|
237304
|
+
try {
|
|
237305
|
+
y = Fp.sqrt(y2);
|
|
237306
|
+
} catch (sqrtError) {
|
|
237307
|
+
const err = sqrtError instanceof Error ? ": " + sqrtError.message : "";
|
|
237308
|
+
throw new Error("bad point: is not on curve, sqrt error" + err);
|
|
237309
|
+
}
|
|
237310
|
+
assertCompressionIsSupported();
|
|
237311
|
+
const isYOdd = Fp.isOdd(y);
|
|
237312
|
+
const isHeadOdd = (head & 1) === 1;
|
|
237313
|
+
if (isHeadOdd !== isYOdd)
|
|
237314
|
+
y = Fp.neg(y);
|
|
237315
|
+
return { x: x2, y };
|
|
237316
|
+
} else if (length === LU && head === 4) {
|
|
237317
|
+
const x2 = Fp.fromBytes(tail.subarray(L * 0, L * 1));
|
|
237318
|
+
const y = Fp.fromBytes(tail.subarray(L * 1, L * 2));
|
|
237319
|
+
if (!isValidXY(x2, y))
|
|
237320
|
+
throw new Error("bad point: is not on curve");
|
|
237321
|
+
return { x: x2, y };
|
|
237322
|
+
} else {
|
|
237323
|
+
throw new Error(`bad point: got length ${length}, expected compressed=${LC} or uncompressed=${LU}`);
|
|
237324
|
+
}
|
|
237325
|
+
}
|
|
237326
|
+
const toBytes2 = curveOpts.toBytes || pointToBytes;
|
|
237327
|
+
const fromBytes = curveOpts.fromBytes || pointFromBytes;
|
|
237328
|
+
const weierstrassEquation = _legacyHelperEquat(Fp, CURVE.a, CURVE.b);
|
|
237329
|
+
function isValidXY(x2, y) {
|
|
237330
|
+
const left = Fp.sqr(y);
|
|
237331
|
+
const right = weierstrassEquation(x2);
|
|
237332
|
+
return Fp.eql(left, right);
|
|
237333
|
+
}
|
|
237334
|
+
if (!isValidXY(CURVE.Gx, CURVE.Gy))
|
|
237335
|
+
throw new Error("bad curve params: generator point");
|
|
237336
|
+
const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n2), _4n2);
|
|
237337
|
+
const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27));
|
|
237338
|
+
if (Fp.is0(Fp.add(_4a3, _27b2)))
|
|
237339
|
+
throw new Error("bad curve params: a or b");
|
|
237340
|
+
function acoord(title, n, banZero = false) {
|
|
237341
|
+
if (!Fp.isValid(n) || banZero && Fp.is0(n))
|
|
237342
|
+
throw new Error(`bad point coordinate ${title}`);
|
|
237343
|
+
return n;
|
|
237344
|
+
}
|
|
237345
|
+
function aprjpoint(other) {
|
|
237346
|
+
if (!(other instanceof Point))
|
|
237347
|
+
throw new Error("ProjectivePoint expected");
|
|
237348
|
+
}
|
|
237349
|
+
const toAffineMemo = memoized((p, iz) => {
|
|
237350
|
+
const { px: x2, py: y, pz: z } = p;
|
|
237351
|
+
if (Fp.eql(z, Fp.ONE))
|
|
237352
|
+
return { x: x2, y };
|
|
237353
|
+
const is0 = p.is0();
|
|
237354
|
+
if (iz == null)
|
|
237355
|
+
iz = is0 ? Fp.ONE : Fp.inv(z);
|
|
237356
|
+
const ax = Fp.mul(x2, iz);
|
|
237357
|
+
const ay = Fp.mul(y, iz);
|
|
237358
|
+
const zz = Fp.mul(z, iz);
|
|
237359
|
+
if (is0)
|
|
237360
|
+
return { x: Fp.ZERO, y: Fp.ZERO };
|
|
237361
|
+
if (!Fp.eql(zz, Fp.ONE))
|
|
237362
|
+
throw new Error("invZ was invalid");
|
|
237363
|
+
return { x: ax, y: ay };
|
|
237364
|
+
});
|
|
237365
|
+
const assertValidMemo = memoized((p) => {
|
|
237366
|
+
if (p.is0()) {
|
|
237367
|
+
if (curveOpts.allowInfinityPoint && !Fp.is0(p.py))
|
|
237368
|
+
return;
|
|
237369
|
+
throw new Error("bad point: ZERO");
|
|
237370
|
+
}
|
|
237371
|
+
const { x: x2, y } = p.toAffine();
|
|
237372
|
+
if (!Fp.isValid(x2) || !Fp.isValid(y))
|
|
237373
|
+
throw new Error("bad point: x or y not field elements");
|
|
237374
|
+
if (!isValidXY(x2, y))
|
|
237375
|
+
throw new Error("bad point: equation left != right");
|
|
237376
|
+
if (!p.isTorsionFree())
|
|
237377
|
+
throw new Error("bad point: not in prime-order subgroup");
|
|
237378
|
+
return true;
|
|
237379
|
+
});
|
|
237380
|
+
function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) {
|
|
237381
|
+
k2p = new Point(Fp.mul(k2p.px, endoBeta), k2p.py, k2p.pz);
|
|
237382
|
+
k1p = negateCt(k1neg, k1p);
|
|
237383
|
+
k2p = negateCt(k2neg, k2p);
|
|
237384
|
+
return k1p.add(k2p);
|
|
237385
|
+
}
|
|
237386
|
+
|
|
237387
|
+
class Point {
|
|
237388
|
+
constructor(px, py, pz) {
|
|
237389
|
+
this.px = acoord("x", px);
|
|
237390
|
+
this.py = acoord("y", py, true);
|
|
237391
|
+
this.pz = acoord("z", pz);
|
|
237392
|
+
Object.freeze(this);
|
|
237393
|
+
}
|
|
237394
|
+
static fromAffine(p) {
|
|
237395
|
+
const { x: x2, y } = p || {};
|
|
237396
|
+
if (!p || !Fp.isValid(x2) || !Fp.isValid(y))
|
|
237397
|
+
throw new Error("invalid affine point");
|
|
237398
|
+
if (p instanceof Point)
|
|
237399
|
+
throw new Error("projective point not allowed");
|
|
237400
|
+
if (Fp.is0(x2) && Fp.is0(y))
|
|
237401
|
+
return Point.ZERO;
|
|
237402
|
+
return new Point(x2, y, Fp.ONE);
|
|
237403
|
+
}
|
|
237404
|
+
get x() {
|
|
237405
|
+
return this.toAffine().x;
|
|
237406
|
+
}
|
|
237407
|
+
get y() {
|
|
237408
|
+
return this.toAffine().y;
|
|
237409
|
+
}
|
|
237410
|
+
static normalizeZ(points) {
|
|
237411
|
+
return normalizeZ(Point, "pz", points);
|
|
237412
|
+
}
|
|
237413
|
+
static fromBytes(bytes) {
|
|
237414
|
+
abytes(bytes);
|
|
237415
|
+
return Point.fromHex(bytes);
|
|
237416
|
+
}
|
|
237417
|
+
static fromHex(hex) {
|
|
237418
|
+
const P = Point.fromAffine(fromBytes(ensureBytes("pointHex", hex)));
|
|
237419
|
+
P.assertValidity();
|
|
237420
|
+
return P;
|
|
237421
|
+
}
|
|
237422
|
+
static fromPrivateKey(privateKey) {
|
|
237423
|
+
const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, curveOpts.allowedPrivateKeyLengths, curveOpts.wrapPrivateKey);
|
|
237424
|
+
return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));
|
|
237425
|
+
}
|
|
237426
|
+
static msm(points, scalars) {
|
|
237427
|
+
return pippenger(Point, Fn, points, scalars);
|
|
237428
|
+
}
|
|
237429
|
+
precompute(windowSize = 8, isLazy = true) {
|
|
237430
|
+
wnaf.setWindowSize(this, windowSize);
|
|
237431
|
+
if (!isLazy)
|
|
237432
|
+
this.multiply(_3n2);
|
|
237433
|
+
return this;
|
|
237434
|
+
}
|
|
237435
|
+
_setWindowSize(windowSize) {
|
|
237436
|
+
this.precompute(windowSize);
|
|
237437
|
+
}
|
|
237438
|
+
assertValidity() {
|
|
237439
|
+
assertValidMemo(this);
|
|
237440
|
+
}
|
|
237441
|
+
hasEvenY() {
|
|
237442
|
+
const { y } = this.toAffine();
|
|
237443
|
+
if (!Fp.isOdd)
|
|
237444
|
+
throw new Error("Field doesn't support isOdd");
|
|
237445
|
+
return !Fp.isOdd(y);
|
|
237446
|
+
}
|
|
237447
|
+
equals(other) {
|
|
237448
|
+
aprjpoint(other);
|
|
237449
|
+
const { px: X1, py: Y1, pz: Z1 } = this;
|
|
237450
|
+
const { px: X2, py: Y2, pz: Z2 } = other;
|
|
237451
|
+
const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
|
|
237452
|
+
const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
|
|
237453
|
+
return U1 && U2;
|
|
237454
|
+
}
|
|
237455
|
+
negate() {
|
|
237456
|
+
return new Point(this.px, Fp.neg(this.py), this.pz);
|
|
237457
|
+
}
|
|
237458
|
+
double() {
|
|
237459
|
+
const { a, b } = CURVE;
|
|
237460
|
+
const b3 = Fp.mul(b, _3n2);
|
|
237461
|
+
const { px: X1, py: Y1, pz: Z1 } = this;
|
|
237462
|
+
let { ZERO: X3, ZERO: Y3, ZERO: Z3 } = Fp;
|
|
237463
|
+
let t0 = Fp.mul(X1, X1);
|
|
237464
|
+
let t1 = Fp.mul(Y1, Y1);
|
|
237465
|
+
let t2 = Fp.mul(Z1, Z1);
|
|
237466
|
+
let t3 = Fp.mul(X1, Y1);
|
|
237467
|
+
t3 = Fp.add(t3, t3);
|
|
237468
|
+
Z3 = Fp.mul(X1, Z1);
|
|
237469
|
+
Z3 = Fp.add(Z3, Z3);
|
|
237470
|
+
X3 = Fp.mul(a, Z3);
|
|
237471
|
+
Y3 = Fp.mul(b3, t2);
|
|
237472
|
+
Y3 = Fp.add(X3, Y3);
|
|
237473
|
+
X3 = Fp.sub(t1, Y3);
|
|
237474
|
+
Y3 = Fp.add(t1, Y3);
|
|
237475
|
+
Y3 = Fp.mul(X3, Y3);
|
|
237476
|
+
X3 = Fp.mul(t3, X3);
|
|
237477
|
+
Z3 = Fp.mul(b3, Z3);
|
|
237478
|
+
t2 = Fp.mul(a, t2);
|
|
237479
|
+
t3 = Fp.sub(t0, t2);
|
|
237480
|
+
t3 = Fp.mul(a, t3);
|
|
237481
|
+
t3 = Fp.add(t3, Z3);
|
|
237482
|
+
Z3 = Fp.add(t0, t0);
|
|
237483
|
+
t0 = Fp.add(Z3, t0);
|
|
237484
|
+
t0 = Fp.add(t0, t2);
|
|
237485
|
+
t0 = Fp.mul(t0, t3);
|
|
237486
|
+
Y3 = Fp.add(Y3, t0);
|
|
237487
|
+
t2 = Fp.mul(Y1, Z1);
|
|
237488
|
+
t2 = Fp.add(t2, t2);
|
|
237489
|
+
t0 = Fp.mul(t2, t3);
|
|
237490
|
+
X3 = Fp.sub(X3, t0);
|
|
237491
|
+
Z3 = Fp.mul(t2, t1);
|
|
237492
|
+
Z3 = Fp.add(Z3, Z3);
|
|
237493
|
+
Z3 = Fp.add(Z3, Z3);
|
|
237494
|
+
return new Point(X3, Y3, Z3);
|
|
237495
|
+
}
|
|
237496
|
+
add(other) {
|
|
237497
|
+
aprjpoint(other);
|
|
237498
|
+
const { px: X1, py: Y1, pz: Z1 } = this;
|
|
237499
|
+
const { px: X2, py: Y2, pz: Z2 } = other;
|
|
237500
|
+
let { ZERO: X3, ZERO: Y3, ZERO: Z3 } = Fp;
|
|
237501
|
+
const a = CURVE.a;
|
|
237502
|
+
const b3 = Fp.mul(CURVE.b, _3n2);
|
|
237503
|
+
let t0 = Fp.mul(X1, X2);
|
|
237504
|
+
let t1 = Fp.mul(Y1, Y2);
|
|
237505
|
+
let t2 = Fp.mul(Z1, Z2);
|
|
237506
|
+
let t3 = Fp.add(X1, Y1);
|
|
237507
|
+
let t4 = Fp.add(X2, Y2);
|
|
237508
|
+
t3 = Fp.mul(t3, t4);
|
|
237509
|
+
t4 = Fp.add(t0, t1);
|
|
237510
|
+
t3 = Fp.sub(t3, t4);
|
|
237511
|
+
t4 = Fp.add(X1, Z1);
|
|
237512
|
+
let t5 = Fp.add(X2, Z2);
|
|
237513
|
+
t4 = Fp.mul(t4, t5);
|
|
237514
|
+
t5 = Fp.add(t0, t2);
|
|
237515
|
+
t4 = Fp.sub(t4, t5);
|
|
237516
|
+
t5 = Fp.add(Y1, Z1);
|
|
237517
|
+
X3 = Fp.add(Y2, Z2);
|
|
237518
|
+
t5 = Fp.mul(t5, X3);
|
|
237519
|
+
X3 = Fp.add(t1, t2);
|
|
237520
|
+
t5 = Fp.sub(t5, X3);
|
|
237521
|
+
Z3 = Fp.mul(a, t4);
|
|
237522
|
+
X3 = Fp.mul(b3, t2);
|
|
237523
|
+
Z3 = Fp.add(X3, Z3);
|
|
237524
|
+
X3 = Fp.sub(t1, Z3);
|
|
237525
|
+
Z3 = Fp.add(t1, Z3);
|
|
237526
|
+
Y3 = Fp.mul(X3, Z3);
|
|
237527
|
+
t1 = Fp.add(t0, t0);
|
|
237528
|
+
t1 = Fp.add(t1, t0);
|
|
237529
|
+
t2 = Fp.mul(a, t2);
|
|
237530
|
+
t4 = Fp.mul(b3, t4);
|
|
237531
|
+
t1 = Fp.add(t1, t2);
|
|
237532
|
+
t2 = Fp.sub(t0, t2);
|
|
237533
|
+
t2 = Fp.mul(a, t2);
|
|
237534
|
+
t4 = Fp.add(t4, t2);
|
|
237535
|
+
t0 = Fp.mul(t1, t4);
|
|
237536
|
+
Y3 = Fp.add(Y3, t0);
|
|
237537
|
+
t0 = Fp.mul(t5, t4);
|
|
237538
|
+
X3 = Fp.mul(t3, X3);
|
|
237539
|
+
X3 = Fp.sub(X3, t0);
|
|
237540
|
+
t0 = Fp.mul(t3, t1);
|
|
237541
|
+
Z3 = Fp.mul(t5, Z3);
|
|
237542
|
+
Z3 = Fp.add(Z3, t0);
|
|
237543
|
+
return new Point(X3, Y3, Z3);
|
|
237544
|
+
}
|
|
237545
|
+
subtract(other) {
|
|
237546
|
+
return this.add(other.negate());
|
|
237547
|
+
}
|
|
237548
|
+
is0() {
|
|
237549
|
+
return this.equals(Point.ZERO);
|
|
237550
|
+
}
|
|
237551
|
+
multiply(scalar) {
|
|
237552
|
+
const { endo: endo2 } = curveOpts;
|
|
237553
|
+
if (!Fn.isValidNot0(scalar))
|
|
237554
|
+
throw new Error("invalid scalar: out of range");
|
|
237555
|
+
let point, fake;
|
|
237556
|
+
const mul = (n) => wnaf.wNAFCached(this, n, Point.normalizeZ);
|
|
237557
|
+
if (endo2) {
|
|
237558
|
+
const { k1neg, k1, k2neg, k2 } = endo2.splitScalar(scalar);
|
|
237559
|
+
const { p: k1p, f: k1f } = mul(k1);
|
|
237560
|
+
const { p: k2p, f: k2f } = mul(k2);
|
|
237561
|
+
fake = k1f.add(k2f);
|
|
237562
|
+
point = finishEndo(endo2.beta, k1p, k2p, k1neg, k2neg);
|
|
237563
|
+
} else {
|
|
237564
|
+
const { p, f: f3 } = mul(scalar);
|
|
237565
|
+
point = p;
|
|
237566
|
+
fake = f3;
|
|
237567
|
+
}
|
|
237568
|
+
return Point.normalizeZ([point, fake])[0];
|
|
237569
|
+
}
|
|
237570
|
+
multiplyUnsafe(sc) {
|
|
237571
|
+
const { endo: endo2 } = curveOpts;
|
|
237572
|
+
const p = this;
|
|
237573
|
+
if (!Fn.isValid(sc))
|
|
237574
|
+
throw new Error("invalid scalar: out of range");
|
|
237575
|
+
if (sc === _0n4 || p.is0())
|
|
237576
|
+
return Point.ZERO;
|
|
237577
|
+
if (sc === _1n4)
|
|
237578
|
+
return p;
|
|
237579
|
+
if (wnaf.hasPrecomputes(this))
|
|
237580
|
+
return this.multiply(sc);
|
|
237581
|
+
if (endo2) {
|
|
237582
|
+
const { k1neg, k1, k2neg, k2 } = endo2.splitScalar(sc);
|
|
237583
|
+
const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2);
|
|
237584
|
+
return finishEndo(endo2.beta, p1, p2, k1neg, k2neg);
|
|
237585
|
+
} else {
|
|
237586
|
+
return wnaf.wNAFCachedUnsafe(p, sc);
|
|
237587
|
+
}
|
|
237588
|
+
}
|
|
237589
|
+
multiplyAndAddUnsafe(Q, a, b) {
|
|
237590
|
+
const sum = this.multiplyUnsafe(a).add(Q.multiplyUnsafe(b));
|
|
237591
|
+
return sum.is0() ? undefined : sum;
|
|
237592
|
+
}
|
|
237593
|
+
toAffine(invertedZ) {
|
|
237594
|
+
return toAffineMemo(this, invertedZ);
|
|
237595
|
+
}
|
|
237596
|
+
isTorsionFree() {
|
|
237597
|
+
const { isTorsionFree } = curveOpts;
|
|
237598
|
+
if (cofactor === _1n4)
|
|
237599
|
+
return true;
|
|
237600
|
+
if (isTorsionFree)
|
|
237601
|
+
return isTorsionFree(Point, this);
|
|
237602
|
+
return wnaf.wNAFCachedUnsafe(this, CURVE_ORDER).is0();
|
|
237603
|
+
}
|
|
237604
|
+
clearCofactor() {
|
|
237605
|
+
const { clearCofactor } = curveOpts;
|
|
237606
|
+
if (cofactor === _1n4)
|
|
237607
|
+
return this;
|
|
237608
|
+
if (clearCofactor)
|
|
237609
|
+
return clearCofactor(Point, this);
|
|
237610
|
+
return this.multiplyUnsafe(cofactor);
|
|
237611
|
+
}
|
|
237612
|
+
toBytes(isCompressed = true) {
|
|
237613
|
+
abool("isCompressed", isCompressed);
|
|
237614
|
+
this.assertValidity();
|
|
237615
|
+
return toBytes2(Point, this, isCompressed);
|
|
237616
|
+
}
|
|
237617
|
+
toRawBytes(isCompressed = true) {
|
|
237618
|
+
return this.toBytes(isCompressed);
|
|
237619
|
+
}
|
|
237620
|
+
toHex(isCompressed = true) {
|
|
237621
|
+
return bytesToHex(this.toBytes(isCompressed));
|
|
237622
|
+
}
|
|
237623
|
+
toString() {
|
|
237624
|
+
return `<Point ${this.is0() ? "ZERO" : this.toHex()}>`;
|
|
237625
|
+
}
|
|
237626
|
+
}
|
|
237627
|
+
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
|
|
237628
|
+
Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
|
|
237629
|
+
Point.Fp = Fp;
|
|
237630
|
+
Point.Fn = Fn;
|
|
237631
|
+
const bits = Fn.BITS;
|
|
237632
|
+
const wnaf = wNAF(Point, curveOpts.endo ? Math.ceil(bits / 2) : bits);
|
|
237633
|
+
return Point;
|
|
237634
|
+
}
|
|
237635
|
+
function pprefix(hasEvenY) {
|
|
237636
|
+
return Uint8Array.of(hasEvenY ? 2 : 3);
|
|
237637
|
+
}
|
|
237638
|
+
function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
237639
|
+
_validateObject(ecdsaOpts, { hash: "function" }, {
|
|
237640
|
+
hmac: "function",
|
|
237641
|
+
lowS: "boolean",
|
|
237642
|
+
randomBytes: "function",
|
|
237643
|
+
bits2int: "function",
|
|
237644
|
+
bits2int_modN: "function"
|
|
237645
|
+
});
|
|
237646
|
+
const randomBytes_ = ecdsaOpts.randomBytes || randomBytes;
|
|
237647
|
+
const hmac_ = ecdsaOpts.hmac || ((key, ...msgs) => hmac(ecdsaOpts.hash, key, concatBytes(...msgs)));
|
|
237648
|
+
const { Fp, Fn } = Point;
|
|
237649
|
+
const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
|
|
237650
|
+
function isBiggerThanHalfOrder(number2) {
|
|
237651
|
+
const HALF = CURVE_ORDER >> _1n4;
|
|
237652
|
+
return number2 > HALF;
|
|
237653
|
+
}
|
|
237654
|
+
function normalizeS(s2) {
|
|
237655
|
+
return isBiggerThanHalfOrder(s2) ? Fn.neg(s2) : s2;
|
|
237656
|
+
}
|
|
237657
|
+
function aValidRS(title, num) {
|
|
237658
|
+
if (!Fn.isValidNot0(num))
|
|
237659
|
+
throw new Error(`invalid signature ${title}: out of range 1..CURVE.n`);
|
|
237660
|
+
}
|
|
237661
|
+
|
|
237662
|
+
class Signature {
|
|
237663
|
+
constructor(r2, s2, recovery) {
|
|
237664
|
+
aValidRS("r", r2);
|
|
237665
|
+
aValidRS("s", s2);
|
|
237666
|
+
this.r = r2;
|
|
237667
|
+
this.s = s2;
|
|
237668
|
+
if (recovery != null)
|
|
237669
|
+
this.recovery = recovery;
|
|
237670
|
+
Object.freeze(this);
|
|
237671
|
+
}
|
|
237672
|
+
static fromCompact(hex) {
|
|
237673
|
+
const L = Fn.BYTES;
|
|
237674
|
+
const b = ensureBytes("compactSignature", hex, L * 2);
|
|
237675
|
+
return new Signature(Fn.fromBytes(b.subarray(0, L)), Fn.fromBytes(b.subarray(L, L * 2)));
|
|
237676
|
+
}
|
|
237677
|
+
static fromDER(hex) {
|
|
237678
|
+
const { r: r2, s: s2 } = DER.toSig(ensureBytes("DER", hex));
|
|
237679
|
+
return new Signature(r2, s2);
|
|
237680
|
+
}
|
|
237681
|
+
assertValidity() {}
|
|
237682
|
+
addRecoveryBit(recovery) {
|
|
237683
|
+
return new Signature(this.r, this.s, recovery);
|
|
237684
|
+
}
|
|
237685
|
+
recoverPublicKey(msgHash) {
|
|
237686
|
+
const FIELD_ORDER = Fp.ORDER;
|
|
237687
|
+
const { r: r2, s: s2, recovery: rec } = this;
|
|
237688
|
+
if (rec == null || ![0, 1, 2, 3].includes(rec))
|
|
237689
|
+
throw new Error("recovery id invalid");
|
|
237690
|
+
const hasCofactor = CURVE_ORDER * _2n2 < FIELD_ORDER;
|
|
237691
|
+
if (hasCofactor && rec > 1)
|
|
237692
|
+
throw new Error("recovery id is ambiguous for h>1 curve");
|
|
237693
|
+
const radj = rec === 2 || rec === 3 ? r2 + CURVE_ORDER : r2;
|
|
237694
|
+
if (!Fp.isValid(radj))
|
|
237695
|
+
throw new Error("recovery id 2 or 3 invalid");
|
|
237696
|
+
const x2 = Fp.toBytes(radj);
|
|
237697
|
+
const R = Point.fromHex(concatBytes(pprefix((rec & 1) === 0), x2));
|
|
237698
|
+
const ir = Fn.inv(radj);
|
|
237699
|
+
const h2 = bits2int_modN(ensureBytes("msgHash", msgHash));
|
|
237700
|
+
const u1 = Fn.create(-h2 * ir);
|
|
237701
|
+
const u2 = Fn.create(s2 * ir);
|
|
237702
|
+
const Q = Point.BASE.multiplyUnsafe(u1).add(R.multiplyUnsafe(u2));
|
|
237703
|
+
if (Q.is0())
|
|
237704
|
+
throw new Error("point at infinify");
|
|
237705
|
+
Q.assertValidity();
|
|
237706
|
+
return Q;
|
|
237707
|
+
}
|
|
237708
|
+
hasHighS() {
|
|
237709
|
+
return isBiggerThanHalfOrder(this.s);
|
|
237710
|
+
}
|
|
237711
|
+
normalizeS() {
|
|
237712
|
+
return this.hasHighS() ? new Signature(this.r, Fn.neg(this.s), this.recovery) : this;
|
|
237713
|
+
}
|
|
237714
|
+
toBytes(format) {
|
|
237715
|
+
if (format === "compact")
|
|
237716
|
+
return concatBytes(Fn.toBytes(this.r), Fn.toBytes(this.s));
|
|
237717
|
+
if (format === "der")
|
|
237718
|
+
return hexToBytes(DER.hexFromSig(this));
|
|
237719
|
+
throw new Error("invalid format");
|
|
237720
|
+
}
|
|
237721
|
+
toDERRawBytes() {
|
|
237722
|
+
return this.toBytes("der");
|
|
237723
|
+
}
|
|
237724
|
+
toDERHex() {
|
|
237725
|
+
return bytesToHex(this.toBytes("der"));
|
|
237726
|
+
}
|
|
237727
|
+
toCompactRawBytes() {
|
|
237728
|
+
return this.toBytes("compact");
|
|
237729
|
+
}
|
|
237730
|
+
toCompactHex() {
|
|
237731
|
+
return bytesToHex(this.toBytes("compact"));
|
|
237732
|
+
}
|
|
237733
|
+
}
|
|
237734
|
+
const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, curveOpts.allowedPrivateKeyLengths, curveOpts.wrapPrivateKey);
|
|
237735
|
+
const utils = {
|
|
237736
|
+
isValidPrivateKey(privateKey) {
|
|
237737
|
+
try {
|
|
237738
|
+
normPrivateKeyToScalar(privateKey);
|
|
237739
|
+
return true;
|
|
237740
|
+
} catch (error) {
|
|
237741
|
+
return false;
|
|
237742
|
+
}
|
|
237743
|
+
},
|
|
237744
|
+
normPrivateKeyToScalar,
|
|
237745
|
+
randomPrivateKey: () => {
|
|
237746
|
+
const n = CURVE_ORDER;
|
|
237747
|
+
return mapHashToField(randomBytes_(getMinHashLength(n)), n);
|
|
237748
|
+
},
|
|
237749
|
+
precompute(windowSize = 8, point = Point.BASE) {
|
|
237750
|
+
return point.precompute(windowSize, false);
|
|
237751
|
+
}
|
|
237752
|
+
};
|
|
237753
|
+
function getPublicKey(privateKey, isCompressed = true) {
|
|
237754
|
+
return Point.fromPrivateKey(privateKey).toBytes(isCompressed);
|
|
237755
|
+
}
|
|
237756
|
+
function isProbPub(item) {
|
|
237757
|
+
if (typeof item === "bigint")
|
|
237758
|
+
return false;
|
|
237759
|
+
if (item instanceof Point)
|
|
237760
|
+
return true;
|
|
237761
|
+
const arr = ensureBytes("key", item);
|
|
237762
|
+
const length = arr.length;
|
|
237763
|
+
const L = Fp.BYTES;
|
|
237764
|
+
const LC = L + 1;
|
|
237765
|
+
const LU = 2 * L + 1;
|
|
237766
|
+
if (curveOpts.allowedPrivateKeyLengths || Fn.BYTES === LC) {
|
|
237767
|
+
return;
|
|
237768
|
+
} else {
|
|
237769
|
+
return length === LC || length === LU;
|
|
237770
|
+
}
|
|
237771
|
+
}
|
|
237772
|
+
function getSharedSecret(privateA, publicB, isCompressed = true) {
|
|
237773
|
+
if (isProbPub(privateA) === true)
|
|
237774
|
+
throw new Error("first arg must be private key");
|
|
237775
|
+
if (isProbPub(publicB) === false)
|
|
237776
|
+
throw new Error("second arg must be public key");
|
|
237777
|
+
const b = Point.fromHex(publicB);
|
|
237778
|
+
return b.multiply(normPrivateKeyToScalar(privateA)).toBytes(isCompressed);
|
|
237779
|
+
}
|
|
237780
|
+
const bits2int = ecdsaOpts.bits2int || function(bytes) {
|
|
237781
|
+
if (bytes.length > 8192)
|
|
237782
|
+
throw new Error("input is too large");
|
|
237783
|
+
const num = bytesToNumberBE(bytes);
|
|
237784
|
+
const delta = bytes.length * 8 - fnBits;
|
|
237785
|
+
return delta > 0 ? num >> BigInt(delta) : num;
|
|
237786
|
+
};
|
|
237787
|
+
const bits2int_modN = ecdsaOpts.bits2int_modN || function(bytes) {
|
|
237788
|
+
return Fn.create(bits2int(bytes));
|
|
237789
|
+
};
|
|
237790
|
+
const ORDER_MASK = bitMask(fnBits);
|
|
237791
|
+
function int2octets(num) {
|
|
237792
|
+
aInRange("num < 2^" + fnBits, num, _0n4, ORDER_MASK);
|
|
237793
|
+
return Fn.toBytes(num);
|
|
237794
|
+
}
|
|
237795
|
+
function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
|
|
237796
|
+
if (["recovered", "canonical"].some((k) => (k in opts)))
|
|
237797
|
+
throw new Error("sign() legacy options not supported");
|
|
237798
|
+
const { hash } = ecdsaOpts;
|
|
237799
|
+
let { lowS, prehash, extraEntropy: ent } = opts;
|
|
237800
|
+
if (lowS == null)
|
|
237801
|
+
lowS = true;
|
|
237802
|
+
msgHash = ensureBytes("msgHash", msgHash);
|
|
237803
|
+
validateSigVerOpts(opts);
|
|
237804
|
+
if (prehash)
|
|
237805
|
+
msgHash = ensureBytes("prehashed msgHash", hash(msgHash));
|
|
237806
|
+
const h1int = bits2int_modN(msgHash);
|
|
237807
|
+
const d = normPrivateKeyToScalar(privateKey);
|
|
237808
|
+
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
237809
|
+
if (ent != null && ent !== false) {
|
|
237810
|
+
const e2 = ent === true ? randomBytes_(Fp.BYTES) : ent;
|
|
237811
|
+
seedArgs.push(ensureBytes("extraEntropy", e2));
|
|
237812
|
+
}
|
|
237813
|
+
const seed = concatBytes(...seedArgs);
|
|
237814
|
+
const m2 = h1int;
|
|
237815
|
+
function k2sig(kBytes) {
|
|
237816
|
+
const k = bits2int(kBytes);
|
|
237817
|
+
if (!Fn.isValidNot0(k))
|
|
237818
|
+
return;
|
|
237819
|
+
const ik = Fn.inv(k);
|
|
237820
|
+
const q = Point.BASE.multiply(k).toAffine();
|
|
237821
|
+
const r2 = Fn.create(q.x);
|
|
237822
|
+
if (r2 === _0n4)
|
|
237823
|
+
return;
|
|
237824
|
+
const s2 = Fn.create(ik * Fn.create(m2 + r2 * d));
|
|
237825
|
+
if (s2 === _0n4)
|
|
237826
|
+
return;
|
|
237827
|
+
let recovery = (q.x === r2 ? 0 : 2) | Number(q.y & _1n4);
|
|
237828
|
+
let normS = s2;
|
|
237829
|
+
if (lowS && isBiggerThanHalfOrder(s2)) {
|
|
237830
|
+
normS = normalizeS(s2);
|
|
237831
|
+
recovery ^= 1;
|
|
237832
|
+
}
|
|
237833
|
+
return new Signature(r2, normS, recovery);
|
|
237834
|
+
}
|
|
237835
|
+
return { seed, k2sig };
|
|
237836
|
+
}
|
|
237837
|
+
const defaultSigOpts = { lowS: ecdsaOpts.lowS, prehash: false };
|
|
237838
|
+
const defaultVerOpts = { lowS: ecdsaOpts.lowS, prehash: false };
|
|
237839
|
+
function sign(msgHash, privKey, opts = defaultSigOpts) {
|
|
237840
|
+
const { seed, k2sig } = prepSig(msgHash, privKey, opts);
|
|
237841
|
+
const drbg = createHmacDrbg(ecdsaOpts.hash.outputLen, Fn.BYTES, hmac_);
|
|
237842
|
+
return drbg(seed, k2sig);
|
|
237843
|
+
}
|
|
237844
|
+
Point.BASE.precompute(8);
|
|
237845
|
+
function verify(signature, msgHash, publicKey, opts = defaultVerOpts) {
|
|
237846
|
+
const sg = signature;
|
|
237847
|
+
msgHash = ensureBytes("msgHash", msgHash);
|
|
237848
|
+
publicKey = ensureBytes("publicKey", publicKey);
|
|
237849
|
+
validateSigVerOpts(opts);
|
|
237850
|
+
const { lowS, prehash, format } = opts;
|
|
237851
|
+
if ("strict" in opts)
|
|
237852
|
+
throw new Error("options.strict was renamed to lowS");
|
|
237853
|
+
if (format !== undefined && !["compact", "der", "js"].includes(format))
|
|
237854
|
+
throw new Error('format must be "compact", "der" or "js"');
|
|
237855
|
+
const isHex = typeof sg === "string" || isBytes(sg);
|
|
237856
|
+
const isObj = !isHex && !format && typeof sg === "object" && sg !== null && typeof sg.r === "bigint" && typeof sg.s === "bigint";
|
|
237857
|
+
if (!isHex && !isObj)
|
|
237858
|
+
throw new Error("invalid signature, expected Uint8Array, hex string or Signature instance");
|
|
237859
|
+
let _sig = undefined;
|
|
237860
|
+
let P;
|
|
237861
|
+
try {
|
|
237862
|
+
if (isObj) {
|
|
237863
|
+
if (format === undefined || format === "js") {
|
|
237864
|
+
_sig = new Signature(sg.r, sg.s);
|
|
237865
|
+
} else {
|
|
237866
|
+
throw new Error("invalid format");
|
|
237867
|
+
}
|
|
237868
|
+
}
|
|
237869
|
+
if (isHex) {
|
|
237870
|
+
try {
|
|
237871
|
+
if (format !== "compact")
|
|
237872
|
+
_sig = Signature.fromDER(sg);
|
|
237873
|
+
} catch (derError) {
|
|
237874
|
+
if (!(derError instanceof DER.Err))
|
|
237875
|
+
throw derError;
|
|
237876
|
+
}
|
|
237877
|
+
if (!_sig && format !== "der")
|
|
237878
|
+
_sig = Signature.fromCompact(sg);
|
|
237879
|
+
}
|
|
237880
|
+
P = Point.fromHex(publicKey);
|
|
237881
|
+
} catch (error) {
|
|
237882
|
+
return false;
|
|
237883
|
+
}
|
|
237884
|
+
if (!_sig)
|
|
237885
|
+
return false;
|
|
237886
|
+
if (lowS && _sig.hasHighS())
|
|
237887
|
+
return false;
|
|
237888
|
+
if (prehash)
|
|
237889
|
+
msgHash = ecdsaOpts.hash(msgHash);
|
|
237890
|
+
const { r: r2, s: s2 } = _sig;
|
|
237891
|
+
const h2 = bits2int_modN(msgHash);
|
|
237892
|
+
const is = Fn.inv(s2);
|
|
237893
|
+
const u1 = Fn.create(h2 * is);
|
|
237894
|
+
const u2 = Fn.create(r2 * is);
|
|
237895
|
+
const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
|
|
237896
|
+
if (R.is0())
|
|
237897
|
+
return false;
|
|
237898
|
+
const v = Fn.create(R.x);
|
|
237899
|
+
return v === r2;
|
|
237900
|
+
}
|
|
237901
|
+
return Object.freeze({
|
|
237902
|
+
getPublicKey,
|
|
237903
|
+
getSharedSecret,
|
|
237904
|
+
sign,
|
|
237905
|
+
verify,
|
|
237906
|
+
utils,
|
|
237907
|
+
Point,
|
|
237908
|
+
Signature
|
|
237909
|
+
});
|
|
237910
|
+
}
|
|
237911
|
+
function _weierstrass_legacy_opts_to_new(c) {
|
|
237912
|
+
const CURVE = {
|
|
237913
|
+
a: c.a,
|
|
237914
|
+
b: c.b,
|
|
237915
|
+
p: c.Fp.ORDER,
|
|
237916
|
+
n: c.n,
|
|
237917
|
+
h: c.h,
|
|
237918
|
+
Gx: c.Gx,
|
|
237919
|
+
Gy: c.Gy
|
|
237920
|
+
};
|
|
237921
|
+
const Fp = c.Fp;
|
|
237922
|
+
const Fn = Field(CURVE.n, c.nBitLength);
|
|
237923
|
+
const curveOpts = {
|
|
237924
|
+
Fp,
|
|
237925
|
+
Fn,
|
|
237926
|
+
allowedPrivateKeyLengths: c.allowedPrivateKeyLengths,
|
|
237927
|
+
allowInfinityPoint: c.allowInfinityPoint,
|
|
237928
|
+
endo: c.endo,
|
|
237929
|
+
wrapPrivateKey: c.wrapPrivateKey,
|
|
237930
|
+
isTorsionFree: c.isTorsionFree,
|
|
237931
|
+
clearCofactor: c.clearCofactor,
|
|
237932
|
+
fromBytes: c.fromBytes,
|
|
237933
|
+
toBytes: c.toBytes
|
|
237934
|
+
};
|
|
237935
|
+
return { CURVE, curveOpts };
|
|
237936
|
+
}
|
|
237937
|
+
function _ecdsa_legacy_opts_to_new(c) {
|
|
237938
|
+
const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
|
|
237939
|
+
const ecdsaOpts = {
|
|
237940
|
+
hash: c.hash,
|
|
237941
|
+
hmac: c.hmac,
|
|
237942
|
+
randomBytes: c.randomBytes,
|
|
237943
|
+
lowS: c.lowS,
|
|
237944
|
+
bits2int: c.bits2int,
|
|
237945
|
+
bits2int_modN: c.bits2int_modN
|
|
237946
|
+
};
|
|
237947
|
+
return { CURVE, curveOpts, ecdsaOpts };
|
|
237948
|
+
}
|
|
237949
|
+
function _ecdsa_new_output_to_legacy(c, ecdsa2) {
|
|
237950
|
+
return Object.assign({}, ecdsa2, {
|
|
237951
|
+
ProjectivePoint: ecdsa2.Point,
|
|
237952
|
+
CURVE: c
|
|
237953
|
+
});
|
|
237954
|
+
}
|
|
237955
|
+
function weierstrass(c) {
|
|
237956
|
+
const { CURVE, curveOpts, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
|
|
237957
|
+
const Point = weierstrassN(CURVE, curveOpts);
|
|
237958
|
+
const signs = ecdsa(Point, ecdsaOpts, curveOpts);
|
|
237959
|
+
return _ecdsa_new_output_to_legacy(c, signs);
|
|
237960
|
+
}
|
|
237961
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
237962
|
+
function createCurve(curveDef, defHash) {
|
|
237963
|
+
const create = (hash) => weierstrass({ ...curveDef, hash });
|
|
237964
|
+
return { ...create(defHash), create };
|
|
237965
|
+
}
|
|
237966
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
237967
|
+
var secp256k1_CURVE = {
|
|
237968
|
+
p: BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),
|
|
237969
|
+
n: BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),
|
|
237970
|
+
h: BigInt(1),
|
|
237971
|
+
a: BigInt(0),
|
|
237972
|
+
b: BigInt(7),
|
|
237973
|
+
Gx: BigInt("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),
|
|
237974
|
+
Gy: BigInt("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")
|
|
237975
|
+
};
|
|
237976
|
+
var _0n5 = BigInt(0);
|
|
237977
|
+
var _1n5 = BigInt(1);
|
|
237978
|
+
var _2n3 = BigInt(2);
|
|
237979
|
+
var divNearest = (a, b) => (a + b / _2n3) / b;
|
|
237980
|
+
function sqrtMod(y) {
|
|
237981
|
+
const P = secp256k1_CURVE.p;
|
|
237982
|
+
const _3n3 = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22);
|
|
237983
|
+
const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88);
|
|
237984
|
+
const b2 = y * y * y % P;
|
|
237985
|
+
const b3 = b2 * b2 * y % P;
|
|
237986
|
+
const b6 = pow2(b3, _3n3, P) * b3 % P;
|
|
237987
|
+
const b9 = pow2(b6, _3n3, P) * b3 % P;
|
|
237988
|
+
const b11 = pow2(b9, _2n3, P) * b2 % P;
|
|
237989
|
+
const b22 = pow2(b11, _11n, P) * b11 % P;
|
|
237990
|
+
const b44 = pow2(b22, _22n, P) * b22 % P;
|
|
237991
|
+
const b88 = pow2(b44, _44n, P) * b44 % P;
|
|
237992
|
+
const b176 = pow2(b88, _88n, P) * b88 % P;
|
|
237993
|
+
const b220 = pow2(b176, _44n, P) * b44 % P;
|
|
237994
|
+
const b223 = pow2(b220, _3n3, P) * b3 % P;
|
|
237995
|
+
const t1 = pow2(b223, _23n, P) * b22 % P;
|
|
237996
|
+
const t2 = pow2(t1, _6n, P) * b2 % P;
|
|
237997
|
+
const root = pow2(t2, _2n3, P);
|
|
237998
|
+
if (!Fpk1.eql(Fpk1.sqr(root), y))
|
|
237999
|
+
throw new Error("Cannot find square root");
|
|
238000
|
+
return root;
|
|
238001
|
+
}
|
|
238002
|
+
var Fpk1 = Field(secp256k1_CURVE.p, undefined, undefined, { sqrt: sqrtMod });
|
|
238003
|
+
var secp256k1 = createCurve({
|
|
238004
|
+
...secp256k1_CURVE,
|
|
238005
|
+
Fp: Fpk1,
|
|
238006
|
+
lowS: true,
|
|
238007
|
+
endo: {
|
|
238008
|
+
beta: BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),
|
|
238009
|
+
splitScalar: (k) => {
|
|
238010
|
+
const n = secp256k1_CURVE.n;
|
|
238011
|
+
const a1 = BigInt("0x3086d221a7d46bcde86c90e49284eb15");
|
|
238012
|
+
const b1 = -_1n5 * BigInt("0xe4437ed6010e88286f547fa90abfe4c3");
|
|
238013
|
+
const a2 = BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8");
|
|
238014
|
+
const b2 = a1;
|
|
238015
|
+
const POW_2_128 = BigInt("0x100000000000000000000000000000000");
|
|
238016
|
+
const c1 = divNearest(b2 * k, n);
|
|
238017
|
+
const c2 = divNearest(-b1 * k, n);
|
|
238018
|
+
let k1 = mod(k - c1 * a1 - c2 * a2, n);
|
|
238019
|
+
let k2 = mod(-c1 * b1 - c2 * b2, n);
|
|
238020
|
+
const k1neg = k1 > POW_2_128;
|
|
238021
|
+
const k2neg = k2 > POW_2_128;
|
|
238022
|
+
if (k1neg)
|
|
238023
|
+
k1 = n - k1;
|
|
238024
|
+
if (k2neg)
|
|
238025
|
+
k2 = n - k2;
|
|
238026
|
+
if (k1 > POW_2_128 || k2 > POW_2_128) {
|
|
238027
|
+
throw new Error("splitScalar: Endomorphism failed, k=" + k);
|
|
238028
|
+
}
|
|
238029
|
+
return { k1neg, k1, k2neg, k2 };
|
|
238030
|
+
}
|
|
238031
|
+
}
|
|
238032
|
+
}, sha256);
|
|
238033
|
+
|
|
238034
|
+
class CryptoUtils {
|
|
238035
|
+
static generateKeyPair() {
|
|
238036
|
+
const privateKey = secp256k1.utils.randomPrivateKey();
|
|
238037
|
+
const publicKey = secp256k1.getPublicKey(privateKey);
|
|
238038
|
+
return {
|
|
238039
|
+
privateKey: bytesToHex(privateKey),
|
|
238040
|
+
publicKey: bytesToHex(publicKey)
|
|
238041
|
+
};
|
|
238042
|
+
}
|
|
238043
|
+
static getPublicKeyFromPrivate(privateKeyHex) {
|
|
238044
|
+
const privateKey = hexToBytes(privateKeyHex);
|
|
238045
|
+
const publicKey = secp256k1.getPublicKey(privateKey);
|
|
238046
|
+
return bytesToHex(publicKey);
|
|
238047
|
+
}
|
|
238048
|
+
static hash(data) {
|
|
238049
|
+
return bytesToHex(sha2562(data));
|
|
238050
|
+
}
|
|
238051
|
+
static sign(privateKeyHex, messageHash) {
|
|
238052
|
+
const privateKey = hexToBytes(privateKeyHex);
|
|
238053
|
+
const hash = hexToBytes(messageHash);
|
|
238054
|
+
const signature = secp256k1.sign(hash, privateKey);
|
|
238055
|
+
return signature.toCompactHex();
|
|
238056
|
+
}
|
|
238057
|
+
static verify(publicKeyHex, messageHash, signatureHex) {
|
|
238058
|
+
try {
|
|
238059
|
+
const publicKey = hexToBytes(publicKeyHex);
|
|
238060
|
+
const hash = hexToBytes(messageHash);
|
|
238061
|
+
return secp256k1.verify(signatureHex, hash, publicKey);
|
|
238062
|
+
} catch {
|
|
238063
|
+
return false;
|
|
238064
|
+
}
|
|
238065
|
+
}
|
|
238066
|
+
static hexToPem(hexKey, type) {
|
|
238067
|
+
let derKey;
|
|
238068
|
+
if (type === "PUBLIC") {
|
|
238069
|
+
const publicKeyBytes = hexToBytes(hexKey);
|
|
238070
|
+
const derPrefix = "3056301006072a8648ce3d020106052b8104000a034200";
|
|
238071
|
+
derKey = derPrefix + hexKey;
|
|
238072
|
+
} else {
|
|
238073
|
+
const privateKeyBytes = hexToBytes(hexKey);
|
|
238074
|
+
const derPrefix = "308184020100301006072a8648ce3d020106052b8104000a046d306b0201010420";
|
|
238075
|
+
const derSuffix = "a144034200" + CryptoUtils.getPublicKeyFromPrivate(hexKey);
|
|
238076
|
+
derKey = derPrefix + hexKey + derSuffix;
|
|
238077
|
+
}
|
|
238078
|
+
const derBytes = hexToBytes(derKey);
|
|
238079
|
+
const base64Key = Buffer.from(derBytes).toString("base64");
|
|
238080
|
+
const keyType = type === "PUBLIC" ? "PUBLIC KEY" : "PRIVATE KEY";
|
|
238081
|
+
const pemLines = base64Key.match(/.{1,64}/g) || [];
|
|
238082
|
+
return [
|
|
238083
|
+
`-----BEGIN ${keyType}-----`,
|
|
238084
|
+
...pemLines,
|
|
238085
|
+
`-----END ${keyType}-----`
|
|
238086
|
+
].join(`
|
|
238087
|
+
`);
|
|
238088
|
+
}
|
|
238089
|
+
static pemToHex(pemKey, type) {
|
|
238090
|
+
const keyType = type === "PUBLIC" ? "PUBLIC KEY" : "PRIVATE KEY";
|
|
238091
|
+
const beginMarker = `-----BEGIN ${keyType}-----`;
|
|
238092
|
+
const endMarker = `-----END ${keyType}-----`;
|
|
238093
|
+
const base64Content = pemKey.replace(beginMarker, "").replace(endMarker, "").replace(/\s+/g, "");
|
|
238094
|
+
const derBytes = Buffer.from(base64Content, "base64");
|
|
238095
|
+
const derHex = bytesToHex(derBytes);
|
|
238096
|
+
if (type === "PUBLIC") {
|
|
238097
|
+
const standardPrefixIndex = derHex.indexOf("034200");
|
|
238098
|
+
if (standardPrefixIndex !== -1) {
|
|
238099
|
+
const publicKeyStart = standardPrefixIndex + 6;
|
|
238100
|
+
return derHex.substring(publicKeyStart, publicKeyStart + 66);
|
|
238101
|
+
}
|
|
238102
|
+
if (derBytes.length === 33 && (derBytes[0] === 2 || derBytes[0] === 3)) {
|
|
238103
|
+
return derHex;
|
|
238104
|
+
}
|
|
238105
|
+
if (derBytes.length === 32) {
|
|
238106
|
+
return "02" + derHex;
|
|
238107
|
+
}
|
|
238108
|
+
if (derBytes.length === 65 && derBytes[0] === 4) {
|
|
238109
|
+
const x2 = derHex.substring(2, 66);
|
|
238110
|
+
const y = derHex.substring(66, 130);
|
|
238111
|
+
const yBigInt = BigInt("0x" + y);
|
|
238112
|
+
const prefix = yBigInt % 2n === 0n ? "02" : "03";
|
|
238113
|
+
return prefix + x2;
|
|
238114
|
+
}
|
|
238115
|
+
if (derBytes.length >= 32 && derBytes.length <= 65) {
|
|
238116
|
+
return derHex;
|
|
238117
|
+
}
|
|
238118
|
+
throw new Error(`Unsupported public key format: ${derBytes.length} bytes`);
|
|
238119
|
+
} else {
|
|
238120
|
+
const privateKeyStart = derHex.indexOf("0420") + 4;
|
|
238121
|
+
return derHex.substring(privateKeyStart, privateKeyStart + 64);
|
|
238122
|
+
}
|
|
238123
|
+
}
|
|
238124
|
+
static isPemFormat(key) {
|
|
238125
|
+
return key.includes("-----BEGIN") && key.includes("-----END");
|
|
238126
|
+
}
|
|
238127
|
+
}
|
|
238128
|
+
var ENACT_DEFAULT_CRITICAL_FIELDS = [
|
|
238129
|
+
{ name: "annotations", required: false, securityCritical: true, description: "Security behavior hints" },
|
|
238130
|
+
{ name: "command", required: true, securityCritical: true, description: "The actual execution payload" },
|
|
238131
|
+
{ name: "description", required: true, securityCritical: true, description: "What the tool claims to do" },
|
|
238132
|
+
{ name: "enact", required: false, securityCritical: true, description: "Protocol version security" },
|
|
238133
|
+
{ name: "env", required: false, securityCritical: true, description: "Environment variables" },
|
|
238134
|
+
{ name: "from", required: false, securityCritical: true, description: "Container image (critical for security)" },
|
|
238135
|
+
{ name: "inputSchema", required: false, securityCritical: true, description: "Defines the attack surface" },
|
|
238136
|
+
{ name: "name", required: true, securityCritical: true, description: "Tool identity (prevents impersonation)" },
|
|
238137
|
+
{ name: "timeout", required: false, securityCritical: true, description: "Prevents DoS attacks" },
|
|
238138
|
+
{ name: "version", required: false, securityCritical: true, description: "Tool version for compatibility" }
|
|
238139
|
+
];
|
|
238140
|
+
var GENERIC_DEFAULT_FIELDS = [
|
|
238141
|
+
{ name: "id", required: true, securityCritical: true, description: "Document identifier" },
|
|
238142
|
+
{ name: "content", required: true, securityCritical: true, description: "Document content" },
|
|
238143
|
+
{ name: "timestamp", required: true, securityCritical: true, description: "Creation timestamp" },
|
|
238144
|
+
{ name: "metadata", required: false, securityCritical: false, description: "Additional metadata" }
|
|
238145
|
+
];
|
|
238146
|
+
|
|
238147
|
+
class FieldSelector {
|
|
238148
|
+
fieldConfigs;
|
|
238149
|
+
constructor(fieldConfigs = GENERIC_DEFAULT_FIELDS) {
|
|
238150
|
+
this.fieldConfigs = fieldConfigs;
|
|
238151
|
+
}
|
|
238152
|
+
createCanonicalObject(document, options = {}) {
|
|
238153
|
+
const {
|
|
238154
|
+
includeFields,
|
|
238155
|
+
excludeFields = [],
|
|
238156
|
+
additionalCriticalFields = [],
|
|
238157
|
+
customFieldConfig
|
|
238158
|
+
} = options;
|
|
238159
|
+
const activeConfig = customFieldConfig || this.fieldConfigs;
|
|
238160
|
+
let fieldsToInclude;
|
|
238161
|
+
if (includeFields) {
|
|
238162
|
+
fieldsToInclude = includeFields;
|
|
238163
|
+
} else {
|
|
238164
|
+
const criticalFields = activeConfig.filter((config) => config.securityCritical).map((config) => config.name);
|
|
238165
|
+
fieldsToInclude = [...criticalFields, ...additionalCriticalFields];
|
|
238166
|
+
}
|
|
238167
|
+
fieldsToInclude = fieldsToInclude.filter((field2) => !excludeFields.includes(field2));
|
|
238168
|
+
this.validateRequiredFields(document, activeConfig, fieldsToInclude);
|
|
238169
|
+
const canonical = {};
|
|
238170
|
+
fieldsToInclude.sort().forEach((fieldName) => {
|
|
238171
|
+
const value = document[fieldName];
|
|
238172
|
+
if (this.isNonEmpty(value)) {
|
|
238173
|
+
canonical[fieldName] = value;
|
|
238174
|
+
}
|
|
238175
|
+
});
|
|
238176
|
+
return canonical;
|
|
238177
|
+
}
|
|
238178
|
+
validateRequiredFields(document, config, fieldsToInclude) {
|
|
238179
|
+
const requiredFieldsToInclude = config.filter((field2) => field2.required && fieldsToInclude.includes(field2.name)).map((field2) => field2.name);
|
|
238180
|
+
for (const requiredField of requiredFieldsToInclude) {
|
|
238181
|
+
if (!document.hasOwnProperty(requiredField) || this.isEmpty(document[requiredField])) {
|
|
238182
|
+
throw new Error(`Required field '${requiredField}' is missing or empty`);
|
|
238183
|
+
}
|
|
238184
|
+
}
|
|
238185
|
+
}
|
|
238186
|
+
isEmpty(value) {
|
|
238187
|
+
if (value === null || value === undefined)
|
|
238188
|
+
return true;
|
|
238189
|
+
if (typeof value === "string" && value === "")
|
|
238190
|
+
return true;
|
|
238191
|
+
if (Array.isArray(value) && value.length === 0)
|
|
238192
|
+
return true;
|
|
238193
|
+
if (typeof value === "object" && Object.keys(value).length === 0)
|
|
238194
|
+
return true;
|
|
238195
|
+
return false;
|
|
238196
|
+
}
|
|
238197
|
+
isNonEmpty(value) {
|
|
238198
|
+
return !this.isEmpty(value);
|
|
238199
|
+
}
|
|
238200
|
+
getFieldConfig() {
|
|
238201
|
+
return [...this.fieldConfigs];
|
|
238202
|
+
}
|
|
238203
|
+
getSecurityCriticalFields() {
|
|
238204
|
+
return this.fieldConfigs.filter((config) => config.securityCritical).map((config) => config.name).sort();
|
|
238205
|
+
}
|
|
238206
|
+
getRequiredFields() {
|
|
238207
|
+
return this.fieldConfigs.filter((config) => config.required).map((config) => config.name).sort();
|
|
238208
|
+
}
|
|
238209
|
+
}
|
|
238210
|
+
var EnactFieldSelector = new FieldSelector(ENACT_DEFAULT_CRITICAL_FIELDS);
|
|
238211
|
+
var GenericFieldSelector = new FieldSelector(GENERIC_DEFAULT_FIELDS);
|
|
238212
|
+
var DEFAULT_SECURITY_CONFIG = {
|
|
238213
|
+
allowLocalUnsigned: true,
|
|
238214
|
+
minimumSignatures: 1
|
|
238215
|
+
};
|
|
238216
|
+
|
|
238217
|
+
class KeyManager {
|
|
238218
|
+
static TRUSTED_KEYS_DIR = path7.join(os4.homedir(), ".enact", "trusted-keys");
|
|
238219
|
+
static PRIVATE_KEYS_DIR = path7.join(os4.homedir(), ".enact", "private-keys");
|
|
238220
|
+
static ensureDirectories() {
|
|
238221
|
+
fs4.mkdirSync(this.TRUSTED_KEYS_DIR, { recursive: true, mode: 493 });
|
|
238222
|
+
fs4.mkdirSync(this.PRIVATE_KEYS_DIR, { recursive: true, mode: 448 });
|
|
238223
|
+
}
|
|
238224
|
+
static getPublicKeyPath(keyId) {
|
|
238225
|
+
return path7.join(this.TRUSTED_KEYS_DIR, `${keyId}-public.pem`);
|
|
238226
|
+
}
|
|
238227
|
+
static getPrivateKeyPath(keyId) {
|
|
238228
|
+
return path7.join(this.PRIVATE_KEYS_DIR, `${keyId}-private.pem`);
|
|
238229
|
+
}
|
|
238230
|
+
static getMetadataPath(keyId) {
|
|
238231
|
+
return path7.join(this.TRUSTED_KEYS_DIR, `${keyId}.meta`);
|
|
238232
|
+
}
|
|
238233
|
+
static generateAndStoreKey(keyId, description) {
|
|
238234
|
+
this.ensureDirectories();
|
|
238235
|
+
if (this.keyExists(keyId)) {
|
|
238236
|
+
throw new Error(`Key with ID '${keyId}' already exists`);
|
|
238237
|
+
}
|
|
238238
|
+
const keyPair = CryptoUtils.generateKeyPair();
|
|
238239
|
+
this.storeKey(keyId, keyPair, description);
|
|
238240
|
+
return keyPair;
|
|
238241
|
+
}
|
|
238242
|
+
static storeKey(keyId, keyPair, description) {
|
|
238243
|
+
this.ensureDirectories();
|
|
238244
|
+
try {
|
|
238245
|
+
const publicKeyPem = CryptoUtils.hexToPem(keyPair.publicKey, "PUBLIC");
|
|
238246
|
+
fs4.writeFileSync(this.getPublicKeyPath(keyId), publicKeyPem, { mode: 420 });
|
|
238247
|
+
const privateKeyPem = CryptoUtils.hexToPem(keyPair.privateKey, "PRIVATE");
|
|
238248
|
+
fs4.writeFileSync(this.getPrivateKeyPath(keyId), privateKeyPem, { mode: 384 });
|
|
238249
|
+
const metadata = {
|
|
238250
|
+
keyId,
|
|
238251
|
+
created: new Date().toISOString(),
|
|
238252
|
+
algorithm: "secp256k1",
|
|
238253
|
+
description
|
|
238254
|
+
};
|
|
238255
|
+
fs4.writeFileSync(this.getMetadataPath(keyId), JSON.stringify(metadata, null, 2), { mode: 420 });
|
|
238256
|
+
} catch (error) {
|
|
238257
|
+
this.removeKey(keyId);
|
|
238258
|
+
throw new Error(`Failed to store key '${keyId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
238259
|
+
}
|
|
238260
|
+
}
|
|
238261
|
+
static getKey(keyId) {
|
|
238262
|
+
try {
|
|
238263
|
+
const publicKeyPath = this.getPublicKeyPath(keyId);
|
|
238264
|
+
const privateKeyPath = this.getPrivateKeyPath(keyId);
|
|
238265
|
+
if (!fs4.existsSync(publicKeyPath) || !fs4.existsSync(privateKeyPath)) {
|
|
238266
|
+
return;
|
|
238267
|
+
}
|
|
238268
|
+
const publicKeyPem = fs4.readFileSync(publicKeyPath, "utf8").trim();
|
|
238269
|
+
const privateKeyPem = fs4.readFileSync(privateKeyPath, "utf8").trim();
|
|
238270
|
+
const publicKey = CryptoUtils.pemToHex(publicKeyPem, "PUBLIC");
|
|
238271
|
+
const privateKey = CryptoUtils.pemToHex(privateKeyPem, "PRIVATE");
|
|
238272
|
+
return { privateKey, publicKey };
|
|
238273
|
+
} catch (error) {
|
|
238274
|
+
console.warn(`Failed to read key '${keyId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
238275
|
+
return;
|
|
238276
|
+
}
|
|
238277
|
+
}
|
|
238278
|
+
static getPublicKey(keyId) {
|
|
238279
|
+
try {
|
|
238280
|
+
const publicKeyPath = this.getPublicKeyPath(keyId);
|
|
238281
|
+
if (!fs4.existsSync(publicKeyPath)) {
|
|
238282
|
+
return;
|
|
238283
|
+
}
|
|
238284
|
+
const publicKeyPem = fs4.readFileSync(publicKeyPath, "utf8").trim();
|
|
238285
|
+
return CryptoUtils.pemToHex(publicKeyPem, "PUBLIC");
|
|
238286
|
+
} catch (error) {
|
|
238287
|
+
console.warn(`Failed to read public key '${keyId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
238288
|
+
return;
|
|
238289
|
+
}
|
|
238290
|
+
}
|
|
238291
|
+
static getKeyMetadata(keyId) {
|
|
238292
|
+
try {
|
|
238293
|
+
const metadataPath = this.getMetadataPath(keyId);
|
|
238294
|
+
if (!fs4.existsSync(metadataPath)) {
|
|
238295
|
+
return;
|
|
238296
|
+
}
|
|
238297
|
+
const metadataJson = fs4.readFileSync(metadataPath, "utf8");
|
|
238298
|
+
return JSON.parse(metadataJson);
|
|
238299
|
+
} catch (error) {
|
|
238300
|
+
console.warn(`Failed to read metadata for key '${keyId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
238301
|
+
return;
|
|
238302
|
+
}
|
|
238303
|
+
}
|
|
238304
|
+
static keyExists(keyId) {
|
|
238305
|
+
const publicKeyPath = this.getPublicKeyPath(keyId);
|
|
238306
|
+
const privateKeyPath = this.getPrivateKeyPath(keyId);
|
|
238307
|
+
return fs4.existsSync(publicKeyPath) && fs4.existsSync(privateKeyPath);
|
|
238308
|
+
}
|
|
238309
|
+
static removeKey(keyId) {
|
|
238310
|
+
try {
|
|
238311
|
+
let removed = false;
|
|
238312
|
+
const publicKeyPath = this.getPublicKeyPath(keyId);
|
|
238313
|
+
if (fs4.existsSync(publicKeyPath)) {
|
|
238314
|
+
fs4.unlinkSync(publicKeyPath);
|
|
238315
|
+
removed = true;
|
|
238316
|
+
}
|
|
238317
|
+
const privateKeyPath = this.getPrivateKeyPath(keyId);
|
|
238318
|
+
if (fs4.existsSync(privateKeyPath)) {
|
|
238319
|
+
fs4.unlinkSync(privateKeyPath);
|
|
238320
|
+
removed = true;
|
|
238321
|
+
}
|
|
238322
|
+
const metadataPath = this.getMetadataPath(keyId);
|
|
238323
|
+
if (fs4.existsSync(metadataPath)) {
|
|
238324
|
+
fs4.unlinkSync(metadataPath);
|
|
238325
|
+
removed = true;
|
|
238326
|
+
}
|
|
238327
|
+
return removed;
|
|
238328
|
+
} catch (error) {
|
|
238329
|
+
console.warn(`Failed to remove key '${keyId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
238330
|
+
return false;
|
|
238331
|
+
}
|
|
238332
|
+
}
|
|
238333
|
+
static listKeys() {
|
|
238334
|
+
try {
|
|
238335
|
+
this.ensureDirectories();
|
|
238336
|
+
const publicFiles = fs4.readdirSync(this.TRUSTED_KEYS_DIR).filter((file) => file.endsWith("-public.pem")).map((file) => file.replace("-public.pem", ""));
|
|
238337
|
+
return publicFiles.filter((keyId) => this.keyExists(keyId));
|
|
238338
|
+
} catch (error) {
|
|
238339
|
+
console.warn(`Failed to list keys: ${error instanceof Error ? error.message : String(error)}`);
|
|
238340
|
+
return [];
|
|
238341
|
+
}
|
|
238342
|
+
}
|
|
238343
|
+
static listTrustedKeys() {
|
|
238344
|
+
try {
|
|
238345
|
+
this.ensureDirectories();
|
|
238346
|
+
return fs4.readdirSync(this.TRUSTED_KEYS_DIR).filter((file) => file.endsWith("-public.pem")).map((file) => file.replace("-public.pem", ""));
|
|
238347
|
+
} catch (error) {
|
|
238348
|
+
console.warn(`Failed to list trusted keys: ${error instanceof Error ? error.message : String(error)}`);
|
|
238349
|
+
return [];
|
|
238350
|
+
}
|
|
238351
|
+
}
|
|
238352
|
+
static getAllTrustedPublicKeys() {
|
|
238353
|
+
try {
|
|
238354
|
+
this.ensureDirectories();
|
|
238355
|
+
return fs4.readdirSync(this.TRUSTED_KEYS_DIR).filter((file) => file.endsWith("-public.pem")).map((file) => {
|
|
238356
|
+
try {
|
|
238357
|
+
const publicKeyPem = fs4.readFileSync(path7.join(this.TRUSTED_KEYS_DIR, file), "utf8").trim();
|
|
238358
|
+
return CryptoUtils.pemToHex(publicKeyPem, "PUBLIC");
|
|
238359
|
+
} catch (error) {
|
|
238360
|
+
console.warn(`Failed to read trusted key file ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
238361
|
+
return null;
|
|
238362
|
+
}
|
|
238363
|
+
}).filter((key) => key !== null);
|
|
238364
|
+
} catch (error) {
|
|
238365
|
+
console.warn(`Failed to get all trusted public keys: ${error instanceof Error ? error.message : String(error)}`);
|
|
238366
|
+
return [];
|
|
238367
|
+
}
|
|
238368
|
+
}
|
|
238369
|
+
static exportKey(keyId) {
|
|
238370
|
+
return this.getKey(keyId);
|
|
238371
|
+
}
|
|
238372
|
+
static importKey(keyId, privateKey, description) {
|
|
238373
|
+
const publicKey = CryptoUtils.getPublicKeyFromPrivate(privateKey);
|
|
238374
|
+
const keyPair = { privateKey, publicKey };
|
|
238375
|
+
this.storeKey(keyId, keyPair, description);
|
|
238376
|
+
return keyPair;
|
|
238377
|
+
}
|
|
238378
|
+
static importPublicKey(keyId, publicKey, description) {
|
|
238379
|
+
this.ensureDirectories();
|
|
238380
|
+
if (this.getPublicKey(keyId)) {
|
|
238381
|
+
throw new Error(`Public key with ID '${keyId}' already exists`);
|
|
238382
|
+
}
|
|
238383
|
+
try {
|
|
238384
|
+
const publicKeyPem = CryptoUtils.hexToPem(publicKey, "PUBLIC");
|
|
238385
|
+
fs4.writeFileSync(this.getPublicKeyPath(keyId), publicKeyPem, { mode: 420 });
|
|
238386
|
+
const metadata = {
|
|
238387
|
+
keyId,
|
|
238388
|
+
created: new Date().toISOString(),
|
|
238389
|
+
algorithm: "secp256k1",
|
|
238390
|
+
description: description || "Imported public key"
|
|
238391
|
+
};
|
|
238392
|
+
fs4.writeFileSync(this.getMetadataPath(keyId), JSON.stringify(metadata, null, 2), { mode: 420 });
|
|
238393
|
+
} catch (error) {
|
|
238394
|
+
try {
|
|
238395
|
+
fs4.unlinkSync(this.getPublicKeyPath(keyId));
|
|
238396
|
+
fs4.unlinkSync(this.getMetadataPath(keyId));
|
|
238397
|
+
} catch {}
|
|
238398
|
+
throw new Error(`Failed to import public key '${keyId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
238399
|
+
}
|
|
238400
|
+
}
|
|
238401
|
+
static getStoragePaths() {
|
|
238402
|
+
return {
|
|
238403
|
+
trustedKeys: this.TRUSTED_KEYS_DIR,
|
|
238404
|
+
privateKeys: this.PRIVATE_KEYS_DIR
|
|
238405
|
+
};
|
|
238406
|
+
}
|
|
238407
|
+
static exportKeyToFile(keyId, outputPath, includePrivateKey = false) {
|
|
238408
|
+
const keyPair = this.getKey(keyId);
|
|
238409
|
+
const metadata = this.getKeyMetadata(keyId);
|
|
238410
|
+
if (!keyPair) {
|
|
238411
|
+
throw new Error(`Key '${keyId}' not found`);
|
|
238412
|
+
}
|
|
238413
|
+
const exportData = {
|
|
238414
|
+
metadata,
|
|
238415
|
+
publicKey: keyPair.publicKey,
|
|
238416
|
+
...includePrivateKey && { privateKey: keyPair.privateKey }
|
|
238417
|
+
};
|
|
238418
|
+
fs4.writeFileSync(outputPath, JSON.stringify(exportData, null, 2), { mode: 384 });
|
|
238419
|
+
}
|
|
238420
|
+
}
|
|
236551
238421
|
|
|
238422
|
+
class SigningService {
|
|
238423
|
+
static signDocument(document, privateKey, options = {}) {
|
|
238424
|
+
const {
|
|
238425
|
+
algorithm = "secp256k1",
|
|
238426
|
+
useEnactDefaults = false,
|
|
238427
|
+
includeFields,
|
|
238428
|
+
excludeFields,
|
|
238429
|
+
additionalCriticalFields
|
|
238430
|
+
} = options;
|
|
238431
|
+
const fieldSelector = useEnactDefaults ? EnactFieldSelector : GenericFieldSelector;
|
|
238432
|
+
const canonicalDocument = fieldSelector.createCanonicalObject(document, {
|
|
238433
|
+
includeFields,
|
|
238434
|
+
excludeFields,
|
|
238435
|
+
additionalCriticalFields
|
|
238436
|
+
});
|
|
238437
|
+
const documentString = JSON.stringify(canonicalDocument);
|
|
238438
|
+
const messageHash = CryptoUtils.hash(documentString);
|
|
238439
|
+
const signature = CryptoUtils.sign(privateKey, messageHash);
|
|
238440
|
+
const publicKey = CryptoUtils.getPublicKeyFromPrivate(privateKey);
|
|
238441
|
+
return {
|
|
238442
|
+
signature,
|
|
238443
|
+
publicKey,
|
|
238444
|
+
algorithm,
|
|
238445
|
+
timestamp: Date.now()
|
|
238446
|
+
};
|
|
238447
|
+
}
|
|
238448
|
+
static verifyDocument(document, signature, options = {}, securityConfig = DEFAULT_SECURITY_CONFIG) {
|
|
238449
|
+
const {
|
|
238450
|
+
useEnactDefaults = false,
|
|
238451
|
+
includeFields,
|
|
238452
|
+
excludeFields,
|
|
238453
|
+
additionalCriticalFields
|
|
238454
|
+
} = options;
|
|
238455
|
+
const config = { ...DEFAULT_SECURITY_CONFIG, ...securityConfig };
|
|
238456
|
+
const signatures = document.signatures || [signature];
|
|
238457
|
+
if (signatures.length < (config.minimumSignatures ?? 1)) {
|
|
238458
|
+
if (config.allowLocalUnsigned && signatures.length === 0) {
|
|
238459
|
+
return true;
|
|
238460
|
+
}
|
|
238461
|
+
return false;
|
|
238462
|
+
}
|
|
238463
|
+
const fieldSelector = useEnactDefaults ? EnactFieldSelector : GenericFieldSelector;
|
|
238464
|
+
const canonicalDocument = fieldSelector.createCanonicalObject(document, {
|
|
238465
|
+
includeFields,
|
|
238466
|
+
excludeFields,
|
|
238467
|
+
additionalCriticalFields
|
|
238468
|
+
});
|
|
238469
|
+
const documentString = JSON.stringify(canonicalDocument);
|
|
238470
|
+
const messageHash = CryptoUtils.hash(documentString);
|
|
238471
|
+
const trustedPublicKeys = KeyManager.getAllTrustedPublicKeys();
|
|
238472
|
+
return signatures.every((sig) => {
|
|
238473
|
+
const hasValidPublicKey = sig.publicKey && typeof sig.publicKey === "string" && sig.publicKey.trim() !== "";
|
|
238474
|
+
if (hasValidPublicKey && trustedPublicKeys.includes(sig.publicKey)) {
|
|
238475
|
+
return CryptoUtils.verify(sig.publicKey, messageHash, sig.signature);
|
|
238476
|
+
} else {
|
|
238477
|
+
return trustedPublicKeys.some((trustedKey) => {
|
|
238478
|
+
try {
|
|
238479
|
+
return CryptoUtils.verify(trustedKey, messageHash, sig.signature);
|
|
238480
|
+
} catch {
|
|
238481
|
+
return false;
|
|
238482
|
+
}
|
|
238483
|
+
});
|
|
238484
|
+
}
|
|
238485
|
+
});
|
|
238486
|
+
}
|
|
238487
|
+
static createDocumentHash(document, options = {}) {
|
|
238488
|
+
const {
|
|
238489
|
+
useEnactDefaults = false,
|
|
238490
|
+
includeFields,
|
|
238491
|
+
excludeFields,
|
|
238492
|
+
additionalCriticalFields
|
|
238493
|
+
} = options;
|
|
238494
|
+
const fieldSelector = useEnactDefaults ? EnactFieldSelector : GenericFieldSelector;
|
|
238495
|
+
const canonicalDocument = fieldSelector.createCanonicalObject(document, {
|
|
238496
|
+
includeFields,
|
|
238497
|
+
excludeFields,
|
|
238498
|
+
additionalCriticalFields
|
|
238499
|
+
});
|
|
238500
|
+
const documentString = JSON.stringify(canonicalDocument);
|
|
238501
|
+
return CryptoUtils.hash(documentString);
|
|
238502
|
+
}
|
|
238503
|
+
static getCanonicalDocument(document, options = {}) {
|
|
238504
|
+
const {
|
|
238505
|
+
useEnactDefaults = false,
|
|
238506
|
+
includeFields,
|
|
238507
|
+
excludeFields,
|
|
238508
|
+
additionalCriticalFields
|
|
238509
|
+
} = options;
|
|
238510
|
+
const fieldSelector = useEnactDefaults ? EnactFieldSelector : GenericFieldSelector;
|
|
238511
|
+
return fieldSelector.createCanonicalObject(document, {
|
|
238512
|
+
includeFields,
|
|
238513
|
+
excludeFields,
|
|
238514
|
+
additionalCriticalFields
|
|
238515
|
+
});
|
|
238516
|
+
}
|
|
238517
|
+
static getSignedFields(options = {}) {
|
|
238518
|
+
const { useEnactDefaults = false } = options;
|
|
238519
|
+
const fieldSelector = useEnactDefaults ? EnactFieldSelector : GenericFieldSelector;
|
|
238520
|
+
return fieldSelector.getSecurityCriticalFields();
|
|
238521
|
+
}
|
|
238522
|
+
}
|
|
238523
|
+
|
|
238524
|
+
// ../shared/dist/core/EnactCore.js
|
|
236552
238525
|
class EnactCore {
|
|
236553
238526
|
constructor(options = {}) {
|
|
236554
238527
|
this.options = {
|
|
@@ -236556,7 +238529,6 @@ class EnactCore {
|
|
|
236556
238529
|
supabaseUrl: "https://xjnhhxwxovjifdxdwzih.supabase.co",
|
|
236557
238530
|
executionProvider: "dagger",
|
|
236558
238531
|
defaultTimeout: "30s",
|
|
236559
|
-
verificationPolicy: "permissive",
|
|
236560
238532
|
...options
|
|
236561
238533
|
};
|
|
236562
238534
|
this.apiClient = new EnactApiClient(this.options.apiUrl, this.options.supabaseUrl);
|
|
@@ -236565,7 +238537,8 @@ class EnactCore {
|
|
|
236565
238537
|
setAuthToken(token) {
|
|
236566
238538
|
this.options.authToken = token;
|
|
236567
238539
|
}
|
|
236568
|
-
async searchTools(options) {
|
|
238540
|
+
static async searchTools(options, coreOptions = {}) {
|
|
238541
|
+
const apiClient = new EnactApiClient(coreOptions.apiUrl || "https://enact.tools", coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co");
|
|
236569
238542
|
try {
|
|
236570
238543
|
logger_default.info(`Searching for tools with query: "${options.query}"`);
|
|
236571
238544
|
const searchParams = {
|
|
@@ -236573,12 +238546,12 @@ class EnactCore {
|
|
|
236573
238546
|
limit: options.limit,
|
|
236574
238547
|
tags: options.tags
|
|
236575
238548
|
};
|
|
236576
|
-
const results = await
|
|
238549
|
+
const results = await apiClient.searchTools(searchParams);
|
|
236577
238550
|
const tools = [];
|
|
236578
238551
|
for (const result of results) {
|
|
236579
238552
|
if (result.name) {
|
|
236580
238553
|
try {
|
|
236581
|
-
const tool = await
|
|
238554
|
+
const tool = await EnactCore.getToolByName(result.name, undefined, coreOptions);
|
|
236582
238555
|
if (tool) {
|
|
236583
238556
|
tools.push(tool);
|
|
236584
238557
|
}
|
|
@@ -236593,15 +238566,19 @@ class EnactCore {
|
|
|
236593
238566
|
logger_default.error("Error searching tools:", error);
|
|
236594
238567
|
if (error instanceof Error && error.message.includes("502")) {
|
|
236595
238568
|
logger_default.info("Search API unavailable, trying fallback to local filtering...");
|
|
236596
|
-
return
|
|
238569
|
+
return EnactCore.searchToolsFallback(options, coreOptions);
|
|
236597
238570
|
}
|
|
236598
238571
|
throw new Error(`Search failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
236599
238572
|
}
|
|
236600
238573
|
}
|
|
236601
|
-
async
|
|
238574
|
+
async searchTools(options) {
|
|
238575
|
+
return EnactCore.searchTools(options, this.options);
|
|
238576
|
+
}
|
|
238577
|
+
static async searchToolsFallback(options, coreOptions = {}) {
|
|
238578
|
+
const apiClient = new EnactApiClient(coreOptions.apiUrl || "https://enact.tools", coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co");
|
|
236602
238579
|
try {
|
|
236603
238580
|
logger_default.info("Using fallback search method...");
|
|
236604
|
-
const allTools = await
|
|
238581
|
+
const allTools = await apiClient.getTools({
|
|
236605
238582
|
limit: options.limit || 100
|
|
236606
238583
|
});
|
|
236607
238584
|
const filteredTools = [];
|
|
@@ -236609,7 +238586,7 @@ class EnactCore {
|
|
|
236609
238586
|
for (const result of allTools) {
|
|
236610
238587
|
if (result.name) {
|
|
236611
238588
|
try {
|
|
236612
|
-
const tool = await
|
|
238589
|
+
const tool = await EnactCore.getToolByName(result.name, undefined, coreOptions);
|
|
236613
238590
|
if (tool) {
|
|
236614
238591
|
const matchesQuery = tool.name.toLowerCase().includes(query) || tool.description && tool.description.toLowerCase().includes(query) || tool.tags && tool.tags.some((tag) => tag.toLowerCase().includes(query));
|
|
236615
238592
|
const matchesTags = !options.tags || !options.tags.length || tool.tags && options.tags.some((searchTag) => tool.tags.some((toolTag) => toolTag.toLowerCase().includes(searchTag.toLowerCase())));
|
|
@@ -236633,26 +238610,43 @@ class EnactCore {
|
|
|
236633
238610
|
throw new Error(`Search failed (including fallback): ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`);
|
|
236634
238611
|
}
|
|
236635
238612
|
}
|
|
236636
|
-
async getToolByName(name, version) {
|
|
238613
|
+
static async getToolByName(name, version, coreOptions = {}) {
|
|
238614
|
+
const apiClient = new EnactApiClient(coreOptions.apiUrl || "https://enact.tools", coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co");
|
|
236637
238615
|
try {
|
|
236638
238616
|
logger_default.info(`Fetching tool: ${name}${version ? `@${version}` : ""}`);
|
|
236639
|
-
const response = await
|
|
238617
|
+
const response = await apiClient.getTool(name);
|
|
236640
238618
|
if (!response) {
|
|
236641
238619
|
logger_default.info(`Tool not found: ${name}`);
|
|
236642
238620
|
return null;
|
|
236643
238621
|
}
|
|
236644
238622
|
let tool;
|
|
236645
|
-
if (response.
|
|
236646
|
-
tool = import_yaml2.default.parse(response.content);
|
|
236647
|
-
} else if (response.raw_content && typeof response.raw_content === "string") {
|
|
238623
|
+
if (response.raw_content && typeof response.raw_content === "string") {
|
|
236648
238624
|
try {
|
|
236649
238625
|
tool = JSON.parse(response.raw_content);
|
|
236650
238626
|
} catch {
|
|
236651
|
-
tool =
|
|
238627
|
+
tool = import_yaml.default.parse(response.raw_content);
|
|
238628
|
+
}
|
|
238629
|
+
if (!tool.signature && response.signature) {
|
|
238630
|
+
tool.signature = response.signature;
|
|
236652
238631
|
}
|
|
236653
|
-
if (
|
|
238632
|
+
if (!tool.signatures && response.signatures) {
|
|
238633
|
+
if (Array.isArray(response.signatures)) {
|
|
238634
|
+
tool.signatures = response.signatures;
|
|
238635
|
+
} else {
|
|
238636
|
+
tool.signatures = Object.values(response.signatures);
|
|
238637
|
+
}
|
|
238638
|
+
}
|
|
238639
|
+
} else if (response.content && typeof response.content === "string") {
|
|
238640
|
+
tool = import_yaml.default.parse(response.content);
|
|
238641
|
+
if (!tool.signature && response.signature) {
|
|
236654
238642
|
tool.signature = response.signature;
|
|
236655
|
-
|
|
238643
|
+
}
|
|
238644
|
+
if (!tool.signatures && response.signatures) {
|
|
238645
|
+
if (Array.isArray(response.signatures)) {
|
|
238646
|
+
tool.signatures = response.signatures;
|
|
238647
|
+
} else {
|
|
238648
|
+
tool.signatures = Object.values(response.signatures);
|
|
238649
|
+
}
|
|
236656
238650
|
}
|
|
236657
238651
|
} else {
|
|
236658
238652
|
tool = {
|
|
@@ -236671,7 +238665,7 @@ class EnactCore {
|
|
|
236671
238665
|
env: response.env_vars || response.env,
|
|
236672
238666
|
resources: response.resources,
|
|
236673
238667
|
signature: response.signature,
|
|
236674
|
-
signatures: response.signatures,
|
|
238668
|
+
signatures: response.signatures ? Array.isArray(response.signatures) ? response.signatures : Object.values(response.signatures) : undefined,
|
|
236675
238669
|
namespace: response.namespace
|
|
236676
238670
|
};
|
|
236677
238671
|
}
|
|
@@ -236686,6 +238680,9 @@ class EnactCore {
|
|
|
236686
238680
|
throw error;
|
|
236687
238681
|
}
|
|
236688
238682
|
}
|
|
238683
|
+
async getToolByName(name, version) {
|
|
238684
|
+
return EnactCore.getToolByName(name, version, this.options);
|
|
238685
|
+
}
|
|
236689
238686
|
async executeToolByName(name, inputs = {}, options = {}) {
|
|
236690
238687
|
const executionId = this.generateExecutionId();
|
|
236691
238688
|
try {
|
|
@@ -236722,120 +238719,76 @@ class EnactCore {
|
|
|
236722
238719
|
};
|
|
236723
238720
|
}
|
|
236724
238721
|
}
|
|
238722
|
+
async verifyTool(tool, dangerouslySkipVerification = false) {
|
|
238723
|
+
if (dangerouslySkipVerification) {
|
|
238724
|
+
logger_default.warn(`Skipping signature verification for tool: ${tool.name}`);
|
|
238725
|
+
return;
|
|
238726
|
+
}
|
|
238727
|
+
try {
|
|
238728
|
+
if (!tool.signatures || tool.signatures.length === 0) {
|
|
238729
|
+
throw new Error(`Tool ${tool.name} does not have any signatures`);
|
|
238730
|
+
}
|
|
238731
|
+
const documentForVerification = {
|
|
238732
|
+
command: tool.command
|
|
238733
|
+
};
|
|
238734
|
+
const referenceSignature = {
|
|
238735
|
+
signature: tool.signatures[0].value,
|
|
238736
|
+
publicKey: tool.signatures[0].signer,
|
|
238737
|
+
algorithm: tool.signatures[0].algorithm,
|
|
238738
|
+
timestamp: new Date(tool.signatures[0].created).getTime()
|
|
238739
|
+
};
|
|
238740
|
+
const canonicalDoc = SigningService.getCanonicalDocument(documentForVerification, { includeFields: ["command"] });
|
|
238741
|
+
const docString = JSON.stringify(canonicalDoc);
|
|
238742
|
+
const messageHash = CryptoUtils.hash(docString);
|
|
238743
|
+
const directVerify = CryptoUtils.verify(referenceSignature.publicKey, messageHash, referenceSignature.signature);
|
|
238744
|
+
console.log("Direct crypto verification result:", directVerify);
|
|
238745
|
+
const trustedKeys = KeyManager.getAllTrustedPublicKeys();
|
|
238746
|
+
console.log("Trusted keys:", trustedKeys);
|
|
238747
|
+
console.log("Is our public key trusted?", trustedKeys.includes(referenceSignature.publicKey));
|
|
238748
|
+
const isValid2 = SigningService.verifyDocument(documentForVerification, referenceSignature, { includeFields: ["command"] });
|
|
238749
|
+
console.log("Final verification result:", isValid2);
|
|
238750
|
+
if (!isValid2) {
|
|
238751
|
+
throw new Error(`Tool ${tool.name} has invalid signatures`);
|
|
238752
|
+
}
|
|
238753
|
+
logger_default.info(`Tool ${tool.name} signature verification passed`);
|
|
238754
|
+
} catch (error) {
|
|
238755
|
+
logger_default.error(`Signature verification failed for tool ${tool.name}:`, error);
|
|
238756
|
+
throw new Error(`Signature verification failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
238757
|
+
}
|
|
238758
|
+
}
|
|
236725
238759
|
async executeTool(tool, inputs = {}, options = {}) {
|
|
236726
238760
|
const executionId = this.generateExecutionId();
|
|
236727
238761
|
try {
|
|
236728
238762
|
logger_default.info(`Executing tool: ${tool.name}`);
|
|
236729
238763
|
validateToolStructure(tool);
|
|
236730
|
-
const verificationResult = await enforceSignatureVerification(tool, {
|
|
236731
|
-
skipVerification: options.skipVerification,
|
|
236732
|
-
verifyPolicy: options.verifyPolicy,
|
|
236733
|
-
force: options.force,
|
|
236734
|
-
allowUnsigned: false
|
|
236735
|
-
});
|
|
236736
|
-
logSecurityAudit(tool, verificationResult, verificationResult.allowed, {
|
|
236737
|
-
skipVerification: options.skipVerification,
|
|
236738
|
-
verifyPolicy: options.verifyPolicy,
|
|
236739
|
-
force: options.force
|
|
236740
|
-
});
|
|
236741
|
-
if (!verificationResult.allowed) {
|
|
236742
|
-
return createVerificationFailureResult(tool, verificationResult, executionId);
|
|
236743
|
-
}
|
|
236744
238764
|
const validatedInputs = validateInputs(tool, inputs);
|
|
236745
|
-
|
|
236746
|
-
|
|
236747
|
-
|
|
236748
|
-
|
|
236749
|
-
|
|
236750
|
-
|
|
236751
|
-
code: "COMMAND_UNSAFE",
|
|
236752
|
-
details: safetyCheck
|
|
236753
|
-
},
|
|
236754
|
-
metadata: {
|
|
236755
|
-
executionId,
|
|
236756
|
-
toolName: tool.name,
|
|
236757
|
-
version: tool.version,
|
|
236758
|
-
executedAt: new Date().toISOString(),
|
|
236759
|
-
environment: "direct",
|
|
236760
|
-
command: tool.command
|
|
236761
|
-
}
|
|
236762
|
-
};
|
|
236763
|
-
}
|
|
236764
|
-
if (safetyCheck.warnings.length > 0) {
|
|
236765
|
-
safetyCheck.warnings.forEach((warning) => logger_default.warn(warning));
|
|
236766
|
-
}
|
|
236767
|
-
if (options.dryRun) {
|
|
236768
|
-
return {
|
|
236769
|
-
success: true,
|
|
236770
|
-
output: {
|
|
236771
|
-
dryRun: true,
|
|
236772
|
-
tool: tool.name,
|
|
236773
|
-
command: tool.command,
|
|
236774
|
-
inputs: validatedInputs,
|
|
236775
|
-
safetyCheck
|
|
236776
|
-
},
|
|
236777
|
-
metadata: {
|
|
236778
|
-
executionId,
|
|
236779
|
-
toolName: tool.name,
|
|
236780
|
-
version: tool.version,
|
|
236781
|
-
executedAt: new Date().toISOString(),
|
|
236782
|
-
environment: "direct",
|
|
236783
|
-
command: tool.command
|
|
236784
|
-
}
|
|
236785
|
-
};
|
|
236786
|
-
}
|
|
236787
|
-
const envResult = await resolveToolEnvironmentVariables(tool.name, tool.env);
|
|
236788
|
-
if (envResult.missing.length > 0) {
|
|
236789
|
-
logger_default.warn(`Missing required environment variables: ${envResult.missing.join(", ")}`);
|
|
236790
|
-
}
|
|
236791
|
-
const environment = {
|
|
236792
|
-
vars: {
|
|
236793
|
-
...envResult.resolved,
|
|
236794
|
-
...sanitizeEnvironmentVariables(validatedInputs)
|
|
236795
|
-
},
|
|
236796
|
-
resources: tool.resources,
|
|
236797
|
-
namespace: tool.namespace
|
|
236798
|
-
};
|
|
236799
|
-
await this.executionProvider.setup(tool);
|
|
236800
|
-
const result = await this.executionProvider.execute(tool, validatedInputs, environment);
|
|
236801
|
-
if (result.success && result.output && tool.outputSchema) {
|
|
236802
|
-
try {
|
|
236803
|
-
result.output = validateOutput(tool, result.output);
|
|
236804
|
-
} catch (error) {
|
|
236805
|
-
logger_default.warn(`Output validation failed: ${error.message}`);
|
|
238765
|
+
await this.verifyTool(tool, options.dangerouslySkipVerification);
|
|
238766
|
+
const { resolved: envVars } = await resolveToolEnvironmentVariables(tool.name, tool.env || {});
|
|
238767
|
+
return await this.executionProvider.execute(tool, { ...validatedInputs, ...envVars }, {
|
|
238768
|
+
vars: { ...envVars, ...validatedInputs },
|
|
238769
|
+
resources: {
|
|
238770
|
+
timeout: options.timeout || tool.timeout || this.options.defaultTimeout
|
|
236806
238771
|
}
|
|
236807
|
-
}
|
|
236808
|
-
logger_default.info(`Tool execution completed: ${tool.name} (success: ${result.success})`);
|
|
236809
|
-
return result;
|
|
238772
|
+
});
|
|
236810
238773
|
} catch (error) {
|
|
236811
|
-
logger_default.error(`Error executing tool: ${error.message}`);
|
|
236812
238774
|
return {
|
|
236813
238775
|
success: false,
|
|
236814
238776
|
error: {
|
|
236815
238777
|
message: error.message,
|
|
236816
|
-
code: "EXECUTION_ERROR"
|
|
236817
|
-
details: error
|
|
238778
|
+
code: "EXECUTION_ERROR"
|
|
236818
238779
|
},
|
|
236819
238780
|
metadata: {
|
|
236820
238781
|
executionId,
|
|
236821
238782
|
toolName: tool.name,
|
|
236822
|
-
version: tool.version,
|
|
236823
238783
|
executedAt: new Date().toISOString(),
|
|
236824
|
-
environment: "direct"
|
|
236825
|
-
command: tool.command
|
|
238784
|
+
environment: "direct"
|
|
236826
238785
|
}
|
|
236827
238786
|
};
|
|
236828
|
-
} finally {
|
|
236829
|
-
try {
|
|
236830
|
-
await this.executionProvider.cleanup();
|
|
236831
|
-
} catch (cleanupError) {
|
|
236832
|
-
logger_default.error("Error during cleanup:", cleanupError);
|
|
236833
|
-
}
|
|
236834
238787
|
}
|
|
236835
238788
|
}
|
|
236836
238789
|
async executeRawTool(toolYaml, inputs = {}, options = {}) {
|
|
236837
238790
|
try {
|
|
236838
|
-
const tool =
|
|
238791
|
+
const tool = import_yaml.default.parse(toolYaml);
|
|
236839
238792
|
if (!tool || typeof tool !== "object") {
|
|
236840
238793
|
throw new Error("Invalid tool definition: YAML must contain a tool object");
|
|
236841
238794
|
}
|
|
@@ -236860,94 +238813,40 @@ class EnactCore {
|
|
|
236860
238813
|
};
|
|
236861
238814
|
}
|
|
236862
238815
|
}
|
|
236863
|
-
async
|
|
238816
|
+
static async toolExists(name, coreOptions = {}) {
|
|
236864
238817
|
try {
|
|
236865
|
-
const tool = await
|
|
236866
|
-
if (!tool) {
|
|
236867
|
-
return {
|
|
236868
|
-
verified: false,
|
|
236869
|
-
signatures: [],
|
|
236870
|
-
policy: policy || "permissive",
|
|
236871
|
-
errors: [`Tool not found: ${name}`]
|
|
236872
|
-
};
|
|
236873
|
-
}
|
|
236874
|
-
let publicKey;
|
|
236875
|
-
try {
|
|
236876
|
-
const keyPath = path8.resolve(__dirname, "../../keys/file-public.pem");
|
|
236877
|
-
publicKey = fs5.readFileSync(keyPath, "utf8");
|
|
236878
|
-
} catch (e2) {
|
|
236879
|
-
logger_default.warn("Could not load public key for signature verification:", e2);
|
|
236880
|
-
}
|
|
236881
|
-
if (!publicKey) {
|
|
236882
|
-
return {
|
|
236883
|
-
verified: false,
|
|
236884
|
-
signatures: [],
|
|
236885
|
-
policy: policy || "permissive",
|
|
236886
|
-
errors: ["Public key not found for signature verification"]
|
|
236887
|
-
};
|
|
236888
|
-
}
|
|
236889
|
-
const policyKey = (policy || "permissive").toUpperCase();
|
|
236890
|
-
const policyObj = VERIFICATION_POLICIES[policyKey];
|
|
236891
|
-
const verificationResult = await verifyTool(tool, policyObj);
|
|
236892
|
-
if (!verificationResult.isValid) {
|
|
236893
|
-
return {
|
|
236894
|
-
verified: false,
|
|
236895
|
-
signatures: [],
|
|
236896
|
-
policy: policy || "permissive",
|
|
236897
|
-
errors: verificationResult.errors
|
|
236898
|
-
};
|
|
236899
|
-
}
|
|
236900
|
-
const signatures = [];
|
|
236901
|
-
if (tool.signature) {
|
|
236902
|
-
signatures.push(tool.signature);
|
|
236903
|
-
}
|
|
236904
|
-
if (tool.signatures) {
|
|
236905
|
-
signatures.push(...Object.values(tool.signatures));
|
|
236906
|
-
}
|
|
236907
|
-
return {
|
|
236908
|
-
verified: verificationResult.isValid,
|
|
236909
|
-
signatures,
|
|
236910
|
-
policy: policy || "permissive"
|
|
236911
|
-
};
|
|
236912
|
-
} catch (error) {
|
|
236913
|
-
return {
|
|
236914
|
-
verified: false,
|
|
236915
|
-
signatures: [],
|
|
236916
|
-
policy: policy || "permissive",
|
|
236917
|
-
errors: [`Verification error: ${error.message}`]
|
|
236918
|
-
};
|
|
236919
|
-
}
|
|
236920
|
-
}
|
|
236921
|
-
async toolExists(name) {
|
|
236922
|
-
try {
|
|
236923
|
-
const tool = await this.getToolByName(name);
|
|
238818
|
+
const tool = await EnactCore.getToolByName(name, undefined, coreOptions);
|
|
236924
238819
|
return tool !== null;
|
|
236925
238820
|
} catch (error) {
|
|
236926
238821
|
return false;
|
|
236927
238822
|
}
|
|
236928
238823
|
}
|
|
238824
|
+
async toolExists(name) {
|
|
238825
|
+
return EnactCore.toolExists(name, this.options);
|
|
238826
|
+
}
|
|
236929
238827
|
async getToolsByTags(tags, limit = 20) {
|
|
236930
|
-
return
|
|
238828
|
+
return EnactCore.searchTools({
|
|
236931
238829
|
query: tags.join(" "),
|
|
236932
238830
|
tags,
|
|
236933
238831
|
limit
|
|
236934
|
-
});
|
|
238832
|
+
}, this.options);
|
|
236935
238833
|
}
|
|
236936
238834
|
async getToolsByAuthor(author, limit = 20) {
|
|
236937
|
-
return
|
|
238835
|
+
return EnactCore.searchTools({
|
|
236938
238836
|
query: `author:${author}`,
|
|
236939
238837
|
author,
|
|
236940
238838
|
limit
|
|
236941
|
-
});
|
|
238839
|
+
}, this.options);
|
|
236942
238840
|
}
|
|
236943
|
-
async getTools(options = {}) {
|
|
238841
|
+
static async getTools(options = {}, coreOptions = {}) {
|
|
238842
|
+
const apiClient = new EnactApiClient(coreOptions.apiUrl || "https://enact.tools", coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co");
|
|
236944
238843
|
try {
|
|
236945
|
-
const apiResults = await
|
|
238844
|
+
const apiResults = await apiClient.getTools(options);
|
|
236946
238845
|
const tools = [];
|
|
236947
238846
|
for (const result of apiResults) {
|
|
236948
238847
|
if (result.name) {
|
|
236949
238848
|
try {
|
|
236950
|
-
const tool = await
|
|
238849
|
+
const tool = await EnactCore.getToolByName(result.name, undefined, coreOptions);
|
|
236951
238850
|
if (tool) {
|
|
236952
238851
|
tools.push(tool);
|
|
236953
238852
|
}
|
|
@@ -236962,22 +238861,20 @@ class EnactCore {
|
|
|
236962
238861
|
throw new Error(`Failed to get tools: ${error instanceof Error ? error.message : String(error)}`);
|
|
236963
238862
|
}
|
|
236964
238863
|
}
|
|
238864
|
+
async getTools(options = {}) {
|
|
238865
|
+
return EnactCore.getTools(options, this.options);
|
|
238866
|
+
}
|
|
236965
238867
|
async getAuthStatus() {
|
|
236966
238868
|
return {
|
|
236967
238869
|
authenticated: !!this.options.authToken,
|
|
236968
238870
|
server: this.options.apiUrl
|
|
236969
238871
|
};
|
|
236970
238872
|
}
|
|
236971
|
-
async publishTool(tool) {
|
|
236972
|
-
|
|
236973
|
-
return {
|
|
236974
|
-
success: false,
|
|
236975
|
-
message: "Authentication required to publish tools"
|
|
236976
|
-
};
|
|
236977
|
-
}
|
|
238873
|
+
static async publishTool(tool, authToken, coreOptions = {}) {
|
|
238874
|
+
const apiClient = new EnactApiClient(coreOptions.apiUrl || "https://enact.tools", coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co");
|
|
236978
238875
|
try {
|
|
236979
238876
|
validateToolStructure(tool);
|
|
236980
|
-
await
|
|
238877
|
+
await apiClient.publishTool(tool, authToken);
|
|
236981
238878
|
return {
|
|
236982
238879
|
success: true,
|
|
236983
238880
|
message: `Successfully published tool: ${tool.name}`
|
|
@@ -236989,15 +238886,23 @@ class EnactCore {
|
|
|
236989
238886
|
};
|
|
236990
238887
|
}
|
|
236991
238888
|
}
|
|
238889
|
+
async publishTool(tool) {
|
|
238890
|
+
if (!this.options.authToken) {
|
|
238891
|
+
return {
|
|
238892
|
+
success: false,
|
|
238893
|
+
message: "Authentication required to publish tools"
|
|
238894
|
+
};
|
|
238895
|
+
}
|
|
238896
|
+
return EnactCore.publishTool(tool, this.options.authToken, this.options);
|
|
238897
|
+
}
|
|
236992
238898
|
async getToolInfo(name, version) {
|
|
236993
|
-
return
|
|
238899
|
+
return EnactCore.getToolByName(name, version, this.options);
|
|
236994
238900
|
}
|
|
236995
238901
|
async getStatus() {
|
|
236996
238902
|
const authStatus = await this.getAuthStatus();
|
|
236997
238903
|
return {
|
|
236998
238904
|
executionProvider: this.options.executionProvider || "direct",
|
|
236999
238905
|
apiUrl: this.options.apiUrl || "https://enact.tools",
|
|
237000
|
-
verificationPolicy: this.options.verificationPolicy || "permissive",
|
|
237001
238906
|
defaultTimeout: this.options.defaultTimeout || "30s",
|
|
237002
238907
|
authenticated: authStatus.authenticated
|
|
237003
238908
|
};
|
|
@@ -237019,12 +238924,11 @@ class EnactCore {
|
|
|
237019
238924
|
return `exec_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
237020
238925
|
}
|
|
237021
238926
|
}
|
|
237022
|
-
var enactCore = new EnactCore;
|
|
237023
238927
|
// ../shared/dist/utils/config.js
|
|
237024
238928
|
import { homedir as homedir3 } from "os";
|
|
237025
|
-
import { join as
|
|
237026
|
-
var CONFIG_DIR2 =
|
|
237027
|
-
var CONFIG_FILE =
|
|
238929
|
+
import { join as join3 } from "path";
|
|
238930
|
+
var CONFIG_DIR2 = join3(homedir3(), ".enact");
|
|
238931
|
+
var CONFIG_FILE = join3(CONFIG_DIR2, "config.json");
|
|
237028
238932
|
// ../shared/dist/utils/help.js
|
|
237029
238933
|
var __dirname = "/Users/keithgroves/projects/enact/enact-cli/packages/shared/dist/utils";
|
|
237030
238934
|
// ../shared/dist/utils/logger.js
|
|
@@ -237165,30 +239069,32 @@ function validateSilentEnvironment() {
|
|
|
237165
239069
|
issues
|
|
237166
239070
|
};
|
|
237167
239071
|
}
|
|
239072
|
+
// ../shared/dist/utils/version.js
|
|
239073
|
+
var __filename = "/Users/keithgroves/projects/enact/enact-cli/packages/shared/dist/utils/version.js";
|
|
237168
239074
|
// ../shared/dist/web/env-manager-server.js
|
|
237169
239075
|
import { createServer } from "http";
|
|
237170
|
-
import { parse as
|
|
239076
|
+
import { parse as parse3 } from "url";
|
|
237171
239077
|
import { readFile as readFile2, writeFile, mkdir, readdir, stat as stat2 } from "fs/promises";
|
|
237172
|
-
import { existsSync as
|
|
237173
|
-
import { join as
|
|
239078
|
+
import { existsSync as existsSync3 } from "fs";
|
|
239079
|
+
import { join as join4, dirname as dirname3 } from "path";
|
|
237174
239080
|
import { homedir as homedir4 } from "os";
|
|
237175
239081
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
237176
239082
|
var __filename3 = fileURLToPath4(import.meta.url);
|
|
237177
239083
|
var __dirname3 = dirname3(__filename3);
|
|
237178
|
-
var CONFIG_DIR3 =
|
|
237179
|
-
var ENV_BASE_DIR =
|
|
239084
|
+
var CONFIG_DIR3 = join4(homedir4(), ".enact");
|
|
239085
|
+
var ENV_BASE_DIR = join4(CONFIG_DIR3, "env");
|
|
237180
239086
|
function findStaticDir() {
|
|
237181
239087
|
const candidates = [
|
|
237182
|
-
|
|
237183
|
-
|
|
237184
|
-
|
|
237185
|
-
|
|
237186
|
-
|
|
237187
|
-
|
|
237188
|
-
|
|
239088
|
+
join4(__dirname3, "web", "static"),
|
|
239089
|
+
join4(__dirname3, "static"),
|
|
239090
|
+
join4(__dirname3, "..", "src", "web", "static"),
|
|
239091
|
+
join4(__dirname3, "..", "..", "src", "web", "static"),
|
|
239092
|
+
join4(process.cwd(), "src", "web", "static"),
|
|
239093
|
+
join4(__dirname3, "..", "..", "..", "src", "web", "static"),
|
|
239094
|
+
join4(__dirname3, "..", "..", "src", "web", "static")
|
|
237189
239095
|
];
|
|
237190
239096
|
for (const candidate of candidates) {
|
|
237191
|
-
if (
|
|
239097
|
+
if (existsSync3(join4(candidate, "index.html"))) {
|
|
237192
239098
|
logger_default.debug(`Found static directory: ${candidate}`);
|
|
237193
239099
|
return candidate;
|
|
237194
239100
|
}
|
|
@@ -237232,7 +239138,7 @@ function generateDotEnv(vars) {
|
|
|
237232
239138
|
}
|
|
237233
239139
|
async function getAllPackageNamespaces() {
|
|
237234
239140
|
const packages = [];
|
|
237235
|
-
if (!
|
|
239141
|
+
if (!existsSync3(ENV_BASE_DIR)) {
|
|
237236
239142
|
return packages;
|
|
237237
239143
|
}
|
|
237238
239144
|
try {
|
|
@@ -237246,7 +239152,7 @@ async function scanDirectory(dir, relativePath, packages) {
|
|
|
237246
239152
|
try {
|
|
237247
239153
|
const entries = await readdir(dir);
|
|
237248
239154
|
for (const entry of entries) {
|
|
237249
|
-
const fullPath =
|
|
239155
|
+
const fullPath = join4(dir, entry);
|
|
237250
239156
|
const stats = await stat2(fullPath);
|
|
237251
239157
|
if (stats.isDirectory()) {
|
|
237252
239158
|
const newRelativePath = relativePath ? `${relativePath}/${entry}` : entry;
|
|
@@ -237271,8 +239177,8 @@ async function scanDirectory(dir, relativePath, packages) {
|
|
|
237271
239177
|
}
|
|
237272
239178
|
}
|
|
237273
239179
|
async function getPackageEnvVars(namespace) {
|
|
237274
|
-
const envFile =
|
|
237275
|
-
if (!
|
|
239180
|
+
const envFile = join4(ENV_BASE_DIR, namespace, ".env");
|
|
239181
|
+
if (!existsSync3(envFile)) {
|
|
237276
239182
|
return {};
|
|
237277
239183
|
}
|
|
237278
239184
|
try {
|
|
@@ -237284,9 +239190,9 @@ async function getPackageEnvVars(namespace) {
|
|
|
237284
239190
|
}
|
|
237285
239191
|
}
|
|
237286
239192
|
async function setPackageEnvVar(namespace, key, value) {
|
|
237287
|
-
const envFile =
|
|
239193
|
+
const envFile = join4(ENV_BASE_DIR, namespace, ".env");
|
|
237288
239194
|
const envDir = dirname3(envFile);
|
|
237289
|
-
if (!
|
|
239195
|
+
if (!existsSync3(envDir)) {
|
|
237290
239196
|
await mkdir(envDir, { recursive: true });
|
|
237291
239197
|
}
|
|
237292
239198
|
const existingVars = await getPackageEnvVars(namespace);
|
|
@@ -237300,7 +239206,7 @@ async function deletePackageEnvVar(namespace, key) {
|
|
|
237300
239206
|
throw new Error(`Environment variable '${key}' not found in package '${namespace}'`);
|
|
237301
239207
|
}
|
|
237302
239208
|
delete existingVars[key];
|
|
237303
|
-
const envFile =
|
|
239209
|
+
const envFile = join4(ENV_BASE_DIR, namespace, ".env");
|
|
237304
239210
|
const envContent = generateDotEnv(existingVars);
|
|
237305
239211
|
await writeFile(envFile, envContent, "utf8");
|
|
237306
239212
|
}
|
|
@@ -237332,7 +239238,7 @@ async function serveStaticFile(filePath, res) {
|
|
|
237332
239238
|
}
|
|
237333
239239
|
}
|
|
237334
239240
|
async function handleRequest(req, res) {
|
|
237335
|
-
const urlParts =
|
|
239241
|
+
const urlParts = parse3(req.url || "", true);
|
|
237336
239242
|
const pathname = urlParts.pathname || "/";
|
|
237337
239243
|
const method = req.method || "GET";
|
|
237338
239244
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
@@ -237345,11 +239251,11 @@ async function handleRequest(req, res) {
|
|
|
237345
239251
|
}
|
|
237346
239252
|
try {
|
|
237347
239253
|
if (pathname === "/") {
|
|
237348
|
-
await serveStaticFile(
|
|
239254
|
+
await serveStaticFile(join4(STATIC_DIR, "index.html"), res);
|
|
237349
239255
|
} else if (pathname === "/style.css") {
|
|
237350
|
-
await serveStaticFile(
|
|
239256
|
+
await serveStaticFile(join4(STATIC_DIR, "style.css"), res);
|
|
237351
239257
|
} else if (pathname === "/app.js") {
|
|
237352
|
-
await serveStaticFile(
|
|
239258
|
+
await serveStaticFile(join4(STATIC_DIR, "app.js"), res);
|
|
237353
239259
|
} else if (pathname === "/favicon.ico") {
|
|
237354
239260
|
const favicon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text y=".9em" font-size="90">\uD83C\uDF10</text></svg>`;
|
|
237355
239261
|
res.writeHead(200, { "Content-Type": "image/svg+xml" });
|
|
@@ -237366,12 +239272,12 @@ async function handleRequest(req, res) {
|
|
|
237366
239272
|
res.end(JSON.stringify({ error: "Namespace is required" }));
|
|
237367
239273
|
return;
|
|
237368
239274
|
}
|
|
237369
|
-
const envDir =
|
|
237370
|
-
const envFile =
|
|
237371
|
-
if (!
|
|
239275
|
+
const envDir = join4(ENV_BASE_DIR, namespace);
|
|
239276
|
+
const envFile = join4(envDir, ".env");
|
|
239277
|
+
if (!existsSync3(envDir)) {
|
|
237372
239278
|
await mkdir(envDir, { recursive: true });
|
|
237373
239279
|
}
|
|
237374
|
-
if (!
|
|
239280
|
+
if (!existsSync3(envFile)) {
|
|
237375
239281
|
await writeFile(envFile, "", "utf8");
|
|
237376
239282
|
}
|
|
237377
239283
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
@@ -237448,11 +239354,11 @@ function startEnvManagerServer(port = 5555) {
|
|
|
237448
239354
|
}
|
|
237449
239355
|
// ../shared/dist/LocalToolResolver.js
|
|
237450
239356
|
var yaml2 = __toESM(require_dist3(), 1);
|
|
237451
|
-
import { promises as
|
|
237452
|
-
import { join as
|
|
239357
|
+
import { promises as fs5, readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
239358
|
+
import { join as join5, resolve, basename as basename2 } from "path";
|
|
237453
239359
|
class LocalToolResolver {
|
|
237454
|
-
constructor(
|
|
237455
|
-
this.enactCore =
|
|
239360
|
+
constructor(enactCore, localToolsDir = "./tools", cacheDir = "./.tool-cache") {
|
|
239361
|
+
this.enactCore = enactCore;
|
|
237456
239362
|
this.toolCache = new Map;
|
|
237457
239363
|
this.aliases = new Map;
|
|
237458
239364
|
this.favorites = new Set;
|
|
@@ -237495,17 +239401,17 @@ class LocalToolResolver {
|
|
|
237495
239401
|
}
|
|
237496
239402
|
async getLocalTool(toolName) {
|
|
237497
239403
|
const possiblePaths = [
|
|
237498
|
-
|
|
237499
|
-
|
|
237500
|
-
|
|
237501
|
-
|
|
237502
|
-
|
|
237503
|
-
|
|
239404
|
+
join5(this.localToolsDir, `${toolName}.yaml`),
|
|
239405
|
+
join5(this.localToolsDir, `${toolName}.yml`),
|
|
239406
|
+
join5(this.localToolsDir, toolName, "tool.yaml"),
|
|
239407
|
+
join5(this.localToolsDir, toolName, "tool.yml"),
|
|
239408
|
+
join5(this.localToolsDir, toolName, `${toolName}.yaml`),
|
|
239409
|
+
join5(this.localToolsDir, toolName, `${toolName}.yml`)
|
|
237504
239410
|
];
|
|
237505
239411
|
for (const toolPath of possiblePaths) {
|
|
237506
239412
|
try {
|
|
237507
|
-
const stats = await
|
|
237508
|
-
const content = await
|
|
239413
|
+
const stats = await fs5.stat(toolPath);
|
|
239414
|
+
const content = await fs5.readFile(toolPath, "utf-8");
|
|
237509
239415
|
const definition = yaml2.parse(content);
|
|
237510
239416
|
if (definition && (definition.name === toolName || definition.name === undefined)) {
|
|
237511
239417
|
return {
|
|
@@ -237524,15 +239430,15 @@ class LocalToolResolver {
|
|
|
237524
239430
|
}
|
|
237525
239431
|
async cacheRegistryTool(toolName, tool) {
|
|
237526
239432
|
try {
|
|
237527
|
-
await
|
|
237528
|
-
const cachePath =
|
|
239433
|
+
await fs5.mkdir(this.cacheDir, { recursive: true });
|
|
239434
|
+
const cachePath = join5(this.cacheDir, `${toolName}.yaml`);
|
|
237529
239435
|
const cacheData = {
|
|
237530
239436
|
...tool,
|
|
237531
239437
|
_cached: true,
|
|
237532
239438
|
_cachedAt: new Date().toISOString(),
|
|
237533
239439
|
_source: "registry"
|
|
237534
239440
|
};
|
|
237535
|
-
await
|
|
239441
|
+
await fs5.writeFile(cachePath, yaml2.stringify(cacheData));
|
|
237536
239442
|
this.toolCache.set(toolName, {
|
|
237537
239443
|
name: toolName,
|
|
237538
239444
|
path: cachePath,
|
|
@@ -237561,15 +239467,15 @@ class LocalToolResolver {
|
|
|
237561
239467
|
async scanLocalTools() {
|
|
237562
239468
|
const tools = [];
|
|
237563
239469
|
try {
|
|
237564
|
-
await
|
|
239470
|
+
await fs5.mkdir(this.localToolsDir, { recursive: true });
|
|
237565
239471
|
const entries = await this.scanDirectory(this.localToolsDir);
|
|
237566
239472
|
for (const entry of entries) {
|
|
237567
239473
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
237568
239474
|
try {
|
|
237569
|
-
const content = await
|
|
239475
|
+
const content = await fs5.readFile(entry, "utf-8");
|
|
237570
239476
|
const definition = yaml2.parse(content);
|
|
237571
239477
|
if (definition && (definition.name || definition.command)) {
|
|
237572
|
-
const stats = await
|
|
239478
|
+
const stats = await fs5.stat(entry);
|
|
237573
239479
|
tools.push({
|
|
237574
239480
|
name: definition.name || basename2(entry, ".yaml").replace(".yml", ""),
|
|
237575
239481
|
path: entry,
|
|
@@ -237591,9 +239497,9 @@ class LocalToolResolver {
|
|
|
237591
239497
|
async scanDirectory(dir) {
|
|
237592
239498
|
const files = [];
|
|
237593
239499
|
try {
|
|
237594
|
-
const entries = await
|
|
239500
|
+
const entries = await fs5.readdir(dir, { withFileTypes: true });
|
|
237595
239501
|
for (const entry of entries) {
|
|
237596
|
-
const fullPath =
|
|
239502
|
+
const fullPath = join5(dir, entry.name);
|
|
237597
239503
|
if (entry.isDirectory()) {
|
|
237598
239504
|
const subFiles = await this.scanDirectory(fullPath);
|
|
237599
239505
|
files.push(...subFiles);
|
|
@@ -237639,7 +239545,7 @@ class LocalToolResolver {
|
|
|
237639
239545
|
for (const [toolName, tool] of this.toolCache.entries()) {
|
|
237640
239546
|
if (this.isCacheExpired(tool)) {
|
|
237641
239547
|
try {
|
|
237642
|
-
await
|
|
239548
|
+
await fs5.unlink(tool.path);
|
|
237643
239549
|
this.toolCache.delete(toolName);
|
|
237644
239550
|
cleaned++;
|
|
237645
239551
|
} catch (error) {
|
|
@@ -237652,8 +239558,8 @@ class LocalToolResolver {
|
|
|
237652
239558
|
}
|
|
237653
239559
|
loadConfiguration() {
|
|
237654
239560
|
try {
|
|
237655
|
-
const configPath =
|
|
237656
|
-
const config2 = JSON.parse(
|
|
239561
|
+
const configPath = join5(this.localToolsDir, "config.json");
|
|
239562
|
+
const config2 = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
237657
239563
|
if (config2.aliases) {
|
|
237658
239564
|
this.aliases = new Map(Object.entries(config2.aliases));
|
|
237659
239565
|
}
|
|
@@ -237666,20 +239572,20 @@ class LocalToolResolver {
|
|
|
237666
239572
|
}
|
|
237667
239573
|
saveConfiguration() {
|
|
237668
239574
|
try {
|
|
237669
|
-
const configPath =
|
|
239575
|
+
const configPath = join5(this.localToolsDir, "config.json");
|
|
237670
239576
|
const config2 = {
|
|
237671
239577
|
aliases: Object.fromEntries(this.aliases),
|
|
237672
239578
|
favorites: Array.from(this.favorites),
|
|
237673
239579
|
lastUpdated: new Date().toISOString()
|
|
237674
239580
|
};
|
|
237675
|
-
|
|
239581
|
+
writeFileSync(configPath, JSON.stringify(config2, null, 2));
|
|
237676
239582
|
} catch (error) {
|
|
237677
239583
|
logger_default.warn("Failed to save tool configuration:", error);
|
|
237678
239584
|
}
|
|
237679
239585
|
}
|
|
237680
239586
|
async initialize() {
|
|
237681
|
-
await
|
|
237682
|
-
await
|
|
239587
|
+
await fs5.mkdir(this.localToolsDir, { recursive: true });
|
|
239588
|
+
await fs5.mkdir(this.cacheDir, { recursive: true });
|
|
237683
239589
|
const tools = await this.scanLocalTools();
|
|
237684
239590
|
if (tools.length === 0) {
|
|
237685
239591
|
const sampleTool = {
|
|
@@ -237696,11 +239602,11 @@ class LocalToolResolver {
|
|
|
237696
239602
|
}
|
|
237697
239603
|
}
|
|
237698
239604
|
};
|
|
237699
|
-
const samplePath =
|
|
237700
|
-
await
|
|
239605
|
+
const samplePath = join5(this.localToolsDir, "hello-world.yaml");
|
|
239606
|
+
await fs5.writeFile(samplePath, yaml2.stringify(sampleTool));
|
|
237701
239607
|
logger_default.info(`Created sample tool at ${samplePath}`);
|
|
237702
239608
|
}
|
|
237703
|
-
const readmePath =
|
|
239609
|
+
const readmePath = join5(this.localToolsDir, "README.md");
|
|
237704
239610
|
const readme = `# Local Tools Directory
|
|
237705
239611
|
|
|
237706
239612
|
This directory contains your local Enact tools. Tools can be organized as:
|
|
@@ -237725,9 +239631,9 @@ Registry tools are cached in \`.tool-cache/\` for faster access.
|
|
|
237725
239631
|
Use the MCP tools to manage this directory programmatically.
|
|
237726
239632
|
`;
|
|
237727
239633
|
try {
|
|
237728
|
-
await
|
|
239634
|
+
await fs5.access(readmePath);
|
|
237729
239635
|
} catch {
|
|
237730
|
-
await
|
|
239636
|
+
await fs5.writeFile(readmePath, readme);
|
|
237731
239637
|
}
|
|
237732
239638
|
}
|
|
237733
239639
|
}
|
|
@@ -237759,8 +239665,6 @@ class McpCoreService {
|
|
|
237759
239665
|
async executeToolByName(name, inputs = {}, options) {
|
|
237760
239666
|
const executeOptions = {
|
|
237761
239667
|
timeout: options?.timeout,
|
|
237762
|
-
verifyPolicy: options?.verifyPolicy,
|
|
237763
|
-
skipVerification: options?.skipVerification,
|
|
237764
239668
|
force: options?.force,
|
|
237765
239669
|
dryRun: options?.dryRun
|
|
237766
239670
|
};
|
|
@@ -237769,15 +239673,11 @@ class McpCoreService {
|
|
|
237769
239673
|
async executeRawTool(toolYaml, inputs = {}, options) {
|
|
237770
239674
|
const executeOptions = {
|
|
237771
239675
|
timeout: options?.timeout,
|
|
237772
|
-
skipVerification: options?.skipVerification,
|
|
237773
239676
|
force: options?.force,
|
|
237774
239677
|
dryRun: options?.dryRun
|
|
237775
239678
|
};
|
|
237776
239679
|
return await this.core.executeRawTool(toolYaml, inputs, executeOptions);
|
|
237777
239680
|
}
|
|
237778
|
-
async verifyTool(name, policy) {
|
|
237779
|
-
return await this.core.verifyTool(name, policy);
|
|
237780
|
-
}
|
|
237781
239681
|
async toolExists(name) {
|
|
237782
239682
|
return await this.core.toolExists(name);
|
|
237783
239683
|
}
|
|
@@ -237816,7 +239716,6 @@ class EnactDirect {
|
|
|
237816
239716
|
supabaseUrl: options.supabaseUrl || process.env.ENACT_SUPABASE_URL || "https://xjnhhxwxovjifdxdwzih.supabase.co",
|
|
237817
239717
|
executionProvider: "direct",
|
|
237818
239718
|
authToken: options.authToken || process.env.ENACT_AUTH_TOKEN,
|
|
237819
|
-
verificationPolicy: options.verificationPolicy || "permissive",
|
|
237820
239719
|
defaultTimeout: options.defaultTimeout || "30s"
|
|
237821
239720
|
});
|
|
237822
239721
|
}
|
|
@@ -237829,9 +239728,6 @@ class EnactDirect {
|
|
|
237829
239728
|
async getToolInfo(name, version) {
|
|
237830
239729
|
return this.core.getToolInfo(name, version);
|
|
237831
239730
|
}
|
|
237832
|
-
async verifyTool(name, policy) {
|
|
237833
|
-
return this.core.verifyTool(name, policy);
|
|
237834
|
-
}
|
|
237835
239731
|
async executeRawTool(toolYaml, inputs = {}, options = {}) {
|
|
237836
239732
|
return this.core.executeRawTool(toolYaml, inputs, options);
|
|
237837
239733
|
}
|
|
@@ -237863,7 +239759,7 @@ class EnactDirect {
|
|
|
237863
239759
|
var enactDirect = new EnactDirect;
|
|
237864
239760
|
// src/index.ts
|
|
237865
239761
|
import { homedir as homedir5 } from "os";
|
|
237866
|
-
import { join as
|
|
239762
|
+
import { join as join6 } from "path";
|
|
237867
239763
|
process.env.CI = process.env.CI || "true";
|
|
237868
239764
|
process.env.ENACT_SKIP_INTERACTIVE = process.env.ENACT_SKIP_INTERACTIVE || "true";
|
|
237869
239765
|
if (true) {
|
|
@@ -237873,11 +239769,10 @@ if (true) {
|
|
|
237873
239769
|
`);
|
|
237874
239770
|
}
|
|
237875
239771
|
}
|
|
237876
|
-
var
|
|
239772
|
+
var enactCore = new EnactCore({
|
|
237877
239773
|
apiUrl: process.env.ENACT_API_URL || "https://enact.tools",
|
|
237878
239774
|
supabaseUrl: process.env.ENACT_SUPABASE_URL || "https://xjnhhxwxovjifdxdwzih.supabase.co",
|
|
237879
239775
|
executionProvider: process.env.ENACT_EXECUTION_PROVIDER || "dagger",
|
|
237880
|
-
verificationPolicy: process.env.ENACT_VERIFY_POLICY || "permissive",
|
|
237881
239776
|
authToken: process.env.ENACT_AUTH_TOKEN,
|
|
237882
239777
|
defaultTimeout: "120s"
|
|
237883
239778
|
});
|
|
@@ -237954,9 +239849,9 @@ async function validateMcpToolEnvironmentVariables(toolName, toolEnv) {
|
|
|
237954
239849
|
};
|
|
237955
239850
|
}
|
|
237956
239851
|
}
|
|
237957
|
-
var defaultToolsDir =
|
|
237958
|
-
var defaultCacheDir =
|
|
237959
|
-
var toolResolver = new LocalToolResolver_default(
|
|
239852
|
+
var defaultToolsDir = join6(homedir5(), ".enact", "tools");
|
|
239853
|
+
var defaultCacheDir = join6(homedir5(), ".enact", "cache");
|
|
239854
|
+
var toolResolver = new LocalToolResolver_default(enactCore, process.env.LOCAL_TOOLS_DIR || defaultToolsDir, process.env.TOOL_CACHE_DIR || defaultCacheDir);
|
|
237960
239855
|
(async () => {
|
|
237961
239856
|
try {
|
|
237962
239857
|
await toolResolver.initialize();
|
|
@@ -237972,9 +239867,7 @@ server2.registerTool("execute-tool-by-name", {
|
|
|
237972
239867
|
inputs: exports_external.record(exports_external.any()).optional().describe("Input parameters for the tool"),
|
|
237973
239868
|
localFile: exports_external.boolean().optional().describe("Treat 'name' as a file path to local YAML tool"),
|
|
237974
239869
|
timeout: exports_external.string().optional().describe("Execution timeout"),
|
|
237975
|
-
|
|
237976
|
-
skipVerification: exports_external.boolean().optional().describe("Skip signature verification"),
|
|
237977
|
-
force: exports_external.boolean().optional().describe("Force execution"),
|
|
239870
|
+
dangerouslySkipVerification: exports_external.boolean().optional().describe("Skip all signature verification (DANGEROUS)"),
|
|
237978
239871
|
dryRun: exports_external.boolean().optional().describe("Dry run mode"),
|
|
237979
239872
|
verbose: exports_external.boolean().optional().describe("Verbose output"),
|
|
237980
239873
|
async: exports_external.boolean().optional().describe("Run in background for long operations"),
|
|
@@ -237986,9 +239879,7 @@ server2.registerTool("execute-tool-by-name", {
|
|
|
237986
239879
|
inputs = {},
|
|
237987
239880
|
localFile = false,
|
|
237988
239881
|
timeout: timeout3,
|
|
237989
|
-
|
|
237990
|
-
skipVerification,
|
|
237991
|
-
force,
|
|
239882
|
+
dangerouslySkipVerification,
|
|
237992
239883
|
dryRun,
|
|
237993
239884
|
verbose,
|
|
237994
239885
|
async = false,
|
|
@@ -238000,18 +239891,18 @@ server2.registerTool("execute-tool-by-name", {
|
|
|
238000
239891
|
let resolutionInfo = "";
|
|
238001
239892
|
let isLocalFile = false;
|
|
238002
239893
|
if (localFile) {
|
|
238003
|
-
const
|
|
238004
|
-
const
|
|
239894
|
+
const fs6 = await import("fs/promises");
|
|
239895
|
+
const path8 = await import("path");
|
|
238005
239896
|
const yaml3 = await Promise.resolve().then(() => __toESM(require_dist3(), 1));
|
|
238006
|
-
const resolvedPath =
|
|
239897
|
+
const resolvedPath = path8.resolve(name);
|
|
238007
239898
|
try {
|
|
238008
|
-
await
|
|
238009
|
-
const yamlContent = await
|
|
239899
|
+
await fs6.access(resolvedPath);
|
|
239900
|
+
const yamlContent = await fs6.readFile(resolvedPath, "utf-8");
|
|
238010
239901
|
const definition = yaml3.parse(yamlContent);
|
|
238011
239902
|
toolToExecute = {
|
|
238012
239903
|
path: resolvedPath,
|
|
238013
239904
|
definition,
|
|
238014
|
-
name: definition.name ||
|
|
239905
|
+
name: definition.name || path8.basename(resolvedPath, path8.extname(resolvedPath))
|
|
238015
239906
|
};
|
|
238016
239907
|
resolutionInfo = `\uD83D\uDCC4 Local file (${resolvedPath})`;
|
|
238017
239908
|
isLocalFile = true;
|
|
@@ -238027,7 +239918,7 @@ server2.registerTool("execute-tool-by-name", {
|
|
|
238027
239918
|
};
|
|
238028
239919
|
}
|
|
238029
239920
|
} else if (forceRegistry) {
|
|
238030
|
-
toolToExecute = await
|
|
239921
|
+
toolToExecute = await enactCore.getToolByName(name);
|
|
238031
239922
|
resolutionInfo = "\uD83C\uDF10 Registry (forced)";
|
|
238032
239923
|
} else {
|
|
238033
239924
|
const resolution = await toolResolver.resolveTool(name);
|
|
@@ -238086,23 +239977,21 @@ ${suggestions.map((s2) => ` • ${s2}`).join(`
|
|
|
238086
239977
|
const operationId = `${toolToExecute.name}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
238087
239978
|
let executionPromise;
|
|
238088
239979
|
if (isLocalFile) {
|
|
238089
|
-
const yamlContent = await import("fs/promises").then((
|
|
238090
|
-
executionPromise =
|
|
239980
|
+
const yamlContent = await import("fs/promises").then((fs6) => fs6.readFile(toolToExecute.path, "utf-8"));
|
|
239981
|
+
executionPromise = enactCore.executeRawTool(yamlContent, inputs, {
|
|
238091
239982
|
timeout: timeout3 || "300s",
|
|
238092
|
-
|
|
238093
|
-
skipVerification: true,
|
|
238094
|
-
force,
|
|
239983
|
+
force: dangerouslySkipVerification || true,
|
|
238095
239984
|
dryRun,
|
|
238096
|
-
verbose
|
|
239985
|
+
verbose,
|
|
239986
|
+
isLocalFile: true
|
|
238097
239987
|
});
|
|
238098
239988
|
} else {
|
|
238099
|
-
executionPromise =
|
|
239989
|
+
executionPromise = enactCore.executeToolByName(toolToExecute.name || name, inputs, {
|
|
238100
239990
|
timeout: timeout3 || "300s",
|
|
238101
|
-
|
|
238102
|
-
skipVerification,
|
|
238103
|
-
force,
|
|
239991
|
+
force: dangerouslySkipVerification,
|
|
238104
239992
|
dryRun,
|
|
238105
|
-
verbose
|
|
239993
|
+
verbose,
|
|
239994
|
+
isLocalFile: false
|
|
238106
239995
|
});
|
|
238107
239996
|
}
|
|
238108
239997
|
const operation = {
|
|
@@ -238139,21 +240028,17 @@ Operation ID: ${operationId}
|
|
|
238139
240028
|
} else {
|
|
238140
240029
|
let result;
|
|
238141
240030
|
if (isLocalFile) {
|
|
238142
|
-
const yamlContent = await import("fs/promises").then((
|
|
238143
|
-
result = await
|
|
240031
|
+
const yamlContent = await import("fs/promises").then((fs6) => fs6.readFile(toolToExecute.path, "utf-8"));
|
|
240032
|
+
result = await enactCore.executeRawTool(yamlContent, inputs, {
|
|
238144
240033
|
timeout: timeout3 || "120s",
|
|
238145
|
-
|
|
238146
|
-
skipVerification: true,
|
|
238147
|
-
force,
|
|
240034
|
+
force: dangerouslySkipVerification || true,
|
|
238148
240035
|
dryRun,
|
|
238149
240036
|
verbose
|
|
238150
240037
|
});
|
|
238151
240038
|
} else {
|
|
238152
|
-
result = await
|
|
240039
|
+
result = await enactCore.executeToolByName(toolToExecute.name || name, inputs, {
|
|
238153
240040
|
timeout: timeout3 || "120s",
|
|
238154
|
-
|
|
238155
|
-
skipVerification,
|
|
238156
|
-
force,
|
|
240041
|
+
force: dangerouslySkipVerification,
|
|
238157
240042
|
dryRun,
|
|
238158
240043
|
verbose
|
|
238159
240044
|
});
|
|
@@ -238242,7 +240127,7 @@ server2.registerTool("manage-local-tools", {
|
|
|
238242
240127
|
output += `\uD83D\uDCC1 Local Tools (${allTools.local.length}):
|
|
238243
240128
|
`;
|
|
238244
240129
|
allTools.local.forEach((tool) => {
|
|
238245
|
-
const relativePath = tool.path.replace(
|
|
240130
|
+
const relativePath = tool.path.replace(join6(homedir5(), ".enact", "tools"), "~/.enact/tools");
|
|
238246
240131
|
output += ` • ${tool.name} (${relativePath})
|
|
238247
240132
|
`;
|
|
238248
240133
|
if (detailed && tool.definition.description) {
|
|
@@ -238273,12 +240158,12 @@ server2.registerTool("manage-local-tools", {
|
|
|
238273
240158
|
});
|
|
238274
240159
|
return { content: [{ type: "text", text: output }] };
|
|
238275
240160
|
case "show-directory":
|
|
238276
|
-
const { promises:
|
|
238277
|
-
const enactDir =
|
|
240161
|
+
const { promises: fs6 } = await import("fs");
|
|
240162
|
+
const enactDir = join6(homedir5(), ".enact");
|
|
238278
240163
|
const scanDir = async (dirPath, prefix = "") => {
|
|
238279
240164
|
let result = "";
|
|
238280
240165
|
try {
|
|
238281
|
-
const entries = await
|
|
240166
|
+
const entries = await fs6.readdir(dirPath, {
|
|
238282
240167
|
withFileTypes: true
|
|
238283
240168
|
});
|
|
238284
240169
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
@@ -238289,7 +240174,7 @@ server2.registerTool("manage-local-tools", {
|
|
|
238289
240174
|
`;
|
|
238290
240175
|
if (["tools", "env", "cache"].includes(entry.name)) {
|
|
238291
240176
|
const nextPrefix = prefix + (isLast ? " " : "│ ");
|
|
238292
|
-
result += await scanDir(
|
|
240177
|
+
result += await scanDir(join6(dirPath, entry.name), nextPrefix);
|
|
238293
240178
|
}
|
|
238294
240179
|
} else {
|
|
238295
240180
|
let icon = entry.name.endsWith(".yaml") || entry.name.endsWith(".yml") ? "\uD83D\uDD27" : entry.name.endsWith(".env") ? "\uD83D\uDD10" : entry.name.endsWith(".json") ? "⚙️" : "\uD83D\uDCC4";
|
|
@@ -238394,7 +240279,7 @@ server2.registerTool("create-local-tool", {
|
|
|
238394
240279
|
timeout: exports_external.string().optional().describe("Execution timeout"),
|
|
238395
240280
|
inputSchema: exports_external.record(exports_external.any()).optional().describe("Input schema for the tool"),
|
|
238396
240281
|
env: exports_external.record(exports_external.any()).optional().describe("Environment variables"),
|
|
238397
|
-
|
|
240282
|
+
overwrite: exports_external.boolean().default(false).describe("Overwrite if tool already exists")
|
|
238398
240283
|
}
|
|
238399
240284
|
}, async ({
|
|
238400
240285
|
name,
|
|
@@ -238404,24 +240289,24 @@ server2.registerTool("create-local-tool", {
|
|
|
238404
240289
|
timeout: timeout3,
|
|
238405
240290
|
inputSchema,
|
|
238406
240291
|
env: env3,
|
|
238407
|
-
|
|
240292
|
+
overwrite = false
|
|
238408
240293
|
}) => {
|
|
238409
240294
|
try {
|
|
238410
|
-
const { promises:
|
|
240295
|
+
const { promises: fs6 } = await import("fs");
|
|
238411
240296
|
const yaml3 = await Promise.resolve().then(() => __toESM(require_dist3(), 1));
|
|
238412
|
-
const toolsDir =
|
|
238413
|
-
await
|
|
238414
|
-
const toolPath =
|
|
238415
|
-
if (!
|
|
240297
|
+
const toolsDir = join6(homedir5(), ".enact", "tools");
|
|
240298
|
+
await fs6.mkdir(toolsDir, { recursive: true });
|
|
240299
|
+
const toolPath = join6(toolsDir, `${name}.yaml`);
|
|
240300
|
+
if (!overwrite) {
|
|
238416
240301
|
try {
|
|
238417
|
-
await
|
|
240302
|
+
await fs6.access(toolPath);
|
|
238418
240303
|
return {
|
|
238419
240304
|
content: [
|
|
238420
240305
|
{
|
|
238421
240306
|
type: "text",
|
|
238422
240307
|
text: `❌ Tool already exists: ${toolPath}
|
|
238423
240308
|
|
|
238424
|
-
Use
|
|
240309
|
+
Use overwrite: true to overwrite, or choose a different name.`
|
|
238425
240310
|
}
|
|
238426
240311
|
],
|
|
238427
240312
|
isError: true
|
|
@@ -238443,7 +240328,7 @@ Use force: true to overwrite, or choose a different name.`
|
|
|
238443
240328
|
toolDefinition.inputSchema = inputSchema;
|
|
238444
240329
|
if (env3)
|
|
238445
240330
|
toolDefinition.env = env3;
|
|
238446
|
-
await
|
|
240331
|
+
await fs6.writeFile(toolPath, yaml3.stringify(toolDefinition, null, 2));
|
|
238447
240332
|
let output = `✅ Created local tool: ${name}
|
|
238448
240333
|
|
|
238449
240334
|
`;
|
|
@@ -238485,7 +240370,7 @@ server2.registerTool("enact-search-tools", {
|
|
|
238485
240370
|
}, async ({ query, limit = 10, tags, author, detailed = false }) => {
|
|
238486
240371
|
try {
|
|
238487
240372
|
logger_default.info(`Searching registry tools: "${query}"`);
|
|
238488
|
-
const tools = await
|
|
240373
|
+
const tools = await enactCore.searchTools({ query, limit, tags, author });
|
|
238489
240374
|
if (tools.length === 0) {
|
|
238490
240375
|
return {
|
|
238491
240376
|
content: [
|
|
@@ -238765,7 +240650,7 @@ server2.registerTool("enact-core-status", {
|
|
|
238765
240650
|
}
|
|
238766
240651
|
}, async ({ detailed = false }) => {
|
|
238767
240652
|
try {
|
|
238768
|
-
const status = await
|
|
240653
|
+
const status = await enactCore.getStatus();
|
|
238769
240654
|
const toolStats = await toolResolver.listAllTools();
|
|
238770
240655
|
let output = `\uD83D\uDD27 Enact MCP Status
|
|
238771
240656
|
`;
|
|
@@ -238780,7 +240665,7 @@ server2.registerTool("enact-core-status", {
|
|
|
238780
240665
|
`;
|
|
238781
240666
|
output += ` • API: ${status.apiUrl}
|
|
238782
240667
|
`;
|
|
238783
|
-
output += ` • Verification:
|
|
240668
|
+
output += ` • Verification: Disabled
|
|
238784
240669
|
`;
|
|
238785
240670
|
output += ` • Timeout: ${status.defaultTimeout}
|
|
238786
240671
|
|
|
@@ -238838,7 +240723,7 @@ server2.registerTool("enact-core-status", {
|
|
|
238838
240723
|
`;
|
|
238839
240724
|
output += `\uD83D\uDCC1 Directory Structure:
|
|
238840
240725
|
`;
|
|
238841
|
-
const enactDir =
|
|
240726
|
+
const enactDir = join6(homedir5(), ".enact");
|
|
238842
240727
|
output += ` • Base: ${enactDir}
|
|
238843
240728
|
`;
|
|
238844
240729
|
output += ` • Tools: ~/.enact/tools/
|
|
@@ -238902,5 +240787,5 @@ if (__require.main == __require.module) {
|
|
|
238902
240787
|
}
|
|
238903
240788
|
export {
|
|
238904
240789
|
server2 as server,
|
|
238905
|
-
|
|
240790
|
+
enactCore
|
|
238906
240791
|
};
|