camou 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,38 +6,485 @@ export declare const launchInputSchema: z.ZodObject<{
6
6
  configJson: z.ZodOptional<z.ZodString>;
7
7
  prefsPath: z.ZodOptional<z.ZodString>;
8
8
  prefsJson: z.ZodOptional<z.ZodString>;
9
+ fingerprintPath: z.ZodOptional<z.ZodString>;
10
+ fingerprintJson: z.ZodOptional<z.ZodString>;
11
+ fingerprint: z.ZodOptional<z.ZodObject<{
12
+ locales: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
13
+ region: z.ZodOptional<z.ZodString>;
14
+ geolocation: z.ZodOptional<z.ZodObject<{
15
+ latitude: z.ZodNumber;
16
+ longitude: z.ZodNumber;
17
+ accuracy: z.ZodOptional<z.ZodNumber>;
18
+ timezone: z.ZodOptional<z.ZodString>;
19
+ region: z.ZodOptional<z.ZodString>;
20
+ webrtcIpv4: z.ZodOptional<z.ZodString>;
21
+ webrtcIpv6: z.ZodOptional<z.ZodString>;
22
+ }, "strip", z.ZodTypeAny, {
23
+ latitude: number;
24
+ longitude: number;
25
+ accuracy?: number | undefined;
26
+ timezone?: string | undefined;
27
+ region?: string | undefined;
28
+ webrtcIpv4?: string | undefined;
29
+ webrtcIpv6?: string | undefined;
30
+ }, {
31
+ latitude: number;
32
+ longitude: number;
33
+ accuracy?: number | undefined;
34
+ timezone?: string | undefined;
35
+ region?: string | undefined;
36
+ webrtcIpv4?: string | undefined;
37
+ webrtcIpv6?: string | undefined;
38
+ }>>;
39
+ screenProfile: z.ZodOptional<z.ZodString>;
40
+ screen: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodObject<{
41
+ profile: z.ZodOptional<z.ZodString>;
42
+ width: z.ZodOptional<z.ZodNumber>;
43
+ height: z.ZodOptional<z.ZodNumber>;
44
+ availWidth: z.ZodOptional<z.ZodNumber>;
45
+ availHeight: z.ZodOptional<z.ZodNumber>;
46
+ availTop: z.ZodOptional<z.ZodNumber>;
47
+ availLeft: z.ZodOptional<z.ZodNumber>;
48
+ colorDepth: z.ZodOptional<z.ZodNumber>;
49
+ pixelDepth: z.ZodOptional<z.ZodNumber>;
50
+ devicePixelRatio: z.ZodOptional<z.ZodNumber>;
51
+ }, "strip", z.ZodTypeAny, {
52
+ profile?: string | undefined;
53
+ width?: number | undefined;
54
+ height?: number | undefined;
55
+ availWidth?: number | undefined;
56
+ availHeight?: number | undefined;
57
+ availTop?: number | undefined;
58
+ availLeft?: number | undefined;
59
+ colorDepth?: number | undefined;
60
+ pixelDepth?: number | undefined;
61
+ devicePixelRatio?: number | undefined;
62
+ }, {
63
+ profile?: string | undefined;
64
+ width?: number | undefined;
65
+ height?: number | undefined;
66
+ availWidth?: number | undefined;
67
+ availHeight?: number | undefined;
68
+ availTop?: number | undefined;
69
+ availLeft?: number | undefined;
70
+ colorDepth?: number | undefined;
71
+ pixelDepth?: number | undefined;
72
+ devicePixelRatio?: number | undefined;
73
+ }>]>>;
74
+ windowProfile: z.ZodOptional<z.ZodString>;
75
+ window: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodObject<{
76
+ profile: z.ZodOptional<z.ZodString>;
77
+ width: z.ZodOptional<z.ZodNumber>;
78
+ height: z.ZodOptional<z.ZodNumber>;
79
+ innerWidth: z.ZodOptional<z.ZodNumber>;
80
+ innerHeight: z.ZodOptional<z.ZodNumber>;
81
+ outerWidth: z.ZodOptional<z.ZodNumber>;
82
+ outerHeight: z.ZodOptional<z.ZodNumber>;
83
+ screenX: z.ZodOptional<z.ZodNumber>;
84
+ screenY: z.ZodOptional<z.ZodNumber>;
85
+ devicePixelRatio: z.ZodOptional<z.ZodNumber>;
86
+ historyLength: z.ZodOptional<z.ZodNumber>;
87
+ }, "strip", z.ZodTypeAny, {
88
+ profile?: string | undefined;
89
+ width?: number | undefined;
90
+ height?: number | undefined;
91
+ devicePixelRatio?: number | undefined;
92
+ innerWidth?: number | undefined;
93
+ innerHeight?: number | undefined;
94
+ outerWidth?: number | undefined;
95
+ outerHeight?: number | undefined;
96
+ screenX?: number | undefined;
97
+ screenY?: number | undefined;
98
+ historyLength?: number | undefined;
99
+ }, {
100
+ profile?: string | undefined;
101
+ width?: number | undefined;
102
+ height?: number | undefined;
103
+ devicePixelRatio?: number | undefined;
104
+ innerWidth?: number | undefined;
105
+ innerHeight?: number | undefined;
106
+ outerWidth?: number | undefined;
107
+ outerHeight?: number | undefined;
108
+ screenX?: number | undefined;
109
+ screenY?: number | undefined;
110
+ historyLength?: number | undefined;
111
+ }>]>>;
112
+ fonts: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
113
+ fontSpacingSeed: z.ZodOptional<z.ZodNumber>;
114
+ blockImages: z.ZodOptional<z.ZodBoolean>;
115
+ blockWebRtc: z.ZodOptional<z.ZodBoolean>;
116
+ blockWebGl: z.ZodOptional<z.ZodBoolean>;
117
+ disableCoop: z.ZodOptional<z.ZodBoolean>;
118
+ }, "strip", z.ZodTypeAny, {
119
+ region?: string | undefined;
120
+ locales?: string | string[] | undefined;
121
+ geolocation?: {
122
+ latitude: number;
123
+ longitude: number;
124
+ accuracy?: number | undefined;
125
+ timezone?: string | undefined;
126
+ region?: string | undefined;
127
+ webrtcIpv4?: string | undefined;
128
+ webrtcIpv6?: string | undefined;
129
+ } | undefined;
130
+ screenProfile?: string | undefined;
131
+ screen?: string | {
132
+ profile?: string | undefined;
133
+ width?: number | undefined;
134
+ height?: number | undefined;
135
+ availWidth?: number | undefined;
136
+ availHeight?: number | undefined;
137
+ availTop?: number | undefined;
138
+ availLeft?: number | undefined;
139
+ colorDepth?: number | undefined;
140
+ pixelDepth?: number | undefined;
141
+ devicePixelRatio?: number | undefined;
142
+ } | undefined;
143
+ windowProfile?: string | undefined;
144
+ window?: string | {
145
+ profile?: string | undefined;
146
+ width?: number | undefined;
147
+ height?: number | undefined;
148
+ devicePixelRatio?: number | undefined;
149
+ innerWidth?: number | undefined;
150
+ innerHeight?: number | undefined;
151
+ outerWidth?: number | undefined;
152
+ outerHeight?: number | undefined;
153
+ screenX?: number | undefined;
154
+ screenY?: number | undefined;
155
+ historyLength?: number | undefined;
156
+ } | undefined;
157
+ fonts?: string[] | undefined;
158
+ fontSpacingSeed?: number | undefined;
159
+ blockImages?: boolean | undefined;
160
+ blockWebRtc?: boolean | undefined;
161
+ blockWebGl?: boolean | undefined;
162
+ disableCoop?: boolean | undefined;
163
+ }, {
164
+ region?: string | undefined;
165
+ locales?: string | string[] | undefined;
166
+ geolocation?: {
167
+ latitude: number;
168
+ longitude: number;
169
+ accuracy?: number | undefined;
170
+ timezone?: string | undefined;
171
+ region?: string | undefined;
172
+ webrtcIpv4?: string | undefined;
173
+ webrtcIpv6?: string | undefined;
174
+ } | undefined;
175
+ screenProfile?: string | undefined;
176
+ screen?: string | {
177
+ profile?: string | undefined;
178
+ width?: number | undefined;
179
+ height?: number | undefined;
180
+ availWidth?: number | undefined;
181
+ availHeight?: number | undefined;
182
+ availTop?: number | undefined;
183
+ availLeft?: number | undefined;
184
+ colorDepth?: number | undefined;
185
+ pixelDepth?: number | undefined;
186
+ devicePixelRatio?: number | undefined;
187
+ } | undefined;
188
+ windowProfile?: string | undefined;
189
+ window?: string | {
190
+ profile?: string | undefined;
191
+ width?: number | undefined;
192
+ height?: number | undefined;
193
+ devicePixelRatio?: number | undefined;
194
+ innerWidth?: number | undefined;
195
+ innerHeight?: number | undefined;
196
+ outerWidth?: number | undefined;
197
+ outerHeight?: number | undefined;
198
+ screenX?: number | undefined;
199
+ screenY?: number | undefined;
200
+ historyLength?: number | undefined;
201
+ } | undefined;
202
+ fonts?: string[] | undefined;
203
+ fontSpacingSeed?: number | undefined;
204
+ blockImages?: boolean | undefined;
205
+ blockWebRtc?: boolean | undefined;
206
+ blockWebGl?: boolean | undefined;
207
+ disableCoop?: boolean | undefined;
208
+ }>>;
9
209
  preset: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
