arn-browser 0.0.10 → 0.0.12

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arn-browser",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "A lightweight, browser autmation helper.",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -181,6 +181,18 @@ export interface LaunchOptions {
181
181
  */
182
182
  maxWidth?: number;
183
183
 
184
+ /**
185
+ * Whether to spoof browser fingerprint with FingerprintInjector.
186
+ * When true: Applies userAgent, viewport, locale from fingerprintData and uses FingerprintInjector.
187
+ * When false: Uses null viewport and applies stealth script only.
188
+ *
189
+ * **For persistent Brave profiles:** The value is locked on first launch.
190
+ * Subsequent launches will use the saved value, ignoring the current parameter.
191
+ *
192
+ * Default: false
193
+ */
194
+ spoof_fingerprint?: boolean;
195
+
184
196
  // ========================================================================
185
197
  // 5. ENGINE SPECIFIC GROUPS
186
198
  // ========================================================================
@@ -180,11 +180,15 @@ export async function launchBrowser({
180
180
 
181
181
  which_browser = "chromium",
182
182
  CapSolver = false,
183
+ humanize_options = {}, // { humanize, maxTime, minTime, showCursor } - defaults to enabled for non-camoufox
184
+
185
+ // Spoof Fingerprint
186
+ spoof_fingerprint = false,
183
187
 
184
188
  // Browser Specific Grouped Options
185
189
  camoufox_options = {}, // { geoip, humanize, ... }
186
190
  multilogin_options = {}, // { profileId, os_type, canvas_noise, ... }
187
- humanize_options = {}, // { humanize, maxTime, minTime, showCursor } - defaults to enabled for non-camoufox
191
+
188
192
  }) {
189
193
  try {
190
194
  if (custom_profile_path) throw new Error("Please use profile_path");
@@ -212,6 +216,7 @@ export async function launchBrowser({
212
216
  CapSolver,
213
217
  maxWidth,
214
218
  humanize_options: effectiveHumanizeOptions,
219
+ spoof_fingerprint,
215
220
  });
216
221
  break;
217
222
  case "firefox":
@@ -221,6 +226,7 @@ export async function launchBrowser({
221
226
  timezoneId,
222
227
  maxWidth,
223
228
  humanize_options: effectiveHumanizeOptions,
229
+ spoof_fingerprint,
224
230
  });
225
231
  break;
226
232
  case "brave":
@@ -232,6 +238,7 @@ export async function launchBrowser({
232
238
  CapSolver,
233
239
  maxWidth,
234
240
  humanize_options: effectiveHumanizeOptions,
241
+ spoof_fingerprint,
235
242
  });
236
243
  break;
237
244
  case "camoufox":
@@ -242,6 +249,7 @@ export async function launchBrowser({
242
249
  timezoneId,
243
250
  maxWidth,
244
251
  camoufox_options,
252
+ // Spoof Fingerprint not needed for Camoufox
245
253
  });
246
254
  break;
247
255
  case "multilogin":
@@ -249,6 +257,7 @@ export async function launchBrowser({
249
257
  proxy,
250
258
  multilogin_options,
251
259
  humanize_options: effectiveHumanizeOptions,
260
+ // Spoof Fingerprint not needed for Multilogin
252
261
  });
253
262
  break;
254
263
  default:
@@ -265,7 +274,9 @@ export async function launchBrowser({
265
274
  // ==========================================================================
266
275
  // 4. ENGINE: CHROMIUM
267
276
  // ==========================================================================
268
- async function chromiumLauncher({ profilePath, proxy, timezoneId, CapSolver, maxWidth, humanize_options }) {
277
+ async function chromiumLauncher({ profilePath, proxy, timezoneId, CapSolver, maxWidth, humanize_options
278
+ , spoof_fingerprint
279
+ }) {
269
280
  const isPersistent = !!profilePath;
270
281
 
271
282
  // 1. Determine Path (Temp needs it for fingerprint storage, Persistent needs it for data)
@@ -278,6 +289,11 @@ async function chromiumLauncher({ profilePath, proxy, timezoneId, CapSolver, max
278
289
  // --- Stealth & Anti-Detection ---
279
290
  "--disable-blink-features=AutomationControlled",
280
291
  // "--disable-features=UserAgentClientHint",
292
+
293
+ // --- Window Size ---
294
+ "--start-maximized",
295
+
296
+
281
297
  // --- PREVENT EXTRA TABS ---
282
298
  // "--homepage=about:blank",
283
299
  "--disable-restore-session-state",
@@ -324,11 +340,20 @@ async function chromiumLauncher({ profilePath, proxy, timezoneId, CapSolver, max
324
340
  ignoreDefaultArgs: ignoreDefaultArgs,
325
341
  });
326
342
 
327
- // Inject the fingerprint
328
- const context = await newInjectedContext(browser, {
329
- fingerprint: fingerprintData,
330
- timezoneId: tz,
331
- });
343
+ let context;
344
+ if (spoof_fingerprint) {
345
+ // Inject the fingerprint
346
+ context = await newInjectedContext(browser, {
347
+ fingerprint: fingerprintData,
348
+ timezoneId: tz,
349
+ });
350
+ } else {
351
+ context = await browser.newContext({
352
+ timezoneId: tz,
353
+ });
354
+ // Manual Stealth Script
355
+ await addStealthScript(context);
356
+ }
332
357
 
333
358
  const page = context.pages()[0] || (await context.newPage());
334
359
 
@@ -343,6 +368,7 @@ async function chromiumLauncher({ profilePath, proxy, timezoneId, CapSolver, max
343
368
  // BRANCH B: PERSISTENT PROFILE (launchPersistentContext + Manual Script)
344
369
  // ==================================================================
345
370
  else {
371
+ // spoof_fingerprint not needed for isPersistent in chromium
346
372
  try {
347
373
  if (!fs.existsSync(activePath)) fs.mkdirSync(activePath, { recursive: true });
348
374
 
@@ -372,7 +398,7 @@ async function chromiumLauncher({ profilePath, proxy, timezoneId, CapSolver, max
372
398
  // ==========================================================================
373
399
  // 5. ENGINE: FIREFOX
374
400
  // ==========================================================================
375
- async function firefoxLauncher({ profilePath, proxy, timezoneId, maxWidth, humanize_options }) {
401
+ async function firefoxLauncher({ profilePath, proxy, timezoneId, maxWidth, humanize_options, spoof_fingerprint }) {
376
402
  const isPersistent = !!profilePath;
377
403
 
378
404
  // 1. Determine Path
@@ -404,10 +430,21 @@ async function firefoxLauncher({ profilePath, proxy, timezoneId, maxWidth, human
404
430
  firefoxUserPrefs: firefoxUserPrefs,
405
431
  });
406
432
 
407
- const context = await newInjectedContext(browser, {
408
- fingerprint: fingerprintData,
409
- timezoneId: tz,
410
- });
433
+ let context;
434
+ if (spoof_fingerprint) {
435
+ context = await newInjectedContext(browser, {
436
+ fingerprint: fingerprintData,
437
+ timezoneId: tz,
438
+ });
439
+ }
440
+ // Spoof Fingerprint not needed for Firefox
441
+ else {
442
+ context = await browser.newContext({
443
+ timezoneId: tz,
444
+ });
445
+ // Manual Stealth Script
446
+ await addStealthScript(context);
447
+ }
411
448
 
412
449
  const page = context.pages()[0] || (await context.newPage());
413
450
 
@@ -422,6 +459,7 @@ async function firefoxLauncher({ profilePath, proxy, timezoneId, maxWidth, human
422
459
  // BRANCH B: PERSISTENT PROFILE (launchPersistentContext + Manual Script)
423
460
  // ==================================================================
424
461
  else {
462
+ // spoof_fingerprint not needed for isPersistent in firefox
425
463
  try {
426
464
  if (!fs.existsSync(activePath)) fs.mkdirSync(activePath, { recursive: true });
427
465
 
@@ -450,13 +488,34 @@ async function firefoxLauncher({ profilePath, proxy, timezoneId, maxWidth, human
450
488
  // ==========================================================================
451
489
  // 6. ENGINE: BRAVE
452
490
  // ==========================================================================
453
- async function braveLauncher({ profilePath, proxy, CapSolver, timezoneId, maxWidth, humanize_options }) {
491
+ async function braveLauncher({ profilePath, proxy, CapSolver, timezoneId, maxWidth, humanize_options, spoof_fingerprint }) {
454
492
  const isPersistent = !!profilePath;
455
493
  const activePath = isPersistent ? profilePath : path.join(TEMP_DIR, crypto.randomUUID());
456
494
 
457
495
  console.log(`🚀 Starting Brave: ${activePath}`);
458
496
  fs.mkdirSync(activePath, { recursive: true });
459
497
 
498
+ // ======================================================
499
+ // Persist spoof_fingerprint setting for persistent profiles
500
+ // On first launch: save the setting. On subsequent launches: use saved value.
501
+ // ======================================================
502
+ let effectiveSpoofFingerprint = spoof_fingerprint;
503
+ const settingsFilePath = path.join(activePath, "settings.json");
504
+
505
+ if (isPersistent) {
506
+ if (fs.existsSync(settingsFilePath)) {
507
+ // Load saved settings from first launch
508
+ const savedSettings = JSON.parse(fs.readFileSync(settingsFilePath, "utf-8"));
509
+ effectiveSpoofFingerprint = savedSettings.spoof_fingerprint;
510
+ console.log(`📋 Using saved spoof_fingerprint: ${effectiveSpoofFingerprint} (ignoring current: ${spoof_fingerprint})`);
511
+ } else {
512
+ // First launch - save the current setting
513
+ const settings = { spoof_fingerprint: spoof_fingerprint };
514
+ fs.writeFileSync(settingsFilePath, JSON.stringify(settings, null, 2), "utf-8");
515
+ console.log(`📝 Saved spoof_fingerprint setting: ${spoof_fingerprint}`);
516
+ }
517
+ }
518
+
460
519
  let fingerprintData;
461
520
  const fingerprintFilePath = path.join(activePath, "fingerprint.json");
462
521
 
@@ -474,17 +533,42 @@ async function braveLauncher({ profilePath, proxy, CapSolver, timezoneId, maxWid
474
533
 
475
534
  const braveBin = getBinaryPath("brave");
476
535
 
536
+ // ======================================================
537
+ // Disable Brave Sidebar via Preferences
538
+ // ======================================================
539
+ const prefsFilePath = path.join(activePath, "Default", "Preferences");
540
+ const prefsDir = path.dirname(prefsFilePath);
541
+ if (!fs.existsSync(prefsDir)) fs.mkdirSync(prefsDir, { recursive: true });
542
+
543
+ try {
544
+ let prefs = {};
545
+ if (fs.existsSync(prefsFilePath)) {
546
+ prefs = JSON.parse(fs.readFileSync(prefsFilePath, "utf-8"));
547
+ }
548
+ // Set sidebar_show_option to 3 = Never show
549
+ if (!prefs.brave) prefs.brave = {};
550
+ if (!prefs.brave.sidebar) prefs.brave.sidebar = {};
551
+ prefs.brave.sidebar.sidebar_show_option = 3;
552
+ fs.writeFileSync(prefsFilePath, JSON.stringify(prefs, null, 2), "utf-8");
553
+ } catch (e) {
554
+ console.warn("⚠️ Could not modify Brave preferences:", e.message);
555
+ }
556
+
477
557
  const args = [
478
558
  "--test-type",
479
559
  // --- Stealth & Anti-Detection ---
480
560
  "--disable-blink-features=AutomationControlled",
481
561
  //"--disable-features=UserAgentClientHint",
482
562
 
563
+ // --- Window Size ---
564
+ "--start-maximized",
565
+
483
566
  // --- PREVENT EXTRA TABS (New Flags) ---
484
567
  // "--no-startup-window",
485
568
  "--homepage=about:blank",
486
569
  "--disable-restore-session-state", // Prevents restoring old tabs
487
570
 
571
+
488
572
  // --- Error Suppression ---
489
573
  "--disable-session-crashed-bubble",
490
574
  "--hide-crash-restore-bubble",
@@ -502,7 +586,7 @@ async function braveLauncher({ profilePath, proxy, CapSolver, timezoneId, maxWid
502
586
  "--disable-client-side-phishing-detection",
503
587
 
504
588
  // --- Brave Specific Silence ---
505
- "--disable-features=Translate,BraveRewards,BraveWallet,BraveNews",
589
+ "--disable-features=Translate,BraveRewards,BraveWallet,BraveNews,Sidebar,SidePanel",
506
590
  "--disable-infobars",
507
591
  ];
508
592
  const ignoreDefaultArgs = ["--enable-automation", "--no-sandbox"];
@@ -514,19 +598,39 @@ async function braveLauncher({ profilePath, proxy, CapSolver, timezoneId, maxWid
514
598
  const proxyObj = formatProxy(proxy);
515
599
  const tz = timezoneId || undefined;
516
600
 
517
- const context = await chromium.launchPersistentContext(activePath, {
518
- headless: false,
519
- executablePath: braveBin,
520
- proxy: proxyObj,
521
- timezoneId: tz,
522
- ignoreDefaultArgs: ignoreDefaultArgs,
523
- args: args,
524
- userAgent: fingerprintData.fingerprint.navigator.userAgent,
525
- viewport: fingerprintData.fingerprint.screen,
526
- locale: fingerprintData.fingerprint.navigator.language,
527
- });
528
601
 
529
- await new FingerprintInjector().attachFingerprintToPlaywright(context, fingerprintData);
602
+ let context;
603
+ if (effectiveSpoofFingerprint) {
604
+ context = await chromium.launchPersistentContext(activePath, {
605
+ headless: false,
606
+ executablePath: braveBin,
607
+ proxy: proxyObj,
608
+ timezoneId: tz,
609
+ ignoreDefaultArgs: ignoreDefaultArgs,
610
+ args: args,
611
+ userAgent: fingerprintData.fingerprint.navigator.userAgent,
612
+ viewport: fingerprintData.fingerprint.screen,
613
+ locale: fingerprintData.fingerprint.navigator.language,
614
+ });
615
+
616
+ await new FingerprintInjector().attachFingerprintToPlaywright(context, fingerprintData);
617
+ }
618
+ else {
619
+ context = await chromium.launchPersistentContext(activePath, {
620
+ headless: false,
621
+ executablePath: braveBin,
622
+ proxy: proxyObj,
623
+ timezoneId: tz,
624
+ ignoreDefaultArgs: ignoreDefaultArgs,
625
+ args: args,
626
+ viewport: null,
627
+ });
628
+
629
+ // Manual Stealth Script
630
+ await addStealthScript(context);
631
+ }
632
+
633
+
530
634
 
531
635
  // ======================================================
532
636
  // 🛠️ FIX: Close Extra Tabs (Brave Dashboard / Restore)