UNPKG

@fedmcp/core

Version:

Federal Model Context Protocol - TypeScript implementation

129 lines 4.22 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LocalSigner = exports.Signer = void 0; exports.base64urlDecode = base64urlDecode; const crypto_1 = require("crypto"); const artifact_1 = require("./artifact"); class Signer { } exports.Signer = Signer; class LocalSigner extends Signer { constructor(privateKey) { super(); this.privateKey = null; this.publicKey = null; if (privateKey) { this.privateKey = privateKey; } this.keyId = ''; } async initialize() { if (!this.privateKey) { // Generate a new P-256 key pair const keyPair = await crypto_1.subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, true, ['sign', 'verify']); this.privateKey = keyPair.privateKey; this.publicKey = keyPair.publicKey; } else { // Extract public key from private key (if needed) // Note: Web Crypto API doesn't directly support this, would need to export/import } // Generate key ID from public key if (this.publicKey) { const publicKeyData = await crypto_1.subtle.exportKey('spki', this.publicKey); const hash = await crypto_1.subtle.digest('SHA-256', publicKeyData); this.keyId = Array.from(new Uint8Array(hash)) .slice(0, 8) .map(b => b.toString(16).padStart(2, '0')) .join(''); } } async sign(artifact) { if (!this.privateKey) { await this.initialize(); } // Validate artifact const fedArtifact = new artifact_1.FedMCPArtifact(artifact); fedArtifact.validate(); // Create JWS header const header = { alg: 'ES256', typ: 'JWT', kid: this.keyId }; // Create JWT payload const now = Math.floor(Date.now() / 1000); const payload = { iss: artifact.workspaceId, sub: artifact.id, iat: now, exp: now + (90 * 24 * 60 * 60), // 90 days artifact: artifact }; // Encode header and payload const encodedHeader = base64url(JSON.stringify(header)); const encodedPayload = base64url(JSON.stringify(payload)); // Create signing input const signingInput = `${encodedHeader}.${encodedPayload}`; // Sign with ECDSA const signature = await crypto_1.subtle.sign({ name: 'ECDSA', hash: 'SHA-256' }, this.privateKey, new TextEncoder().encode(signingInput)); // Convert signature to base64url const encodedSignature = base64url(new Uint8Array(signature)); // Return complete JWS return `${signingInput}.${encodedSignature}`; } getKeyId() { return this.keyId; } async getPublicKeyJWK() { if (!this.publicKey) { await this.initialize(); } const jwk = await crypto_1.subtle.exportKey('jwk', this.publicKey); return { ...jwk, use: 'sig', kid: this.keyId }; } } exports.LocalSigner = LocalSigner; // Helper function to encode to base64url function base64url(input) { let base64; if (typeof input === 'string') { base64 = btoa(input); } else { // Convert Uint8Array to string const binary = String.fromCharCode(...input); base64 = btoa(binary); } return base64 .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=/g, ''); } // Helper function to decode from base64url function base64urlDecode(input) { // Add padding if necessary const padded = input + '=='.slice(0, (4 - input.length % 4) % 4); // Convert base64url to base64 const base64 = padded .replace(/-/g, '+') .replace(/_/g, '/'); // Decode const binary = atob(base64); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } return bytes; } //# sourceMappingURL=signer.js.map