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