import { randomBytes } from "node:crypto";
export const FEEDBACK_ADMIN_COOKIE = "neotoma_feedback_admin";
export const FEEDBACK_ADMIN_ALLOWED_TIERS = [
    "hardware",
    "software",
    "operator_attested",
];
const DEFAULT_CHALLENGE_TTL_MS = 5 * 60 * 1000;
const DEFAULT_SESSION_TTL_MS = 30 * 60 * 1000;
const challenges = new Map();
const sessions = new Map();
function token(bytes = 32) {
    return randomBytes(bytes).toString("base64url");
}
function challengeTtlMs() {
    const parsed = Number.parseInt(process.env.NEOTOMA_FEEDBACK_ADMIN_CHALLENGE_TTL_MS ?? "", 10);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_CHALLENGE_TTL_MS;
}
function sessionTtlMs() {
    const parsed = Number.parseInt(process.env.NEOTOMA_FEEDBACK_ADMIN_SESSION_TTL_MS ?? "", 10);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_SESSION_TTL_MS;
}
function now() {
    return Date.now();
}
function isAllowedTier(tier) {
    return !!tier && FEEDBACK_ADMIN_ALLOWED_TIERS.includes(tier);
}
function pruneExpired(at = now()) {
    for (const [key, challenge] of challenges) {
        if (challenge.expiresAt <= at)
            challenges.delete(key);
    }
    for (const [key, session] of sessions) {
        if (session.expiresAt <= at)
            sessions.delete(key);
    }
}
function sessionSnapshot(session) {
    if (!session)
        return { active: false };
    return {
        active: true,
        tier: session.tier,
        thumbprint: session.thumbprint,
        sub: session.sub,
        iss: session.iss,
        expires_at: new Date(session.expiresAt).toISOString(),
    };
}
export function createFeedbackAdminChallenge() {
    pruneExpired();
    const createdAt = now();
    const challenge = token();
    const expiresAt = createdAt + challengeTtlMs();
    challenges.set(challenge, { challenge, createdAt, expiresAt });
    return { challenge, expires_at: new Date(expiresAt).toISOString() };
}
export function redeemFeedbackAdminChallenge(challenge, identity) {
    pruneExpired();
    const record = challenges.get(challenge);
    if (!record || record.expiresAt <= now()) {
        throw new Error("Admin unlock challenge is missing or expired.");
    }
    if (!isAllowedTier(identity?.tier)) {
        throw new Error(`Admin unlock requires hardware/software/operator_attested AAuth tier. Resolved tier: ${identity?.tier ?? "anonymous"}.`);
    }
    const createdAt = now();
    const session = {
        token: token(),
        tier: identity.tier,
        thumbprint: identity.thumbprint,
        sub: identity.sub,
        iss: identity.iss,
        createdAt,
        expiresAt: createdAt + sessionTtlMs(),
    };
    sessions.set(session.token, session);
    record.sessionToken = session.token;
    return session;
}
export function readFeedbackAdminCookie(req) {
    const fromParser = req.cookies?.[FEEDBACK_ADMIN_COOKIE];
    if (fromParser)
        return fromParser;
    const raw = req.headers?.cookie;
    if (!raw)
        return undefined;
    for (const part of raw.split(";")) {
        const [name, ...rest] = part.trim().split("=");
        if (name === FEEDBACK_ADMIN_COOKIE)
            return decodeURIComponent(rest.join("="));
    }
    return undefined;
}
export function getFeedbackAdminSessionFromRequest(req) {
    pruneExpired();
    const cookie = readFeedbackAdminCookie(req);
    if (!cookie)
        return null;
    const session = sessions.get(cookie);
    if (!session || session.expiresAt <= now()) {
        if (cookie)
            sessions.delete(cookie);
        return null;
    }
    return session;
}
export function getRedeemedFeedbackAdminSession(challenge) {
    pruneExpired();
    const record = challenges.get(challenge);
    if (!record?.sessionToken)
        return null;
    const session = sessions.get(record.sessionToken);
    if (!session || session.expiresAt <= now())
        return null;
    return session;
}
export function setFeedbackAdminCookie(res, session) {
    res.cookie(FEEDBACK_ADMIN_COOKIE, session.token, {
        httpOnly: true,
        sameSite: "lax",
        path: "/",
        expires: new Date(session.expiresAt),
    });
}
export function clearFeedbackAdminCookie(res) {
    res.clearCookie(FEEDBACK_ADMIN_COOKIE, { path: "/" });
}
export function revokeFeedbackAdminSessionFromRequest(req) {
    const cookie = readFeedbackAdminCookie(req);
    if (cookie)
        sessions.delete(cookie);
}
export function describeFeedbackAdminSession(req) {
    return sessionSnapshot(getFeedbackAdminSessionFromRequest(req));
}
export function describeFeedbackAdminSessionForChallenge(challenge) {
    if (!challenge)
        return { active: false };
    return sessionSnapshot(getRedeemedFeedbackAdminSession(challenge));
}
export function clearFeedbackAdminStateForTests() {
    challenges.clear();
    sessions.clear();
}
//# sourceMappingURL=admin_session.js.map