/** * @file identity-types.mts * @description Type definitions for the four-tier ibgib identity hierarchy. * * ## Tier Overview * ``` * META keystone → universal identity handle (cross-app, cross-device) * └─ LOCAL keystone → device/browser-profile-scoped identity * └─ APP-LOCAL keystone → app-scoped identity (one per app per browser profile) * └─ SESSION keystone → session-scoped (existing sync protocol) * ``` * * @see docs/identity/PARADIGM.md * @see docs/identity/KEYSTONES.md */ import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs"; import { KeystoneData_V1, KeystoneIbGib_V1 } from "@ibgib/core-gib/dist/keystone/keystone-types.mjs"; // =========================================================================== // KEYSTONE DATA EXTENSIONS — one per tier // =========================================================================== /** * Data shape for the META keystone tier. * * The META keystone is the user's universal identity — stable across all apps, * devices, and time. Its `tjpGib` is the user's permanent identity handle. * * @see docs/identity/KEYSTONES.md#meta-keystone * @see docs/identity/PARADIGM.md#meta-keystone */ export interface MetaKeystoneData extends KeystoneData_V1 { /** * List of LOCAL keystone `tjpGib` values currently trusted by this identity. * * This is the **trust register** — an app verifies a user by finding the * LOCAL keystone's tjpGib in this list from the current META frame. * * Mutated by: add-device evolution (append), remove-device evolution (remove). * * @see docs/identity/PARADIGM.md#cross-app-identity */ trustedLocalTjpGibs: IbGibAddr[]; /** * For custodial keystones: the publicly-visible nonce used by the custodian * to re-derive `MasterSecret_user = KDF(server_secret, custodialNonce)`. * * No secrecy requirement — security comes from `server_secret` alone. * Stored here so the custodian needs no separate mapping table. * * Undefined for sovereign (user-held) keystones. * * @see docs/identity/PARADIGM.md#custodianship--the-oauth2-path * @see docs/identity/FLOWS.md#flow-2-first-login--custodial-path-oauth2 */ custodialNonce?: string; } /** * Data shape for the LOCAL keystone tier. * * Device/browser-profile-scoped identity. Evolves offline. Lives in IndexedDB. * One per browser profile per user. * * @see docs/identity/KEYSTONES.md#local-keystone */ export interface LocalKeystoneData extends KeystoneData_V1 { /** * Map of registered APP-LOCAL keystones on this browser profile. * * Key: `appId` * Value: the **first epoch** APP-LOCAL keystone `tjpGib` for that app. * * Subsequent epochs are authenticated transitively through the APP-LOCAL * epoch chain — the LOCAL keystone does NOT need to evolve for epoch rotation. * * Mutated by: add-app evolution (set), remove-app evolution (delete). * * @see docs/identity/PARADIGM.md#epoch-rotation-handling-keystone-growth */ registeredAppLocals: Record; } /** * Data shape for the APP-LOCAL keystone tier. * * App-scoped identity for a specific browser profile + app combination. * Evolves offline. Lives in IndexedDB (client) and app server (synced). * One per app per browser profile per user. * * @see docs/identity/KEYSTONES.md#app-local-keystone */ export interface AppLocalKeystoneData extends KeystoneData_V1 { /** The app identifier this APP-LOCAL belongs to. */ appId: string; /** * The LOCAL keystone `tjpGib` this APP-LOCAL is derived from. * Used by verifiers to link APP-LOCAL trust back to LOCAL → META. */ localTjpGib: IbGibAddr; /** * The META keystone `tjpGib` for this identity. * Stored for reference/display. The authoritative trust chain is * always verified by replaying META → LOCAL → APP-LOCAL. */ metaTjpGib: IbGibAddr; /** * For epoch-chained APP-LOCAL keystones: the ibgib address of the * **final frame** of the previous epoch. Establishes the transitive * trust chain from the first epoch. * * Undefined for the first epoch (no prior epoch). * * @see docs/identity/PARADIGM.md#epoch-rotation-handling-keystone-growth */ prevEpochFinalFrameAddr?: IbGibAddr; } // =========================================================================== // BROWSER LOCAL CONTEXT (IndexedDB) // =========================================================================== /** * The browser-local identity context for a user on this browser profile. * Stored in IndexedDB. Reconstructed from keystone chains if lost. * * @see docs/identity/FLOWS.md#flow-3-return-login--same-browser-profile * @see docs/identity/PARTIES.md#party-app-client */ export interface LocalIdentityContext { /** The user's universal identity handle. Used for cross-app identity. */ metaTjpGib: IbGibAddr; /** URL of the identity service hosting the user's META keystone. */ identityServiceUrl: string; /** This browser profile's LOCAL keystone `tjpGib`. */ localTjpGib: IbGibAddr; } /** * Per-app identity context for a specific browser profile + app. * Stored in IndexedDB by the app client. * * @see docs/identity/KEYSTONES.md#app-local-keystone */ export interface AppLocalIdentityContext { /** The user's universal identity handle. */ metaTjpGib: IbGibAddr; /** This browser profile's LOCAL keystone `tjpGib`. */ localTjpGib: IbGibAddr; /** * The **current** (possibly epoch-N) APP-LOCAL keystone `tjpGib`. * Updated in-place after each epoch rotation. */ appLocalTjpGib: IbGibAddr; /** The app identifier. */ appId: string; } // =========================================================================== // IDENTITY SERVICE (Shared Space) INTERFACE // =========================================================================== /** * The shared identity space — a write-verifying history store. * * NOT an authority. Verifies chain continuity on writes. Serves raw chain * data on reads. Any party can independently verify the chain it returns. * * Initial deployment: hosted on the app's server. Federated by design. * * @see docs/identity/PARADIGM.md#the-shared-identity-space * @see docs/identity/PARTIES.md#party-identity-service */ export interface IIdentityService { /** * POST a genesis frame — accepted unconditionally if internally valid. * Genesis is self-legitimizing: Alice's identity IS her genesis frame. * * @returns the `tjpGib` (ibgib address of the genesis frame) * @throws if the frame is internally invalid (malformed structure) */ postGenesis(frame: KeystoneIbGib_V1): Promise<{ tjpGib: IbGibAddr }>; /** * POST an evolution frame. * Verifies chain continuity: revealed solutions must hash-match prior * frame's commitments. Implements CAS: rejects if prior frame is stale. * * @throws `IdentityServiceStaleTipError` if prior frame is no longer tip * @throws `IdentityServiceChainError` if hash pre-images are invalid */ postEvolution(frame: KeystoneIbGib_V1): Promise; /** * GET the full keystone chain from genesis to current tip. * * Does NOT change state. Safe to call without coordination. */ getChain(tjpGib: IbGibAddr): Promise; /** * GET the current tip frame for a keystone. * * Does NOT change state. */ getTip(tjpGib: IbGibAddr): Promise; } // =========================================================================== // MASTERSECRET DERIVATION // =========================================================================== /** * Inputs for deriving a tier-specific MasterSecret from a root password. * * Each tier uses a different salt to ensure independent MasterSecrets * even when the same password is used for all tiers. * * @see docs/identity/KEYSTONES.md for per-tier salt conventions * @see identity-helpers.mts for derivation functions */ export interface MasterSecretDerivationContext { /** The root password (sovereign path) or server secret (custodial path). */ password: string; /** * Tier-specific salt (e.g., `IDENTITY_KDF_SALT_META`, `IDENTITY_KDF_SALT_LOCAL`). * @see identity-constants.mts */ salt: string; /** * Additional device-specific entropy for LOCAL and APP-LOCAL tiers. * Generated once per browser profile and stored in IndexedDB. */ deviceSalt?: string; /** For APP-LOCAL tier: the app identifier, mixed into derivation. */ appId?: string; }