/** * Per-device fingerprint computation. * * The fingerprint is the SDK's answer to "is this still the same * device that started the test?" -- a stable hash over a handful * of low-entropy browser+device properties that change when the * candidate switches laptops, switches browsers, or plugs in a * different camera. Mid-session changes are interesting (and * suspicious); changes between two attempts on the same machine * are not. * * What goes in (all read synchronously, all safe to read in * boot before the worker is up): * - userAgent + platform browser + OS family * - language region hint * - screen geometry primary monitor signature * - devicePixelRatio retina vs non-retina * - hardwareConcurrency logical CPU count * - deviceMemory RAM bucket (Chromium-only) * - timezone region/IANA zone * * Camera groupId is *not* part of the initial fingerprint * because mediaDevices.enumerateDevices needs an * already-granted permission. The runtime SDK boots before any * permission flow; including groupId there would make the * fingerprint change the moment the camera is picked. Camera * identity belongs in the canonical embedding (phase 8), not * here. * * What goes out: a stable 16-hex-char id + the raw record. The * id is what gets stamped on events + headers; the record is * what the server's PreflightAttempt row stores so a proctor * can diff two attempts side by side. */ /** * Raw fingerprint inputs. Stored on `PreflightAttempt.fingerprint` * (the JSONB column) for forensic diffing. Mirrors what the * legacy session.fingerprint event already emits -- we will * dedupe with that event in a follow-up. */ export interface DeviceFingerprint { userAgent: string | null; platform: string | null; language: string | null; timezone: string | null; screen: { width: number; height: number; availWidth: number; availHeight: number; colorDepth: number; } | null; devicePixelRatio: number | null; hardwareConcurrency: number | null; deviceMemory: number | null; } export interface FingerprintResult { /** * Stable 16-char hex id derived from the canonical-serialised * fingerprint inputs. Same inputs -> same id every time. Same * across reloads on the same machine + browser; different * across browsers, devices, or major OS upgrades. */ fingerprintId: string; fingerprint: DeviceFingerprint; } /** * Compute the fingerprint synchronously. Safe to call in * environments without a `navigator` (SSR/tests/workers) -- it * just returns an "unknown" record with a stable sentinel id so * the rest of the pipeline never has to special-case the null * case. */ export declare function computeDeviceFingerprint(): FingerprintResult; /** * Per-tab lock token for the single-active-session lock. Stored in * `sessionStorage`, so it **survives a refresh** (same tab keeps resuming) but * is **unique per tab** (a second tab gets its own → the server can tell them * apart and block the duplicate). Falls back to a fresh per-call token when * `sessionStorage` is unavailable (SSR, private mode, blocked storage) — the * lock then degrades to "no cross-refresh identity" rather than breaking. */ export declare function getTabLockToken(): string; export declare function hashFingerprint(fp: DeviceFingerprint): string; //# sourceMappingURL=index.d.ts.map