export declare class UnsafeHostAuthorityFileError extends Error { constructor(message: string); } /** Create/resolve the parent without ever resolving the final path component. */ export declare function secureHostFilePath(filePath: string): string; /** Return null only for a genuinely absent leaf; unsafe shapes fail closed. */ export declare function readSecureHostFileSync(filePath: string, maxBytes?: number): string | null; /** Strict, durable atomic replace that never follows a leaf symlink. */ export declare function writeSecureHostFileSync(filePath: string, data: string): void; /** * A pinned view of the credential directory that stays valid ONLY for the * synchronous duration of the callback. On Linux every operation resolves * through the opened directory descriptor (`/proc/self/fd/`), so an * ancestor rename/replacement after acquisition cannot redirect subsequent * lock/read/write operations into an attacker-substituted directory. On other * platforms (and Linux without procfs) the parent is the canonical real path * and the strict ancestor-chain check has already run. * * The handle is single-use and fail-closed. It deliberately exposes NO raw * filesystem path: the `/proc/self/fd/` anchor is a live capability that * cannot be revoked once handed out as a string, so a caller could stash it, * let the fd be recycled after release, and hand the stale string to `fs` or a * lock — landing on a directory that never passed the 0700/owner checks. Every * capability is therefore a method that re-checks `active` at call time: once * the owning {@link withSecureHostParentSync} call returns and releases the * descriptor, `readLeaf`/`writeLeaf`/`withLeafLock` throw * {@link UnsafeHostAuthorityFileError} instead of touching the recycled fd. */ export interface SecureHostParentHandle { /** Basename of the credential leaf (informational; carries no path capability). */ readonly leafName: string; /** Read the pinned leaf (fail-closed on unsafe shapes); null if absent. */ readLeaf(maxBytes?: number): string | null; /** Durably, atomically replace the pinned leaf without following a symlink. */ writeLeaf(data: string): void; /** * Run `fn` while holding a cross-process advisory lock on the pinned leaf, * serialized against other processes doing the same get-or-create. The lock * path is derived from the internal anchor and never exposed, so it cannot be * reused after release. `fn` must be synchronous (see {@link NonThenable}). */ withLeafLock(fn: () => NonThenable): R; } /** * `T` constrained to a non-thenable so an `async` callback (or any callback * returning a Promise) is a compile-time error. The pinned descriptor is * released synchronously when the callback returns; an awaited continuation * would run after release, on a possibly-recycled fd. See * {@link withSecureHostParentSync}. */ type NonThenable = T extends PromiseLike ? never : T; /** * Acquire the secure parent directory once and expose it to `fn` as a pinned * handle for the SYNCHRONOUS duration of the call, releasing the descriptor * afterwards. Use this instead of chaining {@link secureHostFilePath} + * independent read/write calls when a credential needs a serialized * get-or-create (lock → read → write): resolving the lock and the leaf through * the same descriptor keeps the whole critical section on one directory inode. * Unlike {@link secureHostFilePath}, this does not force the strict * ancestor-chain assertion on Linux — the pinned descriptor already makes later * operations independent of ancestor renames — so it works under a symlinked * HOME or a shared-drive/0777 ancestor while `~/.botmux` itself stays 0700 and * owned by the current user. * * Fail-closed lifetime: `fn` MUST be synchronous. The `NonThenable` return * bound rejects `async`/Promise-returning callbacks at compile time; the handle * exposes no raw path (only guarded methods); and every method re-checks * `active` at runtime — after this function returns, any escaped handle traps * instead of touching the released (and possibly fd-recycled) anchor. */ export declare function withSecureHostParentSync(filePath: string, fn: (handle: SecureHostParentHandle) => NonThenable): T; /** Strict durable unlink. Returns false only if the leaf is absent. */ export declare function unlinkSecureHostFileSync(filePath: string): boolean; export {}; //# sourceMappingURL=secure-host-file.d.ts.map