export interface AccessUserEntry { userId: string; pin: string; phone?: string; accessHash?: string; [k: string]: unknown; } /** * Identity + destination for one credential-store audit line. The writers are * pure (they only know the file paths); the caller is the only party that knows * WHO is acting and WHERE the audit log lives, so it is threaded in. `actor` is * an admin userId or a non-user sentinel (`onboarding` | `install` | `boot` | * `unknown` when an MCP caller has no resolvable USER_ID); `session` is the * spawning agent session (SESSION_NODE_ID) when one drove the write. `logFile` * is the absolute path to the append-only users-audit log, distinct from * server.log. Mirrored in platform/lib/admins-write. */ export interface AuditContext { actor: string; session?: string; logFile: string; /** Task 1573 — the row being written, recorded on every credential write so * `actor != target` is the standing cross-identity signature. Omitted => * the line carries no target field (a self write not routed through the * identity-resolving tools). */ target?: string; /** Task 1573 — true when the caller passed an explicit `userId` (a deliberate * cross-identity or self write); false/absent for an implicit self write. */ explicitUserId?: boolean; } export declare function hashAccessPassword(password: string): Promise; declare function matchesHash(password: string, stored: string): Promise; /** * Write `accessHash` onto the userId's record. Throws if the record is absent, * or if `password` already verifies against a DIFFERENT record — uniqueness is * an invariant of this writer, so no path (including ones that skip the * call-site pre-check) can create a credential a login scan would resolve * ambiguously. */ export declare function setAccessPassword(userId: string, password: string, usersFile: string, audit: AuditContext): Promise; /** Remove `accessHash` from the userId's record. No-op (no write, no audit * line) when the record is absent or already carries no accessHash. */ export declare function clearAccessPassword(userId: string, usersFile: string, audit: AuditContext): void; /** Return the userId whose accessHash matches, or null. */ export declare function verifyAccessPassword(password: string, usersFile: string): Promise; /** * True when some admin OTHER than excludeUserId already has an accessHash that * matches `password`. Used by the set/change surfaces to refuse a value that * would collide with another admin's perimeter credential — the scan-based * verify attributes a login to the first matching record, so two admins sharing * a password lets one silently overwrite the other. An unreadable store returns * false: the subsequent write is what owns the read-fault error path. */ export declare function accessPasswordCollides(password: string, usersFile: string, excludeUserId: string): Promise; /** True when at least one record carries an accessHash. */ export declare function anyAccessPasswordConfigured(usersFile: string): boolean; /** * True when users.json is present on disk but cannot be read or parsed. The * gate's `isRemoteAuthConfigured` checks this so a transient read fault on a * configured install fails CLOSED (stays "configured" → login screen, not the * setup flow) instead of downgrading to "unconfigured". A genuinely absent or * cleanly-empty store is NOT unreadable. */ export declare function accessStoreUnreadable(usersFile: string): boolean; export type MigrateResult = 'migrated' | 'noop-no-legacy' | 'noop-no-owner' | 'noop-owner-has-hash'; /** * One-time, idempotent. If the legacy single-password file exists and the * owner record has no accessHash, copy the legacy hash (already scrypt * "salt:hash") onto the owner and delete the legacy file. If the owner already * has an accessHash, the legacy file is stale → delete it. If no owner record * exists yet, leave the legacy file untouched (verify still reads it as a * candidate during this window — see readLegacyRemoteHash). */ export declare function migrateLegacyRemotePassword(usersFile: string, legacyFile: string, ownerUserId: string, audit: AuditContext): MigrateResult; /** Read a still-present legacy single-password hash, or null. Used by verify * as one additional candidate before the boot migration runs. */ export declare function readLegacyRemoteHash(legacyFile: string): string | null; export { matchesHash as verifyHashCandidate }; //# sourceMappingURL=index.d.ts.map