/**
 * hosting/signin/door — the sign-in door: the routes under `/auth` that start
 * and end a sign-in. Nothing it handles is a turn or enters a run's record.
 *
 * Pattern: a plain `(req, res) → handled?` handler an app mounts in front of
 *          its own routes (`nodeHost({ onUnhandled })`), like the app's own
 *          `/auth` routes before it.
 *
 *   GET  /auth/config  → `{ mode: 'password', passwordKind: 'directory' | 'local' }`
 *                        (`passwordKind` when the checker declares its `kind`)
 *   GET  /auth/me      → `{ displayName, accountKey, expiresAt }` or 401
 *   POST /auth/login   → the password sign-in (below)
 *   POST /auth/logout  → end the sign-in, expire the cookie, close its sockets
 *
 * ── `POST /auth/login`, in order ────────────────────────────────────────────
 *  1. The door guard, UNCONDITIONALLY — a login carries no credential, so a
 *     gate keyed on "a credential came in" would never run on it, and a forged
 *     cross-site login signs a victim into the attacker's account (login
 *     forgery). Host, Origin, and `content-type: application/json` (so a form
 *     cannot post it).
 *  2. The body is read by THIS door, capped, and a bad one gets a fixed
 *     sentence: a JSON parser's own message quotes the input, and the input is
 *     a password.
 *  3. Attempt limits (per typed name and per client address), with a growing
 *     delay before any refusal.
 *  4. A sign-in cookie already present is ENDED first.
 *  5. The password is checked. Every wrong credential gets ONE answer.
 *  6. A new sign-in: 256 random bits in the cookie, only their SHA-256 in the
 *     store.
 *  Every answer waits until a minimum time has passed, so "no such user" and
 *  "wrong password" cannot be told apart by how fast they come back. The
 *  minimum is a DURATION, so it is measured on the monotonic clock
 *  (`performance.now()`) and waited in full (`lib/sleep`) — never on the epoch
 *  clock `now`, which counts whole milliseconds (an answer up to 1 ms early)
 *  and jumps when the system time is set (an hour ahead: an answer at once).
 *
 * ── The cookie (§5.4) ───────────────────────────────────────────────────────
 * `__Host-Http-af-signin=…; Path=/; HttpOnly; Secure; SameSite=Strict;
 * Max-Age=<lifetime>` — no `Domain`. On a plain-`http` localhost public URL
 * (development only; refused in production) the browser would drop a
 * `__Host-` cookie, so the name is `af-signin` and `Secure` is left off — the
 * banner says so.
 *
 * Every `/auth` response carries `Cache-Control: no-store` and forbids framing,
 * and none carries a CORS header.
 */
