@enactprotocol/shared 1.2.8 → 1.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { EnactToolDefinition, ToolUsage, ToolSearchQuery, CLITokenCreate, OAuthTokenExchange } from "./types";
1
+ import { EnactToolDefinition, ToolSignaturePayload, ToolUsage, ToolSearchQuery, CLITokenCreate, OAuthTokenExchange } from "./types";
2
2
  export declare class EnactApiClient {
3
3
  baseUrl: string;
4
4
  supabaseUrl: string;
@@ -100,6 +100,7 @@ export declare class EnactApiClient {
100
100
  * Get a user's public key
101
101
  */
102
102
  getUserPublicKey(userId: string): Promise<any>;
103
+ signTool(toolId: string, payload: ToolSignaturePayload, token: string, tokenType?: "jwt" | "cli"): Promise<any>;
103
104
  /**
104
105
  * Generate OAuth authorization URL
105
106
  */
@@ -343,6 +343,13 @@ export class EnactApiClient {
343
343
  throw new EnactApiError("Unknown error occurred", 0);
344
344
  }
345
345
  }
346
+ async signTool(toolId, payload, token, tokenType = "cli") {
347
+ const endpoint = `/functions/v1/tools/${encodeURIComponent(toolId)}/signatures`;
348
+ return this.makeRequest(endpoint, {
349
+ method: "POST",
350
+ body: JSON.stringify(payload),
351
+ }, token, tokenType);
352
+ }
346
353
  // ===================
347
354
  // OAUTH FLOW HELPERS
348
355
  // ===================
@@ -1,6 +1,7 @@
1
1
  export interface EnactToolDefinition {
2
2
  name: string;
3
3
  description: string;
4
+ verified?: boolean;
4
5
  command: string;
5
6
  from?: string;
6
7
  version?: string;
@@ -89,3 +90,14 @@ export interface EnactExecOptions {
89
90
  dangerouslySkipVerification?: boolean;
90
91
  mount?: string;
91
92
  }
93
+ export interface ToolSignaturePayload {
94
+ algorithm: "sha256";
95
+ created: string;
96
+ key_id: string;
97
+ public_key: string;
98
+ role: "author";
99
+ signer: string;
100
+ timestamp: number;
101
+ type: "ecdsa-p256";
102
+ value: string;
103
+ }
@@ -1,4 +1,5 @@
1
1
  import type { EnactTool, ExecutionResult } from "../types.js";
2
+ import { EnactToolDefinition } from "../api/types.js";
2
3
  export interface EnactCoreOptions {
3
4
  apiUrl?: string;
4
5
  supabaseUrl?: string;
@@ -67,6 +68,7 @@ export declare class EnactCore {
67
68
  * Execute a tool by name
68
69
  */
69
70
  executeToolByName(name: string, inputs?: Record<string, any>, options?: ToolExecuteOptions): Promise<ExecutionResult>;
71
+ static checkToolVerificationStatus(tool: EnactToolDefinition): Promise<boolean>;
70
72
  private verifyTool;
71
73
  /**
72
74
  * Execute a tool directly
@@ -5,7 +5,7 @@ import { DaggerExecutionProvider } from "./DaggerExecutionProvider.js";
5
5
  import { resolveToolEnvironmentVariables } from "../utils/env-loader.js";
6
6
  import logger from "../exec/logger.js";
7
7
  import yaml from "yaml";
8
- import { CryptoUtils, SecurityConfigManager, SigningService } from "@enactprotocol/security";
8
+ import { SecurityConfigManager, SigningService } from "@enactprotocol/security";
9
9
  import { getFrontendUrl, getApiUrl } from "../utils/config";
10
10
  export class EnactCore {
11
11
  constructor(options = {}) {
@@ -278,6 +278,33 @@ export class EnactCore {
278
278
  };
279
279
  }
280
280
  }
281
+ static async checkToolVerificationStatus(tool) {
282
+ const documentForVerification = {
283
+ command: tool.command,
284
+ description: tool.description,
285
+ from: tool.from,
286
+ name: tool.name,
287
+ signatures: tool.signatures?.map(sig => ({
288
+ signature: sig.value,
289
+ publicKey: "", // TODO: Look up the correct public key
290
+ algorithm: sig.algorithm,
291
+ timestamp: new Date(sig.created).getTime(),
292
+ })),
293
+ };
294
+ let isValid = false;
295
+ if (tool.signatures && tool.signatures.length > 0) {
296
+ isValid = tool.signatures.some(sig => {
297
+ const referenceSignature = {
298
+ signature: sig.value,
299
+ publicKey: "", // TODO: Lookup correct public key based on signature UUID
300
+ algorithm: sig.algorithm,
301
+ timestamp: new Date(sig.created).getTime()
302
+ };
303
+ return SigningService.verifyDocument(documentForVerification, referenceSignature, { includeFields: ['command', 'description', 'from', 'name'] });
304
+ });
305
+ }
306
+ return isValid;
307
+ }
281
308
  async verifyTool(tool, dangerouslySkipVerification = false) {
282
309
  if (dangerouslySkipVerification) {
283
310
  logger.warn(`Skipping signature verification for tool: ${tool.name}`);
@@ -287,28 +314,33 @@ export class EnactCore {
287
314
  if (!tool.signatures || tool.signatures.length === 0) {
288
315
  throw new Error(`Tool ${tool.name} does not have any signatures`);
289
316
  }
290
- const documentForVerification = {
291
- command: tool.command,
292
- description: tool.description,
293
- from: tool.from,
294
- name: tool.name,
295
- };
296
- const referenceSignature = {
297
- signature: tool.signatures[0].value,
298
- publicKey: "", // Correct public key for UUID 71e02e2c-148c-4534-9900-bd9646e99333
299
- algorithm: tool.signatures[0].algorithm,
300
- timestamp: new Date(tool.signatures[0].created).getTime()
301
- };
302
- // Check what canonical document looks like
303
- const canonicalDoc = SigningService.getCanonicalDocument(documentForVerification, { includeFields: ['command', 'description', 'from', 'name'] });
304
- const docString = JSON.stringify(canonicalDoc);
305
- const messageHash = CryptoUtils.hash(docString);
306
- // Test direct crypto verification
307
- const directVerify = CryptoUtils.verify(referenceSignature.publicKey, messageHash, referenceSignature.signature);
317
+ // const documentForVerification = {
318
+ // command: tool.command,
319
+ // description: tool.description,
320
+ // from: tool.from,
321
+ // name: tool.name,
322
+ // };
323
+ // const referenceSignature = {
324
+ // signature: tool.signatures[0].value,
325
+ // publicKey: "", // Correct public key for UUID 71e02e2c-148c-4534-9900-bd9646e99333
326
+ // algorithm: tool.signatures[0].algorithm,
327
+ // timestamp: new Date(tool.signatures[0].created).getTime()
328
+ // };
329
+ // // Check what canonical document looks like
330
+ // const canonicalDoc = SigningService.getCanonicalDocument(documentForVerification, { includeFields: ['command', 'description', 'from', 'name'] }
331
+ // );
332
+ // const docString = JSON.stringify(canonicalDoc);
333
+ // const messageHash = CryptoUtils.hash(docString);
334
+ // // Test direct crypto verification
335
+ // const directVerify = CryptoUtils.verify(
336
+ // referenceSignature.publicKey,
337
+ // messageHash,
338
+ // referenceSignature.signature
339
+ // );
308
340
  // Check trusted keys
309
341
  // const trustedKeys = KeyManager.getAllTrustedPublicKeys();
310
- const isValid = SigningService.verifyDocument(documentForVerification, referenceSignature, { includeFields: ['command', 'description', 'from', 'name'] });
311
- // console.log("Final verification result:", isValid);
342
+ const isValid = await EnactCore.checkToolVerificationStatus(tool);
343
+ console.log("Final verification result:", isValid);
312
344
  if (!isValid) {
313
345
  throw new Error(`Tool ${tool.name} has invalid signatures`);
314
346
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enactprotocol/shared",
3
- "version": "1.2.8",
3
+ "version": "1.2.9",
4
4
  "description": "Shared utilities and core functionality for Enact Protocol",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  EnactToolDefinition,
3
+ ToolSignaturePayload,
3
4
  ToolUsage,
4
5
  ToolSearchQuery,
5
6
  CLITokenCreate,
@@ -480,6 +481,20 @@ export class EnactApiClient {
480
481
  throw new EnactApiError("Unknown error occurred", 0);
481
482
  }
482
483
  }
484
+
485
+ async signTool(
486
+ toolId: string,
487
+ payload: ToolSignaturePayload,
488
+ token: string,
489
+ tokenType: "jwt" | "cli" = "cli"
490
+ ): Promise<any> {
491
+ const endpoint = `/functions/v1/tools/${encodeURIComponent(toolId)}/signatures`;
492
+
493
+ return this.makeRequest(endpoint, {
494
+ method: "POST",
495
+ body: JSON.stringify(payload),
496
+ }, token, tokenType);
497
+ }
483
498
 
484
499
  // ===================
485
500
  // OAUTH FLOW HELPERS
package/src/api/types.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export interface EnactToolDefinition {
2
2
  name: string;
3
3
  description: string;
4
+ verified?: boolean; // Indicates if the tool has been verified
4
5
  command: string;
5
6
  from?: string;
6
7
  version?: string;
@@ -99,3 +100,15 @@ export interface EnactExecOptions {
99
100
  dangerouslySkipVerification?: boolean; // Skip all signature verification (DANGEROUS)
100
101
  mount?: string; // Mount local directory to container (format: "local:container")
101
102
  }
103
+
104
+ export interface ToolSignaturePayload {
105
+ algorithm: "sha256";
106
+ created: string; // Time of signing
107
+ key_id: string; // ID of the private key
108
+ public_key: string; // The corresponding public key
109
+ role: "author";
110
+ signer: string; // The userID of the signer
111
+ timestamp: number;
112
+ type: "ecdsa-p256";
113
+ value: string; // Signature
114
+ }
@@ -19,6 +19,7 @@ import fs from "fs";
19
19
  import path from "path";
20
20
  import { CryptoUtils, KeyManager, SecurityConfigManager, SigningService } from "@enactprotocol/security";
21
21
  import { getFrontendUrl, getApiUrl } from "../utils/config";
22
+ import { EnactToolDefinition } from "../api/types.js";
22
23
 
23
24
  export interface EnactCoreOptions {
24
25
  apiUrl?: string;
@@ -408,6 +409,43 @@ export class EnactCore {
408
409
  }
409
410
  }
410
411
 
412
+ public static async checkToolVerificationStatus(tool: EnactToolDefinition): Promise<boolean> {
413
+ const documentForVerification = {
414
+ command: tool.command,
415
+ description: tool.description,
416
+ from: tool.from,
417
+ name: tool.name,
418
+ signatures: tool.signatures?.map(sig => ({
419
+ signature: sig.value,
420
+ publicKey: "", // TODO: Look up the correct public key
421
+ algorithm: sig.algorithm,
422
+ timestamp: new Date(sig.created).getTime(),
423
+ })),
424
+ };
425
+
426
+ let isValid = false;
427
+
428
+ if (tool.signatures && tool.signatures.length > 0) {
429
+ isValid = tool.signatures.some(sig => {
430
+ const referenceSignature = {
431
+ signature: sig.value,
432
+ publicKey: "", // TODO: Lookup correct public key based on signature UUID
433
+ algorithm: sig.algorithm,
434
+ timestamp: new Date(sig.created).getTime()
435
+ };
436
+
437
+ return SigningService.verifyDocument(
438
+ documentForVerification,
439
+ referenceSignature,
440
+ { includeFields: ['command', 'description', 'from', 'name'] }
441
+ );
442
+ });
443
+ }
444
+
445
+ return isValid;
446
+ }
447
+
448
+
411
449
  private async verifyTool(tool: EnactTool, dangerouslySkipVerification: boolean = false): Promise<void> {
412
450
  if (dangerouslySkipVerification) {
413
451
  logger.warn(`Skipping signature verification for tool: ${tool.name}`);
@@ -419,46 +457,42 @@ private async verifyTool(tool: EnactTool, dangerouslySkipVerification: boolean =
419
457
  throw new Error(`Tool ${tool.name} does not have any signatures`);
420
458
  }
421
459
 
422
- const documentForVerification = {
423
- command: tool.command,
424
- description: tool.description,
425
- from: tool.from,
426
- name: tool.name,
427
- };
428
-
429
- const referenceSignature = {
430
- signature: tool.signatures[0].value,
431
- publicKey: "", // Correct public key for UUID 71e02e2c-148c-4534-9900-bd9646e99333
432
- algorithm: tool.signatures[0].algorithm,
433
- timestamp: new Date(tool.signatures[0].created).getTime()
434
- };
460
+ // const documentForVerification = {
461
+ // command: tool.command,
462
+ // description: tool.description,
463
+ // from: tool.from,
464
+ // name: tool.name,
465
+ // };
466
+
467
+ // const referenceSignature = {
468
+ // signature: tool.signatures[0].value,
469
+ // publicKey: "", // Correct public key for UUID 71e02e2c-148c-4534-9900-bd9646e99333
470
+ // algorithm: tool.signatures[0].algorithm,
471
+ // timestamp: new Date(tool.signatures[0].created).getTime()
472
+ // };
435
473
 
436
474
 
437
- // Check what canonical document looks like
438
- const canonicalDoc = SigningService.getCanonicalDocument(documentForVerification, { includeFields: ['command', 'description', 'from', 'name'] }
439
- );
475
+ // // Check what canonical document looks like
476
+ // const canonicalDoc = SigningService.getCanonicalDocument(documentForVerification, { includeFields: ['command', 'description', 'from', 'name'] }
477
+ // );
440
478
 
441
- const docString = JSON.stringify(canonicalDoc);
442
- const messageHash = CryptoUtils.hash(docString);
479
+ // const docString = JSON.stringify(canonicalDoc);
480
+ // const messageHash = CryptoUtils.hash(docString);
443
481
 
444
482
 
445
- // Test direct crypto verification
446
- const directVerify = CryptoUtils.verify(
447
- referenceSignature.publicKey,
448
- messageHash,
449
- referenceSignature.signature
450
- );
483
+ // // Test direct crypto verification
484
+ // const directVerify = CryptoUtils.verify(
485
+ // referenceSignature.publicKey,
486
+ // messageHash,
487
+ // referenceSignature.signature
488
+ // );
451
489
 
452
490
  // Check trusted keys
453
491
  // const trustedKeys = KeyManager.getAllTrustedPublicKeys();
454
492
 
455
- const isValid = SigningService.verifyDocument(
456
- documentForVerification,
457
- referenceSignature,
458
- { includeFields: ['command', 'description', 'from', 'name'] }
459
- );
493
+ const isValid = await EnactCore.checkToolVerificationStatus(tool);
460
494
 
461
- // console.log("Final verification result:", isValid);
495
+ console.log("Final verification result:", isValid);
462
496
 
463
497
  if (!isValid) {
464
498
  throw new Error(`Tool ${tool.name} has invalid signatures`);