Wire hardware-based CLI fingerprint into login flow#528
Conversation
The enhanced hardware fingerprint (machine-id + CPU + MAC + hostname, SHA-256) in cli/src/utils/fingerprint.ts existed but was never imported, so every login path used Math.random() and every session.fingerprint_id was unique — killing any multi-account clustering signal (maxFpShare/maxSigShare stuck at 1). Cache the promise once per process and pull the id into login-store so both TUI login and plain-text login ship the same hardware hash. Pre-fetch during initializeApp so it's resolved by the time the user hits Enter. Dropped two dead duplicates of generateFingerprintId and the unused login-modal-utils.ts. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Greptile SummaryThis PR wires the existing hardware-based Key changes:
Confidence Score: 5/5Safe to merge; the single P2 is a defensive style improvement that doesn't affect correctness today. No P0/P1 issues found. The ordering invariant that makes cli/src/hooks/use-login-polling.ts — the implicit null guard (P2 suggestion only) Important Files Changed
Sequence DiagramsequenceDiagram
participant App as initializeApp
participant FP as fingerprint.ts
participant Modal as LoginModal
participant Store as login-store
participant Poll as useLoginPolling
participant API as Login API
App->>FP: void getFingerprintId() [pre-warm]
Note over FP: starts calculateFingerprint() promise,<br/>caches it in cachedFingerprintPromise
Note over Modal: user presses Enter
Modal->>FP: await getFingerprintId()
FP-->>Modal: "enhanced-<hash>" (or legacy fallback)
Modal->>Store: setFingerprintId(id)
Modal->>API: fetchLoginUrlMutation.mutate(id)
API-->>Modal: { loginUrl, fingerprintHash, expiresAt }
Modal->>Store: setFingerprintHash / setExpiresAt / setLoginUrl
Poll->>Store: reads fingerprintId, fingerprintHash
Note over Poll: guard: all 4 values non-null?
Poll->>API: pollLoginStatus({ fingerprintId, fingerprintHash, ... })
API-->>Poll: { status: "success", user }
Poll->>Modal: onSuccess(user)
Reviews (1): Last reviewed commit: "Wire hardware-based CLI fingerprint into..." | Re-trigger Greptile |
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
With the new hardware-based fingerprint, legit users on shared dev machines, Docker images with baked-in /etc/machine-id, CI runners, and corporate golden images can all produce the same fingerprint. Hard-blocking in that case would lock out coworkers behind whichever user logged in first. Keep the "Fingerprint ownership conflict" warn log as input for async abuse review, but always proceed to createCliSession so the signal never gates login on its own. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
The hardware-based fingerprint in
cli/src/utils/fingerprint.ts(machine-id + CPU + MAC + hostname → SHA-256) existed but was never imported — every login path usedMath.random(), so everysession.fingerprint_idrow was unique and multi-account clustering signals (maxFpShare/maxSigShare) were stuck at 1.This wires
getFingerprintId()into both the TUI login modal and the plain-text login, caches the promise once per process, and pre-fetches duringinitializeAppso it's resolved by the time the user hits Enter. The resolved id lives inlogin-storeso polling reads from the same place that set it. Addednode-machine-idas an explicit CLI dep (previously only transitive via nx). Applies to both codebuff and freebuff since both build from the samecli/source.Also deletes two dead duplicates of
generateFingerprintIdand the fully-unusedcli/src/components/login-modal-utils.ts.Test plan
fingerprint_idnow starts withenhanced-…fingerprint_idcodebuff login) also produces theenhanced-prefix🤖 Generated with Claude Code