// engine/reviewer-tokens/signer.ts — HMAC-SHA256 sign/verify for reviewer tokens (SPEC-722)
import { randomBytes } from 'node:crypto';
import { readFile, writeFile, mkdir, appendFile } from 'node:fs/promises';
import { join, dirname } from 'node:path';
import { fastHmacSign, fastHmacVerify } from '../core-bridge.js';
const SECRET_FILENAME = '.planu-secret';
const GITIGNORE_ENTRY = '.planu-secret\n';
let cachedSecret = null;
/**
 * Load (or generate) the HMAC secret from `projectPath/.planu-secret`.
 * On first call, generates 32 random bytes and writes them to disk.
 * Also ensures `.planu-secret` is listed in `.gitignore`.
 */
export async function loadSecret(projectPath) {
    if (cachedSecret !== null) {
        return cachedSecret;
    }
    const secretPath = join(projectPath, SECRET_FILENAME);
    try {
        const raw = await readFile(secretPath, 'utf-8');
        cachedSecret = raw.trim();
        return cachedSecret;
    }
    catch {
        // File does not exist — generate and persist.
        const secret = randomBytes(32).toString('hex');
        await mkdir(dirname(secretPath), { recursive: true });
        await writeFile(secretPath, secret, { encoding: 'utf-8', mode: 0o600 });
        await ensureGitignore(projectPath);
        cachedSecret = secret;
        return secret;
    }
}
/** Ensure `.planu-secret` is present in `.gitignore`. */
async function ensureGitignore(projectPath) {
    const gitignorePath = join(projectPath, '.gitignore');
    try {
        const existing = await readFile(gitignorePath, 'utf-8');
        if (existing.includes(SECRET_FILENAME)) {
            return;
        }
        await appendFile(gitignorePath, `\n${GITIGNORE_ENTRY}`);
    }
    catch {
        // .gitignore absent — create it.
        await writeFile(gitignorePath, GITIGNORE_ENTRY, 'utf-8');
    }
}
/**
 * Canonical JSON serialisation for signing.
 * Sort keys so signature is deterministic regardless of property order.
 */
export function canonicalJson(obj) {
    return JSON.stringify(obj, Object.keys(obj).sort());
}
/** Compute HMAC-SHA256 over `data` using `secret`. Returns hex digest. */
export function hmacSign(secret, data) {
    return fastHmacSign(secret, data);
}
/** Verify a previously computed HMAC-SHA256 signature. Constant-time compare via crypto. */
export function hmacVerify(secret, data, signature) {
    return fastHmacVerify(secret, data, signature);
}
/** Reset cached secret (test helper only — not exported from index). */
export function _resetSecretCache() {
    cachedSecret = null;
}
//# sourceMappingURL=signer.js.map