import { createHash, createHmac, createPrivateKey, createPublicKey, sign, verify, generateKeyPairSync, timingSafeEqual } from 'crypto';
// ═══════════════════════════════════════════════════════════════════════════════
// Ed25519 License Signing
// ═══════════════════════════════════════════════════════════════════════════════
/** ASN.1 DER prefix for Ed25519 private key (PKCS#8 wrapper around 32-byte seed) */
const ED25519_PRIVATE_DER_PREFIX = '302e020100300506032b657004220420';
/** ASN.1 DER prefix for Ed25519 public key (SubjectPublicKeyInfo wrapper around 32-byte key) */
const ED25519_PUBLIC_DER_PREFIX = '302a300506032b6570032100';
function privateKeyFromHex(hexSeed) {
    if (hexSeed.length !== 64) {
        throw new Error(`Ed25519 private key seed must be 64 hex chars (32 bytes), got ${hexSeed.length} chars`);
    }
    const der = Buffer.from(ED25519_PRIVATE_DER_PREFIX + hexSeed, 'hex');
    return createPrivateKey({ key: der, format: 'der', type: 'pkcs8' });
}
function publicKeyFromHex(hexKey) {
    if (hexKey.length !== 64) {
        throw new Error(`Ed25519 public key must be 64 hex chars (32 bytes), got ${hexKey.length} chars`);
    }
    const der = Buffer.from(ED25519_PUBLIC_DER_PREFIX + hexKey, 'hex');
    return createPublicKey({ key: der, format: 'der', type: 'spki' });
}
/**
 * Generate a new Ed25519 keypair.
 * Returns hex-encoded raw 32-byte seed (private) and 32-byte public key.
 */
export function generateEd25519Keypair() {
    const { publicKey, privateKey } = generateKeyPairSync('ed25519');
    // Export private key DER, strip the ASN.1 prefix to get raw 32-byte seed
    const privateDer = privateKey.export({ format: 'der', type: 'pkcs8' });
    const prefixLen = Buffer.from(ED25519_PRIVATE_DER_PREFIX, 'hex').length;
    const privateKeyHex = privateDer.subarray(prefixLen).toString('hex');
    // Export public key DER, strip the ASN.1 prefix to get raw 32-byte key
    const publicDer = publicKey.export({ format: 'der', type: 'spki' });
    const pubPrefixLen = Buffer.from(ED25519_PUBLIC_DER_PREFIX, 'hex').length;
    const publicKeyHex = publicDer.subarray(pubPrefixLen).toString('hex');
    return { publicKeyHex, privateKeyHex };
}
/**
 * Sign arbitrary license data with an Ed25519 private key.
 *
 * Output format: base64url(JSON payload) + '.' + base64url(signature)
 * This is NOT a JWT — it is a simple two-part signed token.
 */
export function signLicenseData(data, privateKeyHex) {
    const privKey = privateKeyFromHex(privateKeyHex);
    const payloadBytes = Buffer.from(JSON.stringify(data), 'utf-8');
    const payloadB64 = payloadBytes.toString('base64url');
    const signature = sign(null, payloadBytes, privKey);
    const sigB64 = signature.toString('base64url');
    return `${payloadB64}.${sigB64}`;
}
/**
 * Verify an Ed25519-signed license token and return the payload if valid.
 *
 * Returns null if:
 * - Token format is invalid (no dot separator)
 * - Signature verification fails
 * - Payload is not valid JSON
 */
export function verifyLicenseSignature(signed, publicKeyHex) {
    const dotIndex = signed.indexOf('.');
    if (dotIndex === -1)
        return null;
    const payloadB64 = signed.slice(0, dotIndex);
    const sigB64 = signed.slice(dotIndex + 1);
    const payloadBytes = Buffer.from(payloadB64, 'base64url');
    const sigBytes = Buffer.from(sigB64, 'base64url');
    const pubKey = publicKeyFromHex(publicKeyHex);
    const valid = verify(null, payloadBytes, pubKey, sigBytes);
    if (!valid)
        return null;
    try {
        return JSON.parse(payloadBytes.toString('utf-8'));
    }
    catch {
        return null;
    }
}
// ═══════════════════════════════════════════════════════════════════════════════
// HMAC Session Tokens (server-side only — sessionSecret never leaves the server)
// ═══════════════════════════════════════════════════════════════════════════════
export function signToken(payload, sessionSecret, expiresInMs) {
    const data = JSON.stringify({ ...payload, exp: Date.now() + expiresInMs });
    const sig = createHmac('sha256', sessionSecret).update(data).digest('base64url');
    return Buffer.from(data).toString('base64url') + '.' + sig;
}
export function verifyToken(token, sessionSecret) {
    const dotIndex = token.indexOf('.');
    if (dotIndex === -1)
        return null;
    const dataB64 = token.slice(0, dotIndex);
    const sig = token.slice(dotIndex + 1);
    const data = Buffer.from(dataB64, 'base64url').toString();
    const expected = createHmac('sha256', sessionSecret).update(data).digest('base64url');
    const sigBuf = Buffer.from(sig);
    const expectedBuf = Buffer.from(expected);
    if (sigBuf.length !== expectedBuf.length || !timingSafeEqual(sigBuf, expectedBuf))
        return null;
    let payload;
    try {
        payload = JSON.parse(data);
    }
    catch {
        return null;
    }
    if (payload.exp < Date.now())
        return null;
    return payload;
}
// ═══════════════════════════════════════════════════════════════════════════════
// Key Hashing (for database lookups)
// ═══════════════════════════════════════════════════════════════════════════════
export function hashKey(key) {
    return createHash('sha256').update(key).digest('hex');
}
//# sourceMappingURL=keys.js.map