"use strict";
/**
 * Signed Manifest Push (W2.x infrastructure of F-NEW-PRODUCT-AGENT-VISIBILITY-CLUSTER-2026-05-12).
 *
 * Customer-side signs the discovered AgentManifest with their org private
 * key. Server-side verifies the signature against the registered org
 * public key before accepting the push. Honors Invariant 10 (push-only):
 * we never reach into customer infrastructure, and we only accept pushes
 * that cryptographically prove which org they came from.
 *
 * Signing scheme:
 *   - Algorithm: Ed25519 (small keys, fast verify, deterministic, well-supported in node:crypto).
 *   - Canonical JSON serialisation of the manifest payload (stable key
 *     ordering) prevents signature mismatches due to JSON whitespace or
 *     key-order differences across SDKs.
 *   - Signature is base64url-encoded for transit.
 *
 * Replay protection:
 *   - Payload carries `nonce` (random 16 bytes hex) + `issuedAt` (ISO 8601).
 *   - Server-side verification checks issuedAt is within MAX_AGE_SECONDS
 *     of "now". Replays older than that are rejected.
 *
 * @connexum/ai-governance  F-NEW-PRODUCT-AGENT-DISCOVERY-CLI (push transport)
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ManifestSignatureError = exports.DEFAULT_MAX_AGE_SECONDS = void 0;
exports.generateOrgKeyPair = generateOrgKeyPair;
exports.exportPublicKey = exportPublicKey;
exports.importPublicKey = importPublicKey;
exports.signManifest = signManifest;
exports.verifySignedManifest = verifySignedManifest;
const crypto = __importStar(require("node:crypto"));
/** Maximum age of a signed push, in seconds. 5 minutes by default. */
exports.DEFAULT_MAX_AGE_SECONDS = 300;
class ManifestSignatureError extends Error {
    code;
    constructor(code, message) {
        super(message);
        this.code = code;
        this.name = 'ManifestSignatureError';
    }
}
exports.ManifestSignatureError = ManifestSignatureError;
/**
 * Generate a new Ed25519 keypair. Customer runs this ONCE per org and
 * uploads the public key to us; the private key stays on their side.
 */
function generateOrgKeyPair() {
    const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519');
    return { publicKey, privateKey };
}
/** Export public key as base64url DER for transit / dashboard storage. */
function exportPublicKey(publicKey) {
    return publicKey.export({ format: 'der', type: 'spki' }).toString('base64url');
}
/** Import a previously-exported base64url DER public key. */
function importPublicKey(b64url) {
    return crypto.createPublicKey({
        key: Buffer.from(b64url, 'base64url'),
        format: 'der',
        type: 'spki',
    });
}
/** Canonical JSON serialisation: stable key ordering, no extraneous whitespace. */
function canonicalJson(value) {
    if (value === null || typeof value !== 'object')
        return JSON.stringify(value);
    if (Array.isArray(value)) {
        return '[' + value.map((v) => canonicalJson(v)).join(',') + ']';
    }
    const obj = value;
    const keys = Object.keys(obj).sort();
    return '{' + keys.map((k) => JSON.stringify(k) + ':' + canonicalJson(obj[k])).join(',') + '}';
}
function signManifest(manifest, orgId, privateKey, options = {}) {
    if (!orgId || orgId.trim() === '') {
        throw new ManifestSignatureError('MALFORMED', 'orgId is required');
    }
    const issuedAt = new Date(options.nowMs ?? Date.now()).toISOString();
    const nonce = crypto.randomBytes(16).toString('hex');
    const payload = { orgId, manifest, nonce, issuedAt };
    const canonical = canonicalJson(payload);
    const sig = crypto.sign(null, Buffer.from(canonical, 'utf8'), privateKey);
    return {
        payload,
        signature: sig.toString('base64url'),
        alg: 'ed25519',
    };
}
/**
 * Verify a signed manifest against an org public key.
 *
 * Throws ManifestSignatureError on:
 *   - bad signature (INVALID_SIGNATURE)
 *   - payload older than max-age window (EXPIRED)
 *   - malformed payload (MALFORMED)
 *   - payload.orgId !== expectedOrgId (ORG_MISMATCH)
 */
function verifySignedManifest(signed, publicKey, options) {
    if (!signed.payload || !signed.signature || signed.alg !== 'ed25519') {
        throw new ManifestSignatureError('MALFORMED', 'signed manifest missing payload / signature / alg');
    }
    if (signed.payload.orgId !== options.expectedOrgId) {
        throw new ManifestSignatureError('ORG_MISMATCH', `expected orgId ${options.expectedOrgId} but payload carries ${signed.payload.orgId}`);
    }
    // Age check
    const issuedAtMs = new Date(signed.payload.issuedAt).getTime();
    if (Number.isNaN(issuedAtMs)) {
        throw new ManifestSignatureError('MALFORMED', 'issuedAt is not a valid ISO timestamp');
    }
    const nowMs = options.nowMs ?? Date.now();
    const maxAgeMs = (options.maxAgeSeconds ?? exports.DEFAULT_MAX_AGE_SECONDS) * 1000;
    if (nowMs - issuedAtMs > maxAgeMs) {
        throw new ManifestSignatureError('EXPIRED', 'payload is older than max-age window');
    }
    if (issuedAtMs - nowMs > maxAgeMs) {
        throw new ManifestSignatureError('MALFORMED', 'payload issuedAt is in the future beyond clock-skew tolerance');
    }
    // Signature check
    const canonical = canonicalJson(signed.payload);
    const sig = Buffer.from(signed.signature, 'base64url');
    const ok = crypto.verify(null, Buffer.from(canonical, 'utf8'), publicKey, sig);
    if (!ok) {
        throw new ManifestSignatureError('INVALID_SIGNATURE', 'Ed25519 signature did not verify');
    }
    return signed.payload;
}
//# sourceMappingURL=signed-manifest.js.map