UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

95 lines (94 loc) • 4.75 kB
/** * directory/ldapDirectory — the {@link Directory} port over LDAPS, through * `ldapts` (an optional peer, loaded lazily — the `jose` precedent). * * LDAPS only: `ldap://` would send the password in the clear on the bind, and * StartTLS needs the same DC certificate LDAPS does, so refusing it loses * nothing real. The certificate chain is checked against EITHER the CA the * operator supplies (`caPem`) OR — said in so many words, `systemCa: true` — * Node's default CA store, and the host name against the URL. There is no * switch to skip either check, and no default between the two trusts. * * ── What to trust: the ROOT ───────────────────────────────────────────────── * Trust the CA at the top of the DC certificate's chain, never the DC's own * certificate (refused at construction: it is not a CA) or an intermediate. * A DC certificate is renewed every few months, and an intermediate is * replaced on its own schedule; a root lives for years. Trusting the root * means a renewal — a new leaf, even a new intermediate the DC sends in its * chain — needs no change here. A DC certificate issued by a PUBLIC CA chains * to a root Node already ships (`systemCa: true`); a company CA does not, so * give its root as `caPem`. */ import type { Directory } from './port.js'; /** The slice of `ldapts` this adapter uses, declared structurally. */ export interface LdaptsBackend { Client: new (options: Record<string, unknown>) => { bind(name: string, password?: string): Promise<void>; exop(oid: string): Promise<{ oid?: string; value?: string; }>; search(base: string, options: Record<string, unknown>): Promise<{ searchEntries: Record<string, unknown>[]; }>; unbind(): Promise<void>; }; } export interface LdapDirectoryOptions { /** `ldaps://dc1.corp.example:636`. `ldap://` is refused. */ readonly url: string; /** * The CA certificate(s), PEM, the DC's certificate must chain to — the * company's ROOT CA. Exactly one of this and `systemCa`. */ readonly caPem?: string; /** * `true`: trust Node's default CA store instead of a file — the public * roots Node ships (Mozilla's list), plus `NODE_EXTRA_CA_CERTS`, plus the * operating system's store when Node runs with `--use-system-ca`. For a DC * whose certificate a PUBLIC CA issued. Exactly one of this and `caPem`; * the host-name check stays on either way. */ readonly systemCa?: true; /** Connect and operation timeout, ms. Default 5000. */ readonly timeoutMs?: number; /** An already-imported `ldapts`. */ readonly backend?: LdaptsBackend; /** * Told why the directory could not answer — never reached (with the * connection or TLS error's CODE, e.g. `UNABLE_TO_VERIFY_LEAF_SIGNATURE` * for a CA that does not issue the DC's certificate, * `ERR_TLS_CERT_ALTNAME_INVALID` for a name it does not carry), or failed * after the bind was sent. For the operator; never the password, the name * or an error's text. A REFUSED bind is not logged here: its AD sub-code * travels in the bind's answer to the sign-in door's audit record. */ readonly log?: (line: string) => void; } /** Raised when `directory-password` is configured and `ldapts` is not installed. */ export declare class MissingLdaptsError extends Error { readonly code: "ERR_MISSING_LDAPTS"; constructor(); } export declare function ldapDirectory(options: LdapDirectoryOptions): Directory; /** * Every certificate block in a PEM bundle, in order — what * `pem.match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g)` * finds, in one pass. The regex re-reads the rest of the bundle from every * BEGIN line that has no END after it, which is quadratic on a file of * repeated BEGIN lines; once a BEGIN has no END after it, no later one has * either, so the scan stops there. */ export declare function pemCertificateBlocks(pem: string): string[]; /** * Why a CA file is not one, or `undefined`: every PEM block must parse as an * X.509 certificate with the CA flag set (review idI57 N-10 — a leaf * certificate booted, then failed every sign-in). */ export declare function caPemProblem(caPem: unknown): string | undefined; /** * The subjects of the CA certificates in a PEM bundle that are NOT * self-signed roots — intermediates. Trusting one alone breaks at the next * renewal that changes it, so boot says so (`directory-password`'s banner). */ export declare function intermediateCaSubjects(caPem: string): string[];