/** * Time-boxed cross-tier delegation tokens. * * A higher-tier user can issue a delegation that grants another user * temporary access to records at a specified tier. The delegation is * persisted as an encrypted envelope in the reserved `_delegations` * collection. The target user's runtime scans this collection on every * open and, while `until` is still in the future, merges the * unwrapped tier DEKs into their in-memory DEK map. * * ## Token shape * * ``` * { * id, // ULID, also the _delegations record id * toUser, // grantee user id * fromUser, // grantor user id (owner/admin/higher-tier principal) * tier, // tier being delegated * collection, // collection name OR null for "every collection" * record, // optional specific record id * until, // ISO timestamp — token expires at this instant * wrappedDek, // base64 AES-KW-wrapped tier DEK, wrapped under target KEK * createdAt, // ISO timestamp * } * ``` * * The ciphertext is stored as a normal noy-db envelope — the * `_delegations` collection has its own DEK shared across all vault * users, so an operator can enumerate active delegations for audit * without being able to *use* them (the `wrappedDek` inside is still * keyed to the target user's KEK). * * ## Revocation * * Delete the `_delegations/` envelope. The target user's runtime * reloads the delegation list at each open and at periodic intervals * (tracked by the caller — this module is pure logic). * * @module */ import type { NoydbStore } from '../../kernel/types.js'; import type { UnlockedKeyring } from './keyring.js'; import { type EnclaveKey } from '../../kernel/enclave/index.js'; export declare const DELEGATIONS_COLLECTION = "_delegations"; /** * Durable payload of a delegation token. Encrypted under the vault's * `_delegations` DEK; the `wrappedDek` inside is additionally wrapped * under the target user's KEK. */ export interface DelegationToken { readonly id: string; readonly toUser: string; readonly fromUser: string; readonly tier: number; /** Collection name or `null` for all collections. */ readonly collection: string | null; /** Optional specific record id scope. */ readonly record?: string; readonly until: string; readonly wrappedDek: string; readonly createdAt: string; } export interface IssueDelegationOptions { readonly toUser: string; readonly tier: number; readonly collection?: string; readonly record?: string; readonly until: Date | string; } /** * Build and persist a delegation token. The caller must hold a tier-N * DEK and must have already located the target user's keyring file * (so the `wrappedDek` can be re-wrapped against their KEK). */ export declare function issueDelegation(store: NoydbStore, vault: string, grantor: UnlockedKeyring, targetKek: EnclaveKey | null, delegationsDek: EnclaveKey, opts: IssueDelegationOptions): Promise; /** * Enumerate every live (non-expired) delegation addressed to `toUser` * and merge the unwrapped tier DEKs into their keyring. Returns the * list of merged delegations so the caller can register per-access * audit context. */ export declare function loadActiveDelegations(store: NoydbStore, vault: string, user: UnlockedKeyring, delegationsDek: EnclaveKey, now?: Date): Promise; /** * Revoke a delegation by id — the caller resolves the envelope and * issues a `delete`. Provided as a stable helper so the naming is * symmetric to `issueDelegation`. */ export declare function revokeDelegation(store: NoydbStore, vault: string, id: string): Promise;