10
210
  proxy: z.ZodOptional<z.ZodString>;
11
211
  locale: z.ZodOptional<z.ZodString>;
212
+ locales: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
213
+ region: z.ZodOptional<z.ZodString>;
12
214
  timezone: z.ZodOptional<z.ZodString>;
215
+ screenProfile: z.ZodOptional<z.ZodString>;
216
+ screen: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodObject<{
217
+ profile: z.ZodOptional<z.ZodString>;
218
+ width: z.ZodOptional<z.ZodNumber>;
219
+ height: z.ZodOptional<z.ZodNumber>;
220
+ availWidth: z.ZodOptional<z.ZodNumber>;
221
+ availHeight: z.ZodOptional<z.ZodNumber>;
222
+ availTop: z.ZodOptional<z.ZodNumber>;
223
+ availLeft: z.ZodOptional<z.ZodNumber>;
224
+ colorDepth: z.ZodOptional<z.ZodNumber>;
225
+ pixelDepth: z.ZodOptional<z.ZodNumber>;
226
+ devicePixelRatio: z.ZodOptional<z.ZodNumber>;
227
+ }, "strip", z.ZodTypeAny, {
228
+ profile?: string | undefined;
229
+ width?: number | undefined;
230
+ height?: number | undefined;
231
+ availWidth?: number | undefined;
232
+ availHeight?: number | undefined;
233
+ availTop?: number | undefined;
234
+ availLeft?: number | undefined;
235
+ colorDepth?: number | undefined;
236
+ pixelDepth?: number | undefined;
237
+ devicePixelRatio?: number | undefined;
238
+ }, {
239
+ profile?: string | undefined;
240
+ width?: number | undefined;
241
+ height?: number | undefined;
242
+ availWidth?: number | undefined;
243
+ availHeight?: number | undefined;
244
+ availTop?: number | undefined;
245
+ availLeft?: number | undefined;
246
+ colorDepth?: number | undefined;
247
+ pixelDepth?: number | undefined;
248
+ devicePixelRatio?: number | undefined;
249
+ }>]>>;
250
+ windowProfile: z.ZodOptional<z.ZodString>;
251
+ window: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodObject<{
252
+ profile: z.ZodOptional<z.ZodString>;
253
+ width: z.ZodOptional<z.ZodNumber>;
254
+ height: z.ZodOptional<z.ZodNumber>;
255
+ innerWidth: z.ZodOptional<z.ZodNumber>;
256
+ innerHeight: z.ZodOptional<z.ZodNumber>;
257
+ outerWidth: z.ZodOptional<z.ZodNumber>;
258
+ outerHeight: z.ZodOptional<z.ZodNumber>;
259
+ screenX: z.ZodOptional<z.ZodNumber>;
260
+ screenY: z.ZodOptional<z.ZodNumber>;
261
+ devicePixelRatio: z.ZodOptional<z.ZodNumber>;
262
+ historyLength: z.ZodOptional<z.ZodNumber>;
263
+ }, "strip", z.ZodTypeAny, {
264
+ profile?: string | undefined;
265
+ width?: number | undefined;
266
+ height?: number | undefined;
267
+ devicePixelRatio?: number | undefined;
268
+ innerWidth?: number | undefined;
269
+ innerHeight?: number | undefined;
270
+ outerWidth?: number | undefined;
271
+ outerHeight?: number | undefined;
272
+ screenX?: number | undefined;
273
+ screenY?: number | undefined;
274
+ historyLength?: number | undefined;
275
+ }, {
276
+ profile?: string | undefined;
277
+ width?: number | undefined;
278
+ height?: number | undefined;
279
+ devicePixelRatio?: number | undefined;
280
+ innerWidth?: number | undefined;
281
+ innerHeight?: number | undefined;
282
+ outerWidth?: number | undefined;
283
+ outerHeight?: number | undefined;
284
+ screenX?: number | undefined;
285
+ screenY?: number | undefined;
286
+ historyLength?: number | undefined;
287
+ }>]>>;
288
+ fonts: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
289
+ fontSpacingSeed: z.ZodOptional<z.ZodNumber>;
290
+ blockImages: z.ZodOptional<z.ZodBoolean>;
291
+ blockWebRtc: z.ZodOptional<z.ZodBoolean>;
292
+ blockWebGl: z.ZodOptional<z.ZodBoolean>;
293
+ disableCoop: z.ZodOptional<z.ZodBoolean>;
13
294
  width: z.ZodOptional<z.ZodNumber>;