/// <reference types="node" />
import type { IncomingMessage, ServerResponse } from 'node:http';
import { type CrossSiteOptions } from '../doorGuard.js';
import type { DoorIdentity, IdentityVerifier } from '../identityVerification.js';
import { type CheckGateOptions } from './checkGate.js';
import { type AttemptLimits } from './limits.js';
import { type SignInAuditSink } from './audit.js';
import { type SealKey } from './seal.js';
import { type SignIns } from './source.js';
import { type HostSignInOptions, type PasswordChecker, type RedirectSignIn, type SignInStore } from './types.js';
export interface SignInDoorOptions {
    /** A password strategy (`localPasswords(…)`) — `POST /auth/login`. Exactly one of this and `redirect`. */
    readonly passwords?: PasswordChecker;
    /**
     * A redirect strategy (`oidcSignIn(…)`) — `GET /auth/login` and
     * `GET /auth/callback`. Exactly one of this and `passwords`.
     */
    readonly redirect?: RedirectSignIn;
    /**
     * Bearer tokens accepted beside the sign-in cookie (scripts, the bench): the
     * strategy's own `verify`. Put into {@link SignInDoor.identity}.
     */
    readonly verify?: IdentityVerifier['verify'];
    /**
     * The key that seals redirect transaction cookies — 32 bytes, shared by
     * replicas (`IDENTITY_COOKIE_KEY_FILE`). Unset: random per process, and the
     * banner says a restart invalidates sign-ins in progress.
     */
    readonly cookieKey?: SealKey;
    /** Where sign-ins are kept (`memorySignIns()`). */
    readonly store: SignInStore;
    /**
     * The URL people open the app at. Decides the cookie: `https` → the
     * `__Host-Http-` cookie with `Secure`; `http` only on a loopback host, and
     * only outside production.
     */
    readonly publicUrl: string;
    /** Is this production? Supplied by the app, never guessed. */
    readonly production: boolean;
    /** The door guard's lists — the SAME ones the host uses. `publicUrl` must pass them. */
    readonly guard?: CrossSiteOptions;
    /** The absolute lifetime of a sign-in, hours. Default 8. */
    readonly hours?: number;
    /** Minutes of inactivity after which a sign-in ends. Default 60 under a password, 30 under a redirect (signing in again is silent there). */
    readonly idleMinutes?: number;
    /** Attempt limits on `POST /auth/login`. */
    readonly limits?: AttemptLimits;
    /**
     * Every login answer waits at least this long, ms. Default 400. Measured on
     * the monotonic clock from the moment the login starts — never on `now`.
     */
    readonly minimumResponseMs?: number;
    /**
     * Peers whose `X-Forwarded-For` is believed: the client address is then the
     * rightmost hop that is not one of them. Unset, `X-Forwarded-For` is ignored.
     */
    readonly trustedProxies?: readonly string[];
    /** The route prefix. Default `/auth`. */
    readonly prefix?: string;
    /**
     * The clock, epoch ms: sign-in lifetimes and attempt windows. Default
     * `Date.now`. Not the minimum answer time (`minimumResponseMs`).
     */
    readonly now?: () => number;
    /** The door-wide cap on concurrent password checks (default 4 running, 32 waiting). */
    readonly checks?: CheckGateOptions;
    /** Where a one-time operator warning goes. Default `console.warn`. */
    readonly warn?: (message: string) => void;
    /**
     * The audit trail, typed: called once per sign-in outcome — signed in,
     * refused, limited, unavailable, signed out, expired — with the account,
     * the client address (after `trustedProxies`), the time, the strategy and,
     * on `directory-password`, AD's sub-code and its name. Never a password, a
     * cookie, a token or an error's message. See {@link SignInAuditRecord}.
     * A sink that throws is contained and reported once through `warn`.
     *
     * @example
     *   onAudit: (record) => {
     *     if (record.outcome !== 'signed-in') securityLog.write(record);
     *   }
     */
    readonly onAudit?: SignInAuditSink;
    /**
     * Where the door writes ONE structured line per sign-in outcome — the same
     * record as `onAudit`, as `[identity] sign-in {"time":"…","outcome":…}`.
     * Default `console.info`, so an install has its audit trail with no code;
     * pass `() => {}` to keep it out of the process log.
     */
    readonly log?: (line: string) => void;
    /** Test seam — inject the door's waits: the attempt delay and the minimum answer time. */
    readonly _sleep?: (ms: number) => Promise<void>;
}
export interface SignInDoor {
    /** Answer one request if it is under the prefix; resolves whether it was. Never rejects. */
    handle(req: IncomingMessage, res: ServerResponse): Promise<boolean>;
    /** The sign-ins this door starts and ends — what `identity: { signIn }` takes. */
    readonly signIns: SignIns;
    /** The cookie's name. */
    readonly cookieName: string;
    /** What the host takes: `nodeHost({ signIn: door.hostSignIn })`. */
    readonly hostSignIn: HostSignInOptions;
    /** What `standingAgent({ identity })` takes. */
    readonly identity: DoorIdentity;
    /** Lines for the boot banner. No secrets. */
    readonly banner: readonly string[];
}
export { SignInDoorConfigError } from './errors.js';
/** A sign-in's idle limit by door mode, when `idleMinutes` is not given. */
export declare const DEFAULT_IDLE_MINUTES: {
    readonly password: 60;
    readonly redirect: 30;
};
/** The one answer every wrong credential gets. */
export declare const WRONG_CREDENTIAL_SENTENCE = "That username and password did not sign you in.";
export declare function signInDoor(options: SignInDoorOptions): SignInDoor;
/** A 128-bit key for the page's caches: one per person, not the id itself. */
export declare function accountKeyOf(userId: string): string;
export interface CookieShape {
    readonly name: string;
    readonly secure: boolean;
    readonly url: URL;
    issue(value: string, maxAgeSeconds: number): string;
    expired(): string;
    /** The per-attempt transaction cookie's name. */
    txName(attempt: string): string;
    /** A transaction cookie: `SameSite=Lax` (it must come back on the IdP's redirect), 10 minutes. */
    issueTx(attempt: string, sealed: string): string;
    expireTx(attempt: string): string;
}
