@@ -22,6 +22,14 @@ let machineIdModule: typeof import('node-machine-id') | null = null
2222let systeminformationModule : typeof import ( 'systeminformation' ) | null = null
2323
2424const ENHANCED_FINGERPRINT_TIMEOUT_MS = 3000
25+ const LEGACY_FINGERPRINT_SUFFIX_LENGTH = 8
26+ const LEGACY_FINGERPRINT_RANDOM_BYTES = 6
27+ const BASE64URL_ALPHABET =
28+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'
29+
30+ type RandomValuesProvider = {
31+ getRandomValues : ( bytes : Uint8Array ) => Uint8Array
32+ }
2533
2634async function getMachineId ( ) : Promise < string > {
2735 if ( ! machineIdModule ) {
@@ -136,10 +144,51 @@ async function calculateEnhancedFingerprint(): Promise<string> {
136144 * Used as a fallback when enhanced fingerprinting fails.
137145 */
138146function calculateLegacyFingerprint ( ) : string {
139- const randomSuffix = randomBytes ( 6 ) . toString ( 'base64url' ) . substring ( 0 , 8 )
147+ const randomSuffix = generateLegacyFingerprintSuffix ( )
140148 return `codebuff-cli-${ randomSuffix } `
141149}
142150
151+ export function generateLegacyFingerprintSuffix (
152+ randomByteSource : ( byteCount : number ) => Uint8Array = randomBytes ,
153+ randomValuesProvider : RandomValuesProvider | undefined = globalThis . crypto ,
154+ ) : string {
155+ try {
156+ return Buffer . from ( randomByteSource ( LEGACY_FINGERPRINT_RANDOM_BYTES ) )
157+ . toString ( 'base64url' )
158+ . substring ( 0 , LEGACY_FINGERPRINT_SUFFIX_LENGTH )
159+ } catch ( err ) {
160+ logger . warn (
161+ {
162+ errorMessage : err instanceof Error ? err . message : String ( err ) ,
163+ } ,
164+ 'Node crypto randomBytes failed for legacy fingerprint suffix' ,
165+ )
166+ }
167+
168+ try {
169+ if ( randomValuesProvider ) {
170+ const bytes = new Uint8Array ( LEGACY_FINGERPRINT_RANDOM_BYTES )
171+ randomValuesProvider . getRandomValues ( bytes )
172+ return Buffer . from ( bytes )
173+ . toString ( 'base64url' )
174+ . substring ( 0 , LEGACY_FINGERPRINT_SUFFIX_LENGTH )
175+ }
176+ } catch ( err ) {
177+ logger . warn (
178+ {
179+ errorMessage : err instanceof Error ? err . message : String ( err ) ,
180+ } ,
181+ 'Web Crypto getRandomValues failed for legacy fingerprint suffix' ,
182+ )
183+ }
184+
185+ let suffix = ''
186+ for ( let i = 0 ; i < LEGACY_FINGERPRINT_SUFFIX_LENGTH ; i ++ ) {
187+ suffix += BASE64URL_ALPHABET [ Math . floor ( Math . random ( ) * BASE64URL_ALPHABET . length ) ]
188+ }
189+ return suffix
190+ }
191+
143192/**
144193 * Cached fingerprint promise. Populated on first call and reused for the
145194 * process lifetime so every auth step in a session ships the same fingerprint
0 commit comments