14
295
  height: z.ZodOptional<z.ZodNumber>;
15
296
  browser: z.ZodOptional<z.ZodString>;
16
297
  }, "strip", z.ZodTypeAny, {
298
+ width?: number | undefined;
299
+ height?: number | undefined;
300
+ timezone?: string | undefined;
301
+ region?: string | undefined;
302
+ locales?: string | string[] | undefined;
303
+ screenProfile?: string | undefined;
304
+ screen?: string | {
305
+ profile?: string | undefined;
306
+ width?: number | undefined;
307
+ height?: number | undefined;
308
+ availWidth?: number | undefined;
309
+ availHeight?: number | undefined;
310
+ availTop?: number | undefined;
311
+ availLeft?: number | undefined;
312
+ colorDepth?: number | undefined;
313
+ pixelDepth?: number | undefined;
314
+ devicePixelRatio?: number | undefined;
315
+ } | undefined;
316
+ windowProfile?: string | undefined;
317
+ window?: string | {
318
+ profile?: string | undefined;
319
+ width?: number | undefined;
320
+ height?: number | undefined;
321
+ devicePixelRatio?: number | undefined;
322
+ innerWidth?: number | undefined;
323
+ innerHeight?: number | undefined;
324
+ outerWidth?: number | undefined;
325
+ outerHeight?: number | undefined;
326
+ screenX?: number | undefined;
327
+ screenY?: number | undefined;
328
+ historyLength?: number | undefined;
329
+ } | undefined;
330
+ fonts?: string[] | undefined;
331
+ fontSpacingSeed?: number | undefined;
332
+ blockImages?: boolean | undefined;
333
+ blockWebRtc?: boolean | undefined;
334
+ blockWebGl?: boolean | undefined;
335
+ disableCoop?: boolean | undefined;
336
+ locale?: string | undefined;
17
337
  headless?: boolean | undefined;
18
338
  configPath?: string | undefined;
19
339
  configJson?: string | undefined;
20
340
  prefsPath?: string | undefined;
21
341
  prefsJson?: string | undefined;
342
+ fingerprintPath?: string | undefined;
343
+ fingerprintJson?: string | undefined;
344
+ fingerprint?: {
345
+ region?: string | undefined;
346
+ locales?: string | string[] | undefined;
347
+ geolocation?: {
348
+ latitude: number;
349
+ longitude: number;
350
+ accuracy?: number | undefined;
351
+ timezone?: string | undefined;
352
+ region?: string | undefined;
353
+ webrtcIpv4?: string | undefined;
354
+ webrtcIpv6?: string | undefined;
355
+ } | undefined;
356
+ screenProfile?: string | undefined;
357
+ screen?: string | {
358
+ profile?: string | undefined;
359
+ width?: number | undefined;
360
+ height?: number | undefined;
361
+ availWidth?: number | undefined;
362
+ availHeight?: number | undefined;
363
+ availTop?: number | undefined;
364
+ availLeft?: number | undefined;
365
+ colorDepth?: number | undefined;
366
+ pixelDepth?: number | undefined;
367
+ devicePixelRatio?: number | undefined;
368
+ } | undefined;
369
+ windowProfile?: string | undefined;
370
+ window?: string | {
371
+ profile?: string | undefined;
372
+ width?: number | undefined;
373
+ height?: number | undefined;
374
+ devicePixelRatio?: number | undefined;
375
+ innerWidth?: number | undefined;
376
+ innerHeight?: number | undefined;
377
+ outerWidth?: number | undefined;
378
+ outerHeight?: number | undefined;
379
+ screenX?: number | undefined;
380
+ screenY?: number | undefined;
381
+ historyLength?: number | undefined;
382
+ } | undefined;
383
+ fonts?: string[] | undefined;
384
+ fontSpacingSeed?: number | undefined;
385
+ blockImages?: boolean | undefined;
386
+ blockWebRtc?: boolean | undefined;
387
+ blockWebGl?: boolean | undefined;
388
+ disableCoop?: boolean | undefined;
389
+ } | undefined;
22
390
  preset?: string[] | undefined;
23
391
  proxy?: string | undefined;
24
- locale?: string | undefined;
25
- timezone?: string | undefined;
26
- width?: number | undefined;
27
- height?: number | undefined;
28
392
  browser?: string | undefined;
29
393
  }, {
394
+ width?: number | undefined;
395
+ height?: number | undefined;
396
+ timezone?: string | undefined;
397
+ region?: string | undefined;
398
+ locales?: string | string[] | undefined;
399
+ screenProfile?: string | undefined;
400
+ screen?: string | {
401
+ profile?: string | undefined;
402
+ width?: number | undefined;
403
+ height?: number | undefined;
404
+ availWidth?: number | undefined;
405
+ availHeight?: number | undefined;
406
+ availTop?: number | undefined;
407
+ availLeft?: number | undefined;
408
+ colorDepth?: number | undefined;
409
+ pixelDepth?: number | undefined;
410
+ devicePixelRatio?: number | undefined;
411
+ } | undefined;
412
+ windowProfile?: string | undefined;
413
+ window?: string | {
414
+ profile?: string | undefined;
415
+ width?: number | undefined;
416
+ height?: number | undefined;
417
+ devicePixelRatio?: number | undefined;
418
+ innerWidth?: number | undefined;
419
+ innerHeight?: number | undefined;
420
+ outerWidth?: number | undefined;
421
+ outerHeight?: number | undefined;
422
+ screenX?: number | undefined;
423
+ screenY?: number | undefined;
424
+ historyLength?: number | undefined;
425
+ } | undefined;
426
+ fonts?: string[] | undefined;
427
+ fontSpacingSeed?: number | undefined;
428
+ blockImages?: boolean | undefined;
429
+ blockWebRtc?: boolean | undefined;
430
+ blockWebGl?: boolean | undefined;
431
+ disableCoop?: boolean | undefined;
432
+ locale?: string | undefined;
30
433
  headless?: boolean | undefined;
31
434
  configPath?: string | undefined;
32
435
  configJson?: string | undefined;
33
436
  prefsPath?: string | undefined;
34
437
  prefsJson?: string | undefined;
438
+ fingerprintPath?: string | undefined;
439
+ fingerprintJson?: string | undefined;
440
+ fingerprint?: {
441
+ region?: string | undefined;
442
+ locales?: string | string[] | undefined;
443
+ geolocation?: {
444
+ latitude: number;
445
+ longitude: number;
446
+ accuracy?: number | undefined;
447
+ timezone?: string | undefined;
448
+ region?: string | undefined;
449
+ webrtcIpv4?: string | undefined;
450
+ webrtcIpv6?: string | undefined;
451
+ } | undefined;
452
+ screenProfile?: string | undefined;
453
+ screen?: string | {
454
+ profile?: string | undefined;
455
+ width?: number | undefined;
456
+ height?: number | undefined;
457
+ availWidth?: number | undefined;
458
+ availHeight?: number | undefined;
459
+ availTop?: number | undefined;
460
+ availLeft?: number | undefined;
461
+ colorDepth?: number | undefined;
462
+ pixelDepth?: number | undefined;
463
+ devicePixelRatio?: number | undefined;
464
+ } | undefined;
465
+ windowProfile?: string | undefined;
466
+ window?: string | {
467
+ profile?: string | undefined;
468
+ width?: number | undefined;
469
+ height?: number | undefined;
470
+ devicePixelRatio?: number | undefined;
471
+ innerWidth?: number | undefined;
472
+ innerHeight?: number | undefined;
473
+ outerWidth?: number | undefined;
474
+ outerHeight?: number | undefined;
475
+ screenX?: number | undefined;
476
+ screenY?: number | undefined;
477
+ historyLength?: number | undefined;
478
+ } | undefined;
479
+ fonts?: string[] | undefined;
480
+ fontSpacingSeed?: number | undefined;
481
+ blockImages?: boolean | undefined;
482
+ blockWebRtc?: boolean | undefined;
483
+ blockWebGl?: boolean | undefined;
484
+ disableCoop?: boolean | undefined;
485
+ } | undefined;
35
486
  preset?: string[] | undefined;
36
487
  proxy?: string | undefined;
37
- locale?: string | undefined;
38
- timezone?: string | undefined;
39
- width?: number | undefined;
40
- height?: number | undefined;
41
488
  browser?: string | undefined;
42
489
  }>;
