/**
 * localPassword — the `local-password` strategy: a password list the server
 * holds, for development, tests and a demo box. Refused in production by
 * `identityFromConfig` (Q3): a list in an environment variable is not a
 * production identity store.
 *
 * Pattern: a {@link PasswordChecker} behind the sign-in door. The door owns
 *          everything a password door must do around the check (the guard,
 *          attempt limits, one answer, a minimum response time); this file only
 *          answers "is this the password for that name?".
 *
 * ── Hashed passwords only, with scrypt ──────────────────────────────────────
 * A list entry is `name:scrypt$<log2 N>$<r>$<p>$<salt>$<key>` — never a plain
 * password. Make one with {@link hashPassword}.
 *
 * Why scrypt: it is in `node:crypto`, so it adds no dependency (argon2 needs a
 * native module; bcrypt a package), and it is memory-hard, which PBKDF2 is not.
 * The default cost is OWASP's recommended scrypt setting (N = 2^17, r = 8,
 * p = 1: 128 MiB and a noticeable fraction of a second per check — on purpose).
 * The cost travels in the hash. Anything weaker than N = 2^14, r = 8, p = 1 is
 * refused, and so is anything dearer than 256 MiB per check (128·N·r) or
 * p > 4 — a check is run for every unknown name too, so an absurd cost is a
 * denial of service on the door.
 *
 * ── One cost per list ───────────────────────────────────────────────────────
 * Every entry must carry the SAME cost. An unknown name is checked against a
 * decoy hash so it takes as long as a known one; with mixed costs no single
 * decoy can match every entry, and the time would tell which names exist. A
 * cost change (a re-hash) is therefore done for the whole list at once: this is
 * a development/test list the operator regenerates, not a live store that has
 * to migrate one person at a time as they sign in.
 *
 * ── Ids ─────────────────────────────────────────────────────────────────────
 * The one exception to "never a name a person types" (rule 7): a local
 * password's id IS its configured name, matched exactly (the door trims the
 * typed name once, as the app's own door did) — so one person cannot get two
 * owners by typing `Alice` and `alice`. Renaming someone orphans their
 * conversations.
 */
import type { PasswordChecker } from '../../hosting/signin/types.js';
/** The scrypt cost this library writes. OWASP Password Storage Cheat Sheet: N=2^17, r=8, p=1. */
export declare const SCRYPT_DEFAULT: {
    readonly log2N: 17;
    readonly r: 8;
    readonly p: 1;
};
/** The weakest cost a stored hash may carry. */
export declare const SCRYPT_FLOOR: {
    readonly log2N: 14;
    readonly r: 8;
    readonly p: 1;
};
/** The most memory one check may use: 128·N·r bytes. */
export declare const SCRYPT_MAX_BYTES: number;
/** The most parallel passes one check may run. */
export declare const SCRYPT_MAX_P = 4;
/** The cost of a hash, for {@link hashPassword}. */
export interface ScryptCost {
    readonly log2N: number;
    readonly r: number;
    readonly p: number;
}
/** A local-password list entry is refused. */
export declare class LocalPasswordConfigError extends Error {
    readonly code: "ERR_LOCAL_PASSWORD_CONFIG";
    constructor(sentence: string);
}
/**
 * Hash a password for a `local-password` list entry.
 *
 * @example
 *   // Read the password from stdin, so it never lands in shell history:
 *   //   read -rs PW && PW="$PW" node -e \
 *   //     "import('agentfootprint/security').then(m => m.hashPassword(process.env.PW)).then(console.log)"
 *   // Then SINGLE-QUOTE the list — a shell or a compose file expands `$17`:
 *   //   IDENTITY_LOCAL_USERS='priya:scrypt$17$8$1$…$…'
 */
export declare function hashPassword(password: string, cost?: ScryptCost): Promise<string>;
/**
 * The `local-password` checker over a list: `name:hash` entries, comma
 * separated (the `IDENTITY_LOCAL_USERS` form), or a `{ name: hash }` object.
 * Refused at construction: an empty list, a plain password, a malformed or
 * too-weak hash, a name with `:` `,` or a control character, a duplicate name.
 */
export declare function localPasswords(users: string | Readonly<Record<string, string>>): PasswordChecker & {
    readonly names: readonly string[];
};
//# sourceMappingURL=localPassword.d.ts.map