43
490
  export type LaunchInput = z.infer<typeof launchInputSchema>;
@@ -60,6 +507,7 @@ export interface ResolvedLaunchConfig {
60
507
  }
61
508
  export declare function loadJsonObjectFile(filePath: string, label: string): Promise<Record<string, unknown>>;
62
509
  export declare function parseJsonObjectString(raw: string, label: string): Record<string, unknown>;
510
+ export declare function hasLaunchFingerprintHelpers(input: LaunchInput): boolean;
63
511
  export declare function resolveJsonObjectInput(pathValue: string | undefined, jsonValue: string | undefined, label: string): Promise<Record<string, unknown>>;
64
512
  export declare function parseProxyString(proxy?: string): ProxySettings | undefined;
65
513
  export declare function validateLocale(locale?: string): string | undefined;
@@ -1,6 +1,7 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { z } from 'zod';
3
3
  import { ValidationError } from '../util/errors.js';
4
+ import { fingerprintHelperSchema, fingerprintLocalesValueSchema, fingerprintScreenSchema, fingerprintWindowSchema, mergeFingerprintHelpers, resolveFingerprintHelpers, } from './fingerprint.js';
4
5
  import { parseFirefoxUserPrefs } from './prefs.js';
5
6
  import { resolveCamoufoxPresets } from './presets.js';
6
7
  const jsonObjectSchema = z.record(z.string(), z.unknown());
@@ -10,14 +11,37 @@ export const launchInputSchema = z.object({
10
11
  configJson: z.string().optional(),
11
12
  prefsPath: z.string().optional(),
12
13
  prefsJson: z.string().optional(),
14
+ fingerprintPath: z.string().optional(),
15
+ fingerprintJson: z.string().optional(),
16
+ fingerprint: fingerprintHelperSchema.optional(),
13
17
  preset: z.array(z.string()).optional(),
14
18
  proxy: z.string().optional(),
15
19
  locale: z.string().optional(),
20
+ locales: fingerprintLocalesValueSchema.optional(),
21
+ region: z.string().optional(),
16
22
  timezone: z.string().optional(),
23
+ screenProfile: z.string().optional(),
24
+ screen: z.union([z.string().min(1), fingerprintScreenSchema]).optional(),
25
+ windowProfile: z.string().optional(),
26
+ window: z.union([z.string().min(1), fingerprintWindowSchema]).optional(),
27
+ fonts: z.array(z.string().min(1)).optional(),
28
+ fontSpacingSeed: z.number().int().nonnegative().optional(),
29
+ blockImages: z.boolean().optional(),
30
+ blockWebRtc: z.boolean().optional(),
31
+ blockWebGl: z.boolean().optional(),
32
+ disableCoop: z.boolean().optional(),
17
33
  width: z.number().int().positive().optional(),
18
34
  height: z.number().int().positive().optional(),
19
35
  browser: z.string().optional(),
20
36
  });
37
+ function parseJsonString(raw, label) {
38
+ try {
39
+ return JSON.parse(raw);
40
+ }
41
+ catch (error) {
42
+ throw new ValidationError(`Unable to parse ${label} JSON.`, undefined, error);
43
+ }
44
+ }
21
45
  export async function loadJsonObjectFile(filePath, label) {
22
46
  let raw;
23
47
  try {
@@ -29,19 +53,67 @@ export async function loadJsonObjectFile(filePath, label) {
29
53
  return parseJsonObjectString(raw, label);
30
54
  }
31
55
  export function parseJsonObjectString(raw, label) {
32
- let parsed;
33
- try {
34
- parsed = JSON.parse(raw);
35
- }
36
- catch (error) {
37
- throw new ValidationError(`Unable to parse ${label} JSON.`, undefined, error);
38
- }
56
+ const parsed = parseJsonString(raw, label);
39
57
  const result = jsonObjectSchema.safeParse(parsed);
40
58
  if (!result.success) {
41
59
  throw new ValidationError(`${label} must be a JSON object.`);
42
60
  }
43
61
  return result.data;
44
62
  }
63
+ async function resolveFingerprintHelperInput(pathValue, jsonValue, directValue) {
64
+ if (pathValue && jsonValue) {
65
+ throw new ValidationError('Pass either fingerprint path or fingerprint JSON, not both.');
66
+ }
67
+ let parsedValue;
68
+ if (pathValue) {
69
+ let raw;
70
+ try {
71
+ raw = await readFile(pathValue, 'utf8');
72
+ }
73
+ catch (error) {
74
+ throw new ValidationError(`Unable to read fingerprint helper file at ${pathValue}.`, { filePath: pathValue }, error);
75
+ }
76
+ parsedValue = fingerprintHelperSchema.parse(parseJsonString(raw, 'fingerprint helper'));
77
+ }
78
+ else if (jsonValue) {
79
+ parsedValue = fingerprintHelperSchema.parse(parseJsonString(jsonValue, 'fingerprint helper'));
80
+ }
81
+ return mergeFingerprintHelpers(parsedValue, directValue);
82
+ }
83
+ function buildLaunchFingerprintHelperInput(input) {
84
+ const flatHelperInput = {
85
+ ...(input.locales ? { locales: input.locales } : {}),
86
+ ...(input.region ? { region: input.region } : {}),
87
+ ...(input.screenProfile ? { screenProfile: input.screenProfile } : {}),
88
+ ...(input.screen ? { screen: input.screen } : {}),
89
+ ...(input.windowProfile ? { windowProfile: input.windowProfile } : {}),
90
+ ...(input.window ? { window: input.window } : {}),
91
+ ...(input.fonts ? { fonts: input.fonts } : {}),
92
+ ...(input.fontSpacingSeed !== undefined ? { fontSpacingSeed: input.fontSpacingSeed } : {}),
93
+ ...(input.blockImages !== undefined ? { blockImages: input.blockImages } : {}),
94
+ ...(input.blockWebRtc !== undefined ? { blockWebRtc: input.blockWebRtc } : {}),
95
+ ...(input.blockWebGl !== undefined ? { blockWebGl: input.blockWebGl } : {}),
96
+ ...(input.disableCoop !== undefined ? { disableCoop: input.disableCoop } : {}),
97
+ };
98
+ return Object.keys(flatHelperInput).length > 0 ? flatHelperInput : undefined;
99
+ }
100
+ export function hasLaunchFingerprintHelpers(input) {
101
+ return Boolean(input.fingerprintPath ||
102
+ input.fingerprintJson ||
103
+ input.fingerprint ||
104
+ input.locales ||
105
+ input.region ||
106
+ input.screenProfile ||
107
+ input.screen ||
108
+ input.windowProfile ||
109
+ input.window ||
110
+ input.fonts ||
111
+ input.fontSpacingSeed !== undefined ||
112
+ input.blockImages !== undefined ||
113
+ input.blockWebRtc !== undefined ||
114
+ input.blockWebGl !== undefined ||
115
+ input.disableCoop !== undefined);
116
+ }
45
117
  export async function resolveJsonObjectInput(pathValue, jsonValue, label) {
46
118
  if (pathValue && jsonValue) {
47
119
  throw new ValidationError(`Pass either ${label} path or ${label} JSON, not both.`);
@@ -94,18 +166,32 @@ export async function resolveLaunchConfig(input) {
94
166
  const presets = resolveCamoufoxPresets(input.preset);
95
167
  const rawConfig = await resolveJsonObjectInput(input.configPath, input.configJson, 'config');
96
168
  const rawPrefs = await resolveJsonObjectInput(input.prefsPath, input.prefsJson, 'prefs');
169
+ if (input.locale && input.locales) {
170
+ throw new ValidationError('Pass either locale or locales, not both.');
171
+ }
172
+ const helperInput = mergeFingerprintHelpers(await resolveFingerprintHelperInput(input.fingerprintPath, input.fingerprintJson, input.fingerprint), buildLaunchFingerprintHelperInput({
173
+ ...input,
174
+ ...(input.locale ? { locales: [input.locale] } : {}),
175
+ }));
176
+ const fingerprintHelpers = resolveFingerprintHelpers(helperInput);
97
177
  const camouConfig = {
98
178
  ...presets.camouConfig,
179
+ ...fingerprintHelpers.camouConfig,
99
180
  ...rawConfig,
100
181
  };
101
182
  const firefoxUserPrefs = parseFirefoxUserPrefs({
102
183
  ...presets.firefoxUserPrefs,
184
+ ...fingerprintHelpers.firefoxUserPrefs,
103
185
  ...rawPrefs,
104
186
  });
105
- const viewport = input.width && input.height ? { width: input.width, height: input.height } : undefined;
187
+ const viewport = input.width && input.height ? { width: input.width, height: input.height } : fingerprintHelpers.viewport;
106
188
  if ((input.width && !input.height) || (!input.width && input.height)) {
107
189
  throw new ValidationError('Both width and height are required when setting window size.');
108
190
  }
191
+ if (viewport) {
192
+ camouConfig['window.innerWidth'] = viewport.width;
193
+ camouConfig['window.innerHeight'] = viewport.height;
194
+ }
109
195
  return {
110
196
  headless: input.headless ?? false,
111
197
  browser: input.browser,
@@ -113,8 +199,8 @@ export async function resolveLaunchConfig(input) {
113
199
  camouConfig,
114
200
  firefoxUserPrefs,
115
201
  proxy: parseProxyString(input.proxy),
116
- locale: validateLocale(input.locale),
117
- timezoneId: validateTimezone(input.timezone),
202
+ locale: validateLocale(fingerprintHelpers.locale ?? input.locale),
203
+ timezoneId: validateTimezone(input.timezone ?? fingerprintHelpers.timezoneId),
118
204
  viewport,
119
205
  };
120
206
  }