From 6dfa69608f789802ba3e28c985f7696c20ee5b12 Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Wed, 9 Jul 2025 05:58:47 +0400 Subject: [PATCH] refactor: switch nodecar to commonjs --- .node-version | 2 +- .nvmrc | 2 +- .vscode/settings.json | 4 + nodecar/package.json | 25 +- nodecar/src/camoufox-launcher.ts | 618 +++++++------------------------ nodecar/src/index.ts | 91 +++-- package.json | 2 +- pnpm-lock.yaml | 517 ++++++++++---------------- src-tauri/src/camoufox.rs | 9 + 9 files changed, 404 insertions(+), 866 deletions(-) diff --git a/.node-version b/.node-version index 853058d..e63d7ea 100644 --- a/.node-version +++ b/.node-version @@ -1,2 +1,2 @@ -23 +24 diff --git a/.nvmrc b/.nvmrc index 03ff60b..fce7a4d 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -23 \ No newline at end of file +24 \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 1da025e..37e0dc6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,6 +17,7 @@ "clippy", "cmdk", "codegen", + "codesign", "CTYPE", "datareporting", "devedition", @@ -72,7 +73,9 @@ "oscpu", "peerconnection", "pixbuf", + "pkgman", "plasmohq", + "postject", "prefs", "propertylist", "reqwest", @@ -113,6 +116,7 @@ "urlencoding", "vercel", "VERYSILENT", + "virtdisplay", "webgl", "webrtc", "winreg", diff --git a/nodecar/package.json b/nodecar/package.json index 07c5087..475b587 100644 --- a/nodecar/package.json +++ b/nodecar/package.json @@ -3,19 +3,20 @@ "version": "1.0.0", "description": "", "main": "dist/index.js", + "type": "commonjs", "scripts": { "watch": "nodemon --exec ts-node --esm ./src/index.ts --watch src", "dev": "node --loader ts-node/esm ./src/index.ts", "start": "tsc && node ./dist/index.js", "test": "tsc && node ./dist/test-proxy.js", "rename-binary": "sh ./copy-binary.sh", - "build": "tsc && pkg ./dist/index.js --targets latest-macos-arm64 --output dist/nodecar && pnpm rename-binary", - "build:mac-aarch64": "tsc && pkg ./dist/index.js --targets latest-macos-arm64 --output dist/nodecar && pnpm rename-binary", - "build:mac-x86_64": "tsc && pkg ./dist/index.js --targets latest-macos-x64 --output dist/nodecar && pnpm rename-binary", - "build:linux-x64": "tsc && pkg ./dist/index.js --targets latest-linux-x64 --output dist/nodecar && pnpm rename-binary", - "build:linux-arm64": "tsc && pkg ./dist/index.js --targets latest-linux-arm64 --output dist/nodecar && pnpm rename-binary", - "build:win-x64": "tsc && pkg ./dist/index.js --targets latest-win-x64 --output dist/nodecar && pnpm rename-binary", - "build:win-arm64": "tsc && pkg ./dist/index.js --targets latest-win-arm64 --output dist/nodecar && pnpm rename-binary" + "build": "tsc && pkg ./dist/index.js --targets latest-macos-arm64 --output dist/nodecar --option experimental-require-module --public && pnpm rename-binary", + "build:mac-aarch64": "tsc && pkg ./dist/index.js --targets latest-macos-arm64 --output dist/nodecar --option experimental-require-module --public&& pnpm rename-binary", + "build:mac-x86_64": "tsc && pkg ./dist/index.js --targets latest-macos-x64 --output dist/nodecar --option experimental-require-module --public && pnpm rename-binary", + "build:linux-x64": "tsc && pkg ./dist/index.js --targets latest-linux-x64 --output dist/nodecar --option experimental-require-module --public && pnpm rename-binary", + "build:linux-arm64": "tsc && pkg ./dist/index.js --targets latest-linux-arm64 --output dist/nodecar --option experimental-require-module --public && pnpm rename-binary", + "build:win-x64": "tsc && pkg ./dist/index.js --targets latest-win-x64 --output dist/nodecar --option experimental-require-module --public && pnpm rename-binary", + "build:win-arm64": "tsc && pkg ./dist/index.js --targets latest-win-arm64 --output dist/nodecar --option experimental-require-module --public && pnpm rename-binary" }, "keywords": [], "author": "", @@ -23,7 +24,7 @@ "dependencies": { "@types/node": "^24.0.10", "@yao-pkg/pkg": "^6.5.1", - "camoufox-js": "^0.6.0", + "camoufox-js": "file:../../camoufox-js", "commander": "^14.0.0", "dotenv": "^17.0.1", "get-port": "^7.1.0", @@ -35,5 +36,13 @@ }, "devDependencies": { "@types/tmp": "^0.2.6" + }, + "pkg": { + "assets": [ + "node_modules/camoufox-js/**/*" + ], + "scripts": [ + "node_modules/camoufox-js/**/*.js" + ] } } diff --git a/nodecar/src/camoufox-launcher.ts b/nodecar/src/camoufox-launcher.ts index acd3b03..4498005 100644 --- a/nodecar/src/camoufox-launcher.ts +++ b/nodecar/src/camoufox-launcher.ts @@ -14,7 +14,7 @@ export interface CamoufoxConfig { export interface CamoufoxLaunchOptions { // Operating system to use for fingerprint generation - os?: "windows" | "macos" | "linux" | string[]; + os?: "windows" | "macos" | "linux" | ("windows" | "macos" | "linux")[]; // Blocking options block_images?: boolean; @@ -37,7 +37,7 @@ export interface CamoufoxLaunchOptions { addons?: string[]; fonts?: string[]; custom_fonts_only?: boolean; - exclude_addons?: string[]; + exclude_addons?: "UBO"[]; // Screen and window screen?: { @@ -82,7 +82,7 @@ export interface CamoufoxLaunchOptions { virtual_display?: string; webgl_config?: [string, string]; - // Custom options + // Custom options - these may not be directly supported by camoufox-js timezone?: string; country?: string; geolocation?: { @@ -90,6 +90,12 @@ export interface CamoufoxLaunchOptions { longitude: number; accuracy?: number; }; + + // Add i_know_what_im_doing to match camoufox-js + i_know_what_im_doing?: boolean; + + // Allow any additional properties that camoufox-js might accept + [key: string]: any; } // Store for active Camoufox processes @@ -186,422 +192,6 @@ function isProcessRunning(pid: number): boolean { } } -/** - * Convert Camoufox options to command line arguments - */ -function buildCamoufoxArgs( - options: CamoufoxLaunchOptions, - profilePath: string, - url?: string, -): string[] { - const args: string[] = []; - - // Always use profile - args.push("-profile", profilePath); - - // Cache enabled by default as requested - if (options.enable_cache !== false) { - // Cache is enabled by default in Camoufox, no special args needed - } - - // Headless mode - if (options.headless) { - args.push("-headless"); - } - - // No remote for security (anti-detect) - args.push("-no-remote"); - - // Custom Firefox user preferences will be written to user.js in profile - - // Additional custom args - if (options.args) { - args.push(...options.args); - } - - // URL to open - if (url) { - args.push(url); - } - - return args; -} - -/** - * Create Camoufox configuration object from launch options - * This follows the complete Camoufox schema for CAMOU_CONFIG_* environment variables - */ -function createCamoufoxConfig(options: CamoufoxLaunchOptions): any { - const config: any = {}; - - // Debug flag - if (options.debug !== undefined) { - config.debug = options.debug; - } - - // Locale settings - parse locale string into language and region - if (options.locale) { - const localeValue = Array.isArray(options.locale) - ? options.locale[0] - : options.locale; - - // Parse locale like "en-US" into language and region - const localeParts = localeValue.split("-"); - if (localeParts.length >= 2) { - config["locale:language$__LOCALE"] = localeParts[0]; - config["locale:region$__LOCALE"] = localeParts[1]; - } else { - config["locale:language$__LOCALE"] = localeParts[0]; - // Default region if not specified - config["locale:region$__LOCALE"] = "US"; - } - - // Set navigator language properties - config["navigator.language"] = localeValue; - config["navigator.languages"] = Array.isArray(options.locale) - ? options.locale - : [localeValue]; - config["headers.Accept-Language"] = localeValue; - config["locale:all"] = localeValue; - } - - // Screen dimensions from screen options - if (options.screen) { - if (options.screen.maxWidth) { - config["screen.width$__SC"] = options.screen.maxWidth; - config["screen.availWidth$__SC"] = options.screen.maxWidth; - } - if (options.screen.maxHeight) { - config["screen.height$__SC"] = options.screen.maxHeight; - config["screen.availHeight$__SC"] = options.screen.maxHeight; - } - - // Set default screen properties if not specified - if (!options.screen.maxWidth) { - config["screen.width$__SC"] = 1920; - config["screen.availWidth$__SC"] = 1920; - } - if (!options.screen.maxHeight) { - config["screen.height$__SC"] = 1080; - config["screen.availHeight$__SC"] = 1080; - } - - // Default screen position and color depth - config["screen.availTop"] = 0; - config["screen.availLeft"] = 0; - config["screen.colorDepth"] = 24; - config["screen.pixelDepth"] = 24; - } else { - // Default screen settings if not specified - config["screen.width$__SC"] = 1920; - config["screen.height$__SC"] = 1080; - config["screen.availWidth$__SC"] = 1920; - config["screen.availHeight$__SC"] = 1080; - config["screen.availTop"] = 0; - config["screen.availLeft"] = 0; - config["screen.colorDepth"] = 24; - config["screen.pixelDepth"] = 24; - } - - // Window dimensions - if (options.window) { - config["window.outerWidth$__W_OUTER"] = options.window[0]; - config["window.outerHeight$__W_OUTER"] = options.window[1]; - config["window.innerWidth$__W_INNER"] = options.window[0] - 16; // Account for scrollbars - config["window.innerHeight$__W_INNER"] = options.window[1] - 100; // Account for browser chrome - } else { - // Default window dimensions - config["window.outerWidth$__W_OUTER"] = 1280; - config["window.outerHeight$__W_OUTER"] = 720; - config["window.innerWidth$__W_INNER"] = 1264; - config["window.innerHeight$__W_INNER"] = 620; - } - - // Window position and properties - config["window.screenX"] = 0; - config["window.screenY"] = 0; - config["window.devicePixelRatio"] = 1.0; - config["window.scrollMinX"] = 0; - config["window.scrollMinY"] = 0; - config["window.scrollMaxX"] = 0; - config["window.scrollMaxY"] = 0; - config["screen.pageXOffset"] = 0.0; - config["screen.pageYOffset"] = 0.0; - - // Document body dimensions - config["document.body.clientWidth$__DOC_BODY"] = - config["window.innerWidth$__W_INNER"]; - config["document.body.clientHeight$__DOC_BODY"] = - config["window.innerHeight$__W_INNER"]; - config["document.body.clientTop"] = 0; - config["document.body.clientLeft"] = 0; - - // Geolocation - if (options.geolocation) { - config["geolocation:latitude$__GEO"] = options.geolocation.latitude; - config["geolocation:longitude$__GEO"] = options.geolocation.longitude; - if (options.geolocation.accuracy) { - config["geolocation:accuracy"] = options.geolocation.accuracy; - } - } - - // Timezone - if (options.timezone) { - config.timezone = options.timezone; - } - - // User Agent based on OS option - const osOption = Array.isArray(options.os) ? options.os[0] : options.os; - let userAgent: string; - let platform: string; - let oscpu: string; - let appVersion: string; - - switch (osOption) { - case "macos": - userAgent = - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:135.0) Gecko/20100101 Firefox/135.0"; - platform = "MacIntel"; - oscpu = "Intel Mac OS X 10.15"; - appVersion = - "5.0 (Macintosh; Intel Mac OS X 10.15; rv:135.0) Gecko/20100101 Firefox/135.0"; - break; - case "linux": - userAgent = - "Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0"; - platform = "Linux x86_64"; - oscpu = "Linux x86_64"; - appVersion = - "5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0"; - break; - case "windows": - default: - userAgent = - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:135.0) Gecko/20100101 Firefox/135.0"; - platform = "Win32"; - oscpu = "Windows NT 10.0; Win64; x64"; - appVersion = - "5.0 (Windows NT 10.0; Win64; x64; rv:135.0) Gecko/20100101 Firefox/135.0"; - break; - } - - config["navigator.userAgent"] = userAgent; - config["navigator.appVersion"] = appVersion; - config["navigator.platform"] = platform; - config["navigator.oscpu"] = oscpu; - config["headers.User-Agent"] = userAgent; - - // Headers - config["headers.Accept-Encoding"] = "gzip, deflate, br"; - - // Fonts - if (options.fonts && options.fonts.length > 0) { - config.fonts = options.fonts; - } - config["fonts:spacing_seed"] = 0; - - // WebGL configuration - if ( - options.webgl_config && - Array.isArray(options.webgl_config) && - options.webgl_config.length === 2 - ) { - config["webGl:vendor$__WEBGL"] = options.webgl_config[0]; - config["webGl:renderer$__WEBGL"] = options.webgl_config[1]; - } - - // WebRTC IP spoofing from geoip - if ( - options.geoip && - typeof options.geoip === "string" && - options.geoip !== "auto" - ) { - if (options.geoip.includes(":")) { - // IPv6 - config["webrtc:ipv6"] = options.geoip; - config["webrtc:localipv6"] = options.geoip; - } else { - // IPv4 - config["webrtc:ipv4"] = options.geoip; - config["webrtc:localipv4"] = options.geoip; - } - } - - // Addons - if (options.addons && options.addons.length > 0) { - config.addons = options.addons; - } - - // Humanization - if (options.humanize !== undefined) { - config.humanize = !!options.humanize; - if (typeof options.humanize === "number") { - config["humanize:maxTime"] = options.humanize; - config["humanize:minTime"] = 0.0; - } else { - config["humanize:maxTime"] = 5.0; - config["humanize:minTime"] = 0.5; - } - } - - // Cursor visibility - config.showcursor = false; - - // Advanced browser settings - if (options.main_world_eval) { - config.allowMainWorld = options.main_world_eval; - } - - config.forceScopeAccess = false; - config.enableRemoteSubframes = false; - config.disableTheming = false; - config.memorysaver = false; - - return config; -} - -/** - * Create minimal user.js for Firefox-specific settings that are not part of Camoufox fingerprint config - */ -function createMinimalUserJs( - profilePath: string, - options: CamoufoxLaunchOptions, -): void { - const preferences: string[] = []; - - // Basic privacy settings - preferences.push('user_pref("privacy.resistFingerprinting", false);'); // Let Camoufox handle fingerprinting - preferences.push('user_pref("privacy.trackingprotection.enabled", true);'); - - // Disable telemetry and data collection - preferences.push( - 'user_pref("datareporting.healthreport.uploadEnabled", false);', - ); - preferences.push( - 'user_pref("datareporting.policy.dataSubmissionEnabled", false);', - ); - preferences.push('user_pref("toolkit.telemetry.enabled", false);'); - preferences.push('user_pref("toolkit.telemetry.unified", false);'); - - // Block options - if (options.block_images) { - preferences.push('user_pref("permissions.default.image", 2);'); - } - - if (options.block_webrtc) { - preferences.push('user_pref("media.peerconnection.enabled", false);'); - preferences.push('user_pref("media.navigator.enabled", false);'); - } - - if (options.block_webgl) { - preferences.push('user_pref("webgl.disabled", true);'); - preferences.push('user_pref("webgl.disable-extensions", true);'); - } - - // COOP settings - if (options.disable_coop) { - preferences.push( - 'user_pref("browser.tabs.remote.useCrossOriginOpenerPolicy", false);', - ); - } - - // Proxy settings - if (options.proxy) { - if (typeof options.proxy === "string") { - // Parse proxy URL - try { - const proxyUrl = new URL(options.proxy); - const port = - parseInt(proxyUrl.port) || - (proxyUrl.protocol === "https:" ? 443 : 80); - - if (proxyUrl.protocol.startsWith("socks")) { - preferences.push('user_pref("network.proxy.type", 1);'); - preferences.push( - `user_pref("network.proxy.socks", "${proxyUrl.hostname}");`, - ); - preferences.push(`user_pref("network.proxy.socks_port", ${port});`); - if (proxyUrl.protocol === "socks5:") { - preferences.push('user_pref("network.proxy.socks_version", 5);'); - } else { - preferences.push('user_pref("network.proxy.socks_version", 4);'); - } - } else { - preferences.push('user_pref("network.proxy.type", 1);'); - preferences.push( - `user_pref("network.proxy.http", "${proxyUrl.hostname}");`, - ); - preferences.push(`user_pref("network.proxy.http_port", ${port});`); - preferences.push( - `user_pref("network.proxy.ssl", "${proxyUrl.hostname}");`, - ); - preferences.push(`user_pref("network.proxy.ssl_port", ${port});`); - } - - if (proxyUrl.username && proxyUrl.password) { - // Note: Basic auth for proxies is handled differently in modern Firefox - preferences.push( - 'user_pref("network.proxy.allow_hijacking_localhost", true);', - ); - } - } catch (error) { - console.error(`Invalid proxy URL: ${options.proxy}`); - } - } - } - - // Custom Firefox preferences - if (options.firefox_user_prefs) { - for (const [key, value] of Object.entries(options.firefox_user_prefs)) { - if (typeof value === "string") { - preferences.push(`user_pref("${key}", "${value}");`); - } else if (typeof value === "boolean") { - preferences.push(`user_pref("${key}", ${value});`); - } else if (typeof value === "number") { - preferences.push(`user_pref("${key}", ${value});`); - } - } - } - - // Cache settings - if (options.enable_cache === false) { - preferences.push('user_pref("browser.cache.disk.enable", false);'); - preferences.push('user_pref("browser.cache.memory.enable", false);'); - } - - // Write user.js file only if we have preferences to set - if (preferences.length > 0) { - const userJsPath = path.join(profilePath, "user.js"); - fs.writeFileSync(userJsPath, preferences.join("\n")); - } -} - -/** - * Set Camoufox configuration via environment variables - */ -function setCamoufoxConfigEnv(config: any, env: NodeJS.ProcessEnv): void { - const configJson = JSON.stringify(config); - const chunkSize = os.platform() === "win32" ? 2047 : 32767; - - // Clear any existing CAMOU_CONFIG_* variables - for (const key in env) { - if (key.startsWith("CAMOU_CONFIG_")) { - delete env[key]; - } - } - - // Split config into chunks - const chunks: string[] = []; - for (let i = 0; i < configJson.length; i += chunkSize) { - chunks.push(configJson.slice(i, i + chunkSize)); - } - - // Set environment variables (start from index 1 as expected by Camoufox) - for (let i = 0; i < chunks.length; i++) { - env[`CAMOU_CONFIG_${i + 1}`] = chunks[i]; - } -} - /** * Launch Camoufox browser with specified options */ @@ -618,88 +208,128 @@ export async function launchCamoufox( fs.mkdirSync(profilePath, { recursive: true }); } - // Create Camoufox configuration - const camoufoxConfig = createCamoufoxConfig(options); + try { + // Use camoufox-js launchOptions to generate proper configuration + const { launchOptions } = require("camoufox-js"); + const launchConfig = await launchOptions({ + ...options, + executable_path: executablePath, + // Enable debug if requested + debug: options.debug || false, + // Set i_know_what_im_doing to true to bypass warnings since we're controlling this + i_know_what_im_doing: true, + }); - // Create minimal user.js for Firefox-specific settings (proxy, blocking, etc.) - createMinimalUserJs(profilePath, options); + if (options.debug) { + console.log( + "Generated launch config:", + JSON.stringify(launchConfig, null, 2), + ); + } - // Build command line arguments - const args = buildCamoufoxArgs(options, profilePath, url); + // Extract the command line args and environment from the launch config + const args = [ + "-profile", + profilePath, + "-no-remote", + ...(launchConfig.args || []), + ]; - // Prepare environment variables - const env: NodeJS.ProcessEnv = { - ...process.env, - }; + // Add URL if provided + if (url) { + args.push(url); + } - // Add custom environment variables from options, converting values to strings - if (options.env) { - for (const [key, value] of Object.entries(options.env)) { - if (value !== undefined) { - env[key] = String(value); + // Use the environment variables and other config from camoufox-js + const env: NodeJS.ProcessEnv = { + ...process.env, + ...(launchConfig.env || {}), + }; + + if (options.debug) { + console.log("Launch args:", args); + console.log( + "Environment variables set:", + Object.keys(env).filter( + (key) => key.startsWith("CAMOU_") || key.startsWith("DISPLAY"), + ), + ); + } + + // Use the executable path from the launch config if available + const finalExecutablePath = launchConfig.executablePath || executablePath; + + // Write Firefox user preferences to user.js if provided + if ( + launchConfig.firefoxUserPrefs && + Object.keys(launchConfig.firefoxUserPrefs).length > 0 + ) { + const userJsPath = path.join(profilePath, "user.js"); + const preferences: string[] = []; + + for (const [key, value] of Object.entries( + launchConfig.firefoxUserPrefs, + )) { + if (typeof value === "string") { + preferences.push(`user_pref("${key}", "${value}");`); + } else if (typeof value === "boolean") { + preferences.push(`user_pref("${key}", ${value});`); + } else if (typeof value === "number") { + preferences.push(`user_pref("${key}", ${value});`); + } + } + + if (preferences.length > 0) { + fs.writeFileSync(userJsPath, preferences.join("\n")); } } + + // Launch the process + const child = spawn(finalExecutablePath, args, { + env: env as NodeJS.ProcessEnv, + detached: true, + stdio: options.debug ? "inherit" : "ignore", + }); + + if (!child.pid) { + throw new Error("Failed to launch Camoufox process"); + } + + const config: CamoufoxConfig = { + id, + pid: child.pid, + executablePath: finalExecutablePath, + profilePath, + url, + options, + }; + + // Save configuration + saveCamoufoxConfig(config); + + // Handle process exit + child.on("exit", (code, signal) => { + if (options.debug) { + console.log( + `Camoufox process ${child.pid} exited with code ${code}, signal ${signal}`, + ); + } + deleteCamoufoxConfig(id); + }); + + child.on("error", (error) => { + console.error(`Camoufox process error: ${error}`); + deleteCamoufoxConfig(id); + }); + + // Detach the child process so it can continue running independently + child.unref(); + + return config; + } catch (error) { + console.error(`Failed to launch Camoufox: ${error}`); + throw error; } - - // Set Camoufox configuration via environment variables - setCamoufoxConfigEnv(camoufoxConfig, env); - - if (options.debug) { - console.log( - "Camoufox configuration:", - JSON.stringify(camoufoxConfig, null, 2), - ); - console.log( - "Environment variables set:", - Object.keys(env).filter((key) => key.startsWith("CAMOU_CONFIG_")), - ); - } - - // Handle virtual display - if (options.virtual_display) { - env.DISPLAY = options.virtual_display; - } - - // Launch the process - const child = spawn(executablePath, args, { - env: env as NodeJS.ProcessEnv, - detached: true, - stdio: options.debug ? "inherit" : "ignore", - }); - - if (!child.pid) { - throw new Error("Failed to launch Camoufox process"); - } - - const config: CamoufoxConfig = { - id, - pid: child.pid, - executablePath, - profilePath, - url, - options, - }; - - // Save configuration - saveCamoufoxConfig(config); - - // Handle process exit - child.on("exit", (code, signal) => { - console.log( - `Camoufox process ${child.pid} exited with code ${code}, signal ${signal}`, - ); - deleteCamoufoxConfig(id); - }); - - child.on("error", (error) => { - console.error(`Camoufox process error: ${error}`); - deleteCamoufoxConfig(id); - }); - - // Detach the child process so it can continue running independently - child.unref(); - - return config; } /** diff --git a/nodecar/src/index.ts b/nodecar/src/index.ts index 9a4eb30..481e8e7 100644 --- a/nodecar/src/index.ts +++ b/nodecar/src/index.ts @@ -71,7 +71,7 @@ program "Error: Either --upstream URL or --host, --proxy-port, and --type are required", ); console.log( - "Example: proxy start --host datacenter.proxyempire.io --proxy-port 9000 --type http --username user --password pass", + "Example: proxy start --host example.com --proxy-port 9000 --type http --username user --password pass", ); process.exit(1); return; @@ -221,6 +221,12 @@ program .option("--webgl-vendor ", "WebGL vendor string") .option("--webgl-renderer ", "WebGL renderer string") + // Fingerprint + .option( + "--fingerprint ", + "custom BrowserForge fingerprint (JSON string)", + ) + // Proxy .option( "--proxy ", @@ -264,6 +270,18 @@ program : options.os; } + // Set geolocation from individual latitude/longitude values + if (options.latitude && options.longitude) { + camoufoxOptions.geolocation = { + latitude: options.latitude, + longitude: options.longitude, + }; + } + + // Set timezone and country only if explicitly provided + if (options.country) camoufoxOptions.country = options.country; + if (options.timezone) camoufoxOptions.timezone = options.timezone; + // Blocking options if (options.blockImages) camoufoxOptions.block_images = true; if (options.blockWebrtc) camoufoxOptions.block_webrtc = true; @@ -272,25 +290,12 @@ program // Security options if (options.disableCoop) camoufoxOptions.disable_coop = true; - // Geolocation + // Geolocation IP if (options.geoip) { camoufoxOptions.geoip = options.geoip === "auto" ? true : options.geoip; } - // Combine latitude/longitude into geolocation object if both provided - if (options.latitude && options.longitude) { - camoufoxOptions.geolocation = { - latitude: options.latitude, - longitude: options.longitude, - accuracy: 100, - }; - } - - // Set timezone and country only if explicitly provided - if (options.country) camoufoxOptions.country = options.country; - if (options.timezone) camoufoxOptions.timezone = options.timezone; - // UI and behavior if (options.humanize) camoufoxOptions.humanize = options.humanize; if (options.headless) camoufoxOptions.headless = true; @@ -306,24 +311,33 @@ program if (options.addons) camoufoxOptions.addons = options.addons.split(","); if (options.fonts) camoufoxOptions.fonts = options.fonts.split(","); if (options.customFontsOnly) camoufoxOptions.custom_fonts_only = true; - if (options.excludeAddons) - camoufoxOptions.exclude_addons = options.excludeAddons.split(","); - - // Screen dimensions - combine into screen object if any are provided - const screenOptions: any = {}; - if (options.screenMinWidth) - screenOptions.minWidth = options.screenMinWidth; - if (options.screenMaxWidth) - screenOptions.maxWidth = options.screenMaxWidth; - if (options.screenMinHeight) - screenOptions.minHeight = options.screenMinHeight; - if (options.screenMaxHeight) - screenOptions.maxHeight = options.screenMaxHeight; - if (Object.keys(screenOptions).length > 0) { - camoufoxOptions.screen = screenOptions; + if (options.excludeAddons) { + // Only support UBO for now as that's what camoufox-js supports + const excludeList = options.excludeAddons.split(","); + if (excludeList.includes("UBO") || excludeList.includes("ubo")) { + camoufoxOptions.exclude_addons = ["UBO"]; + } } - // Window dimensions - combine into window tuple if both provided + // Screen dimensions - combine into screen object + if ( + options.screenMinWidth || + options.screenMaxWidth || + options.screenMinHeight || + options.screenMaxHeight + ) { + camoufoxOptions.screen = {}; + if (options.screenMinWidth) + camoufoxOptions.screen.minWidth = options.screenMinWidth; + if (options.screenMaxWidth) + camoufoxOptions.screen.maxWidth = options.screenMaxWidth; + if (options.screenMinHeight) + camoufoxOptions.screen.minHeight = options.screenMinHeight; + if (options.screenMaxHeight) + camoufoxOptions.screen.maxHeight = options.screenMaxHeight; + } + + // Window dimensions - combine into window tuple if (options.windowWidth && options.windowHeight) { camoufoxOptions.window = [options.windowWidth, options.windowHeight]; } @@ -332,7 +346,7 @@ program if (options.ffVersion) camoufoxOptions.ff_version = options.ffVersion; if (options.mainWorldEval) camoufoxOptions.main_world_eval = true; - // WebGL - combine vendor and renderer into webgl_config tuple if both provided + // WebGL - combine vendor and renderer into webgl_config tuple if (options.webglVendor && options.webglRenderer) { camoufoxOptions.webgl_config = [ options.webglVendor, @@ -340,6 +354,17 @@ program ]; } + // Fingerprint + if (options.fingerprint) { + try { + camoufoxOptions.fingerprint = JSON.parse(options.fingerprint); + } catch (e) { + console.error("Invalid JSON for --fingerprint option"); + process.exit(1); + return; + } + } + // Proxy if (options.proxy) camoufoxOptions.proxy = options.proxy; @@ -402,7 +427,7 @@ program console.log(JSON.stringify({ success })); process.exit(0); } else if (action === "list") { - const processes = listCamoufoxProcesses(); + const processes = await listCamoufoxProcesses(); // The processes already have snake_case properties, no conversion needed console.log(JSON.stringify(processes)); process.exit(0); diff --git a/package.json b/package.json index c68e357..02dc60b 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@biomejs/biome": "2.0.6", "@tailwindcss/postcss": "^4.1.11", "@tauri-apps/cli": "^2.6.2", - "@types/node": "^24.0.10", + "@types/node": "^24.0.11", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", "@vitejs/plugin-react": "^4.6.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dcb0610..43f3321 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -106,8 +106,8 @@ importers: specifier: ^2.6.2 version: 2.6.2 '@types/node': - specifier: ^24.0.10 - version: 24.0.10 + specifier: ^24.0.11 + version: 24.0.11 '@types/react': specifier: ^19.1.8 version: 19.1.8 @@ -116,7 +116,7 @@ importers: version: 19.1.6(@types/react@19.1.8) '@vitejs/plugin-react': specifier: ^4.6.0 - version: 4.6.0(vite@6.2.0(@types/node@24.0.10)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + version: 4.6.0(vite@7.0.3(@types/node@24.0.11)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) husky: specifier: ^9.1.7 version: 9.1.7 @@ -140,19 +140,19 @@ importers: dependencies: '@types/node': specifier: ^24.0.10 - version: 24.0.10 + version: 24.0.11 '@yao-pkg/pkg': specifier: ^6.5.1 version: 6.5.1(encoding@0.1.13) camoufox-js: - specifier: ^0.6.0 - version: 0.6.0(encoding@0.1.13)(playwright-core@1.53.2) + specifier: file:../../camoufox-js + version: file:../camoufox-js commander: specifier: ^14.0.0 version: 14.0.0 dotenv: specifier: ^17.0.1 - version: 17.0.1 + version: 17.1.0 get-port: specifier: ^7.1.0 version: 7.1.0 @@ -167,7 +167,7 @@ importers: version: 0.2.3 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@24.0.10)(typescript@5.8.3) + version: 10.9.2(@types/node@24.0.11)(typescript@5.8.3) typescript: specifier: ^5.8.3 version: 5.8.3 @@ -198,10 +198,6 @@ packages: resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} engines: {node: '>=6.9.0'} - '@babel/generator@7.27.5': - resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==} - engines: {node: '>=6.9.0'} - '@babel/generator@7.28.0': resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} engines: {node: '>=6.9.0'} @@ -244,11 +240,6 @@ packages: resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} engines: {node: '>=6.9.0'} - '@babel/parser@7.27.5': - resolution: {integrity: sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/parser@7.28.0': resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} engines: {node: '>=6.0.0'} @@ -278,14 +269,6 @@ packages: resolution: {integrity: sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==} engines: {node: '>=6.9.0'} - '@babel/types@7.27.3': - resolution: {integrity: sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.27.6': - resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==} - engines: {node: '>=6.9.0'} - '@babel/types@7.28.0': resolution: {integrity: sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==} engines: {node: '>=6.9.0'} @@ -347,155 +330,161 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@emnapi/runtime@1.4.3': - resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} + '@emnapi/runtime@1.4.4': + resolution: {integrity: sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==} - '@esbuild/aix-ppc64@0.25.5': - resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} + '@esbuild/aix-ppc64@0.25.6': + resolution: {integrity: sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.5': - resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} + '@esbuild/android-arm64@0.25.6': + resolution: {integrity: sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.5': - resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} + '@esbuild/android-arm@0.25.6': + resolution: {integrity: sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.5': - resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} + '@esbuild/android-x64@0.25.6': + resolution: {integrity: sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.5': - resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} + '@esbuild/darwin-arm64@0.25.6': + resolution: {integrity: sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.5': - resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} + '@esbuild/darwin-x64@0.25.6': + resolution: {integrity: sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.5': - resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} + '@esbuild/freebsd-arm64@0.25.6': + resolution: {integrity: sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.5': - resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} + '@esbuild/freebsd-x64@0.25.6': + resolution: {integrity: sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.5': - resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} + '@esbuild/linux-arm64@0.25.6': + resolution: {integrity: sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.5': - resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} + '@esbuild/linux-arm@0.25.6': + resolution: {integrity: sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.5': - resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} + '@esbuild/linux-ia32@0.25.6': + resolution: {integrity: sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.5': - resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} + '@esbuild/linux-loong64@0.25.6': + resolution: {integrity: sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.5': - resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} + '@esbuild/linux-mips64el@0.25.6': + resolution: {integrity: sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.5': - resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} + '@esbuild/linux-ppc64@0.25.6': + resolution: {integrity: sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.5': - resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} + '@esbuild/linux-riscv64@0.25.6': + resolution: {integrity: sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.5': - resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} + '@esbuild/linux-s390x@0.25.6': + resolution: {integrity: sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.5': - resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} + '@esbuild/linux-x64@0.25.6': + resolution: {integrity: sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.5': - resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} + '@esbuild/netbsd-arm64@0.25.6': + resolution: {integrity: sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.5': - resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} + '@esbuild/netbsd-x64@0.25.6': + resolution: {integrity: sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.5': - resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} + '@esbuild/openbsd-arm64@0.25.6': + resolution: {integrity: sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.5': - resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} + '@esbuild/openbsd-x64@0.25.6': + resolution: {integrity: sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.25.5': - resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} + '@esbuild/openharmony-arm64@0.25.6': + resolution: {integrity: sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.6': + resolution: {integrity: sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.5': - resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} + '@esbuild/win32-arm64@0.25.6': + resolution: {integrity: sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.5': - resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} + '@esbuild/win32-ia32@0.25.6': + resolution: {integrity: sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.5': - resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} + '@esbuild/win32-x64@0.25.6': + resolution: {integrity: sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -641,27 +630,13 @@ packages: '@jridgewell/gen-mapping@0.3.12': resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} - '@jridgewell/gen-mapping@0.3.8': - resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} - engines: {node: '>=6.0.0'} - '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/sourcemap-codec@1.5.4': resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@jridgewell/trace-mapping@0.3.29': resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} @@ -1238,10 +1213,6 @@ packages: cpu: [x64] os: [win32] - '@sindresorhus/is@4.6.0': - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} - '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -1470,8 +1441,8 @@ packages: '@types/node-fetch@2.6.12': resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} - '@types/node@24.0.10': - resolution: {integrity: sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA==} + '@types/node@24.0.11': + resolution: {integrity: sha512-CJV8eqrYnwQJGMrvcRhQmZfpyniDavB+7nAZYJc6w99hFYJyFN3INV1/2W3QfQrqM36WTLrijJ1fxxvGBmCSxA==} '@types/react-dom@19.1.6': resolution: {integrity: sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==} @@ -1519,8 +1490,8 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} - agent-base@7.1.3: - resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} agentkeepalive@4.6.0: @@ -1629,18 +1600,11 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} + camoufox-js@file:../camoufox-js: + resolution: {directory: ../camoufox-js, type: directory} - camoufox-js@0.6.0: - resolution: {integrity: sha512-QoCZoDdkXFRdHV4IgthBTogFCTL2p9QKFyEHGE6q1vGm0a9P3ael5zLXGPYiEzI5ByH2nlH4SV6CjQIJKjbxaA==} - hasBin: true - peerDependencies: - playwright-core: '*' - - caniuse-lite@1.0.30001726: - resolution: {integrity: sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==} + caniuse-lite@1.0.30001727: + resolution: {integrity: sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -1788,12 +1752,8 @@ packages: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} - dot-prop@6.0.1: - resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} - engines: {node: '>=10'} - - dotenv@17.0.1: - resolution: {integrity: sha512-GLjkduuAL7IMJg/ZnOPm9AnWKJ82mSE2tzXLaJ/6hD6DhwGfZaXG77oB8qbReyiczNxnbxQKyh0OE5mXq0bAHA==} + dotenv@17.1.0: + resolution: {integrity: sha512-tG9VUTJTuju6GcXgbdsOuRhupE8cb4mRgY5JLRCh4MtGoVo3/gfGUtOMwmProM6d0ba2mCFvv+WrpYJV6qgJXQ==} engines: {node: '>=12'} dunder-proto@1.0.1: @@ -1803,8 +1763,8 @@ packages: duplexer2@0.1.4: resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} - electron-to-chromium@1.5.179: - resolution: {integrity: sha512-UWKi/EbBopgfFsc5k61wFpV7WrnnSlSzW/e2XcBmS6qKYTivZlLtoll5/rdqRTxGglGHkmkW0j0pFNJG10EUIQ==} + electron-to-chromium@1.5.180: + resolution: {integrity: sha512-ED+GEyEh3kYMwt2faNmgMB0b8O5qtATGgR4RmRsIp4T6p7B8vdMbIedYndnvZfsaXvSzegtpfqRMDNCjjiSduA==} emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -1815,8 +1775,8 @@ packages: encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} enhanced-resolve@5.18.2: resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==} @@ -1849,8 +1809,8 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - esbuild@0.25.5: - resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} + esbuild@0.25.6: + resolution: {integrity: sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==} engines: {node: '>=18'} hasBin: true @@ -1865,8 +1825,8 @@ packages: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} - fdir@6.4.5: - resolution: {integrity: sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==} + fdir@6.4.6: + resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -1880,10 +1840,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - fingerprint-generator@2.1.69: - resolution: {integrity: sha512-Sfd2cLmvVVkzVYvC8+DZWiawquksAbAzrx9+AllpLOg8qlH8votU/Ozx59Z+/70GGQDlEsk48zo7FF5S5vuTEA==} - engines: {node: '>=16.0.0'} - form-data@4.0.3: resolution: {integrity: sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==} engines: {node: '>= 6'} @@ -1990,10 +1946,6 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - header-generator@2.1.69: - resolution: {integrity: sha512-J3BK8UtPAR1Lvvfd/qlzmAS1Qb6Q2qx4K1s4FjYVrYvSQnUc7GgOAo9uacebg6WGCdP0eWxtojh7JwEd+AD2Hw==} - engines: {node: '>=16.0.0'} - http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} @@ -2145,10 +2097,6 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-obj@2.0.0: - resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} - engines: {node: '>=8'} - is-standalone-pwa@0.1.1: resolution: {integrity: sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g==} @@ -2277,10 +2225,6 @@ packages: resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} engines: {node: '>=18.0.0'} - lodash.isequal@4.5.0: - resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} - deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. - lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -2498,10 +2442,6 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} - ow@0.28.2: - resolution: {integrity: sha512-dD4UpyBh/9m4X2NVjA+73/ZPBRF+uF4zIMFvvQsabMiEK8x41L3rQ8EENOi35kyyoaJwNxEeJcP6Fj1H4U409Q==} - engines: {node: '>=12'} - p-is-promise@3.0.0: resolution: {integrity: sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==} engines: {node: '>=8'} @@ -2533,11 +2473,6 @@ packages: engines: {node: '>=0.10'} hasBin: true - playwright-core@1.53.2: - resolution: {integrity: sha512-ox/OytMy+2w1jcYEYlOo1Hhp8hZkLCximMTUTMBXjGUA1KoFfiSZ+DU+3a739jsPY0yoKH2TFy9S2fsJas8yAw==} - engines: {node: '>=18'} - hasBin: true - postcss@8.4.31: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} @@ -2577,8 +2512,8 @@ packages: pstree.remy@1.1.8: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} @@ -2990,23 +2925,19 @@ packages: v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - vali-date@1.0.0: - resolution: {integrity: sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg==} - engines: {node: '>=0.10.0'} - - vite@6.2.0: - resolution: {integrity: sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vite@7.0.3: + resolution: {integrity: sha512-y2L5oJZF7bj4c0jgGYgBNSdIu+5HF+m68rn2cQXFbGoShdhV1phX9rbnxy9YXj82aS8MMsCLAAFkRxZeWdldrQ==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@types/node': ^20.19.0 || >=22.12.0 jiti: '>=1.21.0' - less: '*' + less: ^4.0.0 lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 @@ -3135,14 +3066,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.27.5': - dependencies: - '@babel/parser': 7.27.5 - '@babel/types': 7.27.3 - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 3.1.0 - '@babel/generator@7.28.0': dependencies: '@babel/parser': 7.28.0 @@ -3190,10 +3113,6 @@ snapshots: '@babel/template': 7.27.2 '@babel/types': 7.28.0 - '@babel/parser@7.27.5': - dependencies: - '@babel/types': 7.27.3 - '@babel/parser@7.28.0': dependencies: '@babel/types': 7.28.0 @@ -3228,16 +3147,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/types@7.27.3': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - - '@babel/types@7.27.6': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/types@7.28.0': dependencies: '@babel/helper-string-parser': 7.27.1 @@ -3282,84 +3191,87 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@emnapi/runtime@1.4.3': + '@emnapi/runtime@1.4.4': dependencies: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.25.5': + '@esbuild/aix-ppc64@0.25.6': optional: true - '@esbuild/android-arm64@0.25.5': + '@esbuild/android-arm64@0.25.6': optional: true - '@esbuild/android-arm@0.25.5': + '@esbuild/android-arm@0.25.6': optional: true - '@esbuild/android-x64@0.25.5': + '@esbuild/android-x64@0.25.6': optional: true - '@esbuild/darwin-arm64@0.25.5': + '@esbuild/darwin-arm64@0.25.6': optional: true - '@esbuild/darwin-x64@0.25.5': + '@esbuild/darwin-x64@0.25.6': optional: true - '@esbuild/freebsd-arm64@0.25.5': + '@esbuild/freebsd-arm64@0.25.6': optional: true - '@esbuild/freebsd-x64@0.25.5': + '@esbuild/freebsd-x64@0.25.6': optional: true - '@esbuild/linux-arm64@0.25.5': + '@esbuild/linux-arm64@0.25.6': optional: true - '@esbuild/linux-arm@0.25.5': + '@esbuild/linux-arm@0.25.6': optional: true - '@esbuild/linux-ia32@0.25.5': + '@esbuild/linux-ia32@0.25.6': optional: true - '@esbuild/linux-loong64@0.25.5': + '@esbuild/linux-loong64@0.25.6': optional: true - '@esbuild/linux-mips64el@0.25.5': + '@esbuild/linux-mips64el@0.25.6': optional: true - '@esbuild/linux-ppc64@0.25.5': + '@esbuild/linux-ppc64@0.25.6': optional: true - '@esbuild/linux-riscv64@0.25.5': + '@esbuild/linux-riscv64@0.25.6': optional: true - '@esbuild/linux-s390x@0.25.5': + '@esbuild/linux-s390x@0.25.6': optional: true - '@esbuild/linux-x64@0.25.5': + '@esbuild/linux-x64@0.25.6': optional: true - '@esbuild/netbsd-arm64@0.25.5': + '@esbuild/netbsd-arm64@0.25.6': optional: true - '@esbuild/netbsd-x64@0.25.5': + '@esbuild/netbsd-x64@0.25.6': optional: true - '@esbuild/openbsd-arm64@0.25.5': + '@esbuild/openbsd-arm64@0.25.6': optional: true - '@esbuild/openbsd-x64@0.25.5': + '@esbuild/openbsd-x64@0.25.6': optional: true - '@esbuild/sunos-x64@0.25.5': + '@esbuild/openharmony-arm64@0.25.6': optional: true - '@esbuild/win32-arm64@0.25.5': + '@esbuild/sunos-x64@0.25.6': optional: true - '@esbuild/win32-ia32@0.25.5': + '@esbuild/win32-arm64@0.25.6': optional: true - '@esbuild/win32-x64@0.25.5': + '@esbuild/win32-ia32@0.25.6': + optional: true + + '@esbuild/win32-x64@0.25.6': optional: true '@floating-ui/core@1.7.2': @@ -3451,7 +3363,7 @@ snapshots: '@img/sharp-wasm32@0.34.2': dependencies: - '@emnapi/runtime': 1.4.3 + '@emnapi/runtime': 1.4.4 optional: true '@img/sharp-win32-arm64@0.34.2': @@ -3472,25 +3384,10 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.4 '@jridgewell/trace-mapping': 0.3.29 - '@jridgewell/gen-mapping@0.3.8': - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 - '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/set-array@1.2.1': {} - - '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/sourcemap-codec@1.5.4': {} - '@jridgewell/trace-mapping@0.3.25': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping@0.3.29': dependencies: '@jridgewell/resolve-uri': 3.1.2 @@ -3499,7 +3396,7 @@ snapshots: '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.4 '@next/env@15.3.5': {} @@ -4020,8 +3917,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.44.2': optional: true - '@sindresorhus/is@4.6.0': {} - '@swc/counter@0.1.3': {} '@swc/helpers@0.5.15': @@ -4211,10 +4106,10 @@ snapshots: '@types/node-fetch@2.6.12': dependencies: - '@types/node': 24.0.10 + '@types/node': 24.0.11 form-data: 4.0.3 - '@types/node@24.0.10': + '@types/node@24.0.11': dependencies: undici-types: 7.8.0 @@ -4228,7 +4123,7 @@ snapshots: '@types/tmp@0.2.6': {} - '@vitejs/plugin-react@4.6.0(vite@6.2.0(@types/node@24.0.10)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))': + '@vitejs/plugin-react@4.6.0(vite@7.0.3(@types/node@24.0.11)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.0) @@ -4236,7 +4131,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.19 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.2.0(@types/node@24.0.10)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) + vite: 7.0.3(@types/node@24.0.11)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) transitivePeerDependencies: - supports-color @@ -4255,9 +4150,9 @@ snapshots: '@yao-pkg/pkg@6.5.1(encoding@0.1.13)': dependencies: - '@babel/generator': 7.27.5 - '@babel/parser': 7.27.5 - '@babel/types': 7.27.6 + '@babel/generator': 7.28.0 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.0 '@yao-pkg/pkg-fetch': 3.5.23(encoding@0.1.13) into-stream: 6.0.0 minimist: 1.2.8 @@ -4291,7 +4186,7 @@ snapshots: transitivePeerDependencies: - supports-color - agent-base@7.1.3: {} + agent-base@7.1.4: {} agentkeepalive@4.6.0: dependencies: @@ -4385,8 +4280,8 @@ snapshots: browserslist@4.25.1: dependencies: - caniuse-lite: 1.0.30001726 - electron-to-chromium: 1.5.179 + caniuse-lite: 1.0.30001727 + electron-to-chromium: 1.5.180 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.1) @@ -4428,28 +4323,26 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 - callsites@3.1.0: {} - - camoufox-js@0.6.0(encoding@0.1.13)(playwright-core@1.53.2): + camoufox-js@file:../camoufox-js: dependencies: adm-zip: 0.5.16 + browserslist: 4.25.1 commander: 13.1.0 - fingerprint-generator: 2.1.69 + encoding: 0.1.13 + generative-bayesian-network: 2.1.69 impit: 0.5.2 js-yaml: 4.1.0 language-tags: 2.1.0 maxmind: 4.3.28 - playwright-core: 1.53.2 progress: 2.0.3 sqlite3: 5.1.7 ua-parser-js: 2.0.4(encoding@0.1.13) xml2js: 0.6.2 transitivePeerDependencies: - bluebird - - encoding - supports-color - caniuse-lite@1.0.30001726: {} + caniuse-lite@1.0.30001727: {} chalk@4.1.2: dependencies: @@ -4585,11 +4478,7 @@ snapshots: diff@4.0.2: {} - dot-prop@6.0.1: - dependencies: - is-obj: 2.0.0 - - dotenv@17.0.1: {} + dotenv@17.1.0: {} dunder-proto@1.0.1: dependencies: @@ -4601,7 +4490,7 @@ snapshots: dependencies: readable-stream: 2.3.8 - electron-to-chromium@1.5.179: {} + electron-to-chromium@1.5.180: {} emoji-regex@10.4.0: {} @@ -4610,9 +4499,8 @@ snapshots: encoding@0.1.13: dependencies: iconv-lite: 0.6.3 - optional: true - end-of-stream@1.4.4: + end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -4644,33 +4532,34 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - esbuild@0.25.5: + esbuild@0.25.6: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.5 - '@esbuild/android-arm': 0.25.5 - '@esbuild/android-arm64': 0.25.5 - '@esbuild/android-x64': 0.25.5 - '@esbuild/darwin-arm64': 0.25.5 - '@esbuild/darwin-x64': 0.25.5 - '@esbuild/freebsd-arm64': 0.25.5 - '@esbuild/freebsd-x64': 0.25.5 - '@esbuild/linux-arm': 0.25.5 - '@esbuild/linux-arm64': 0.25.5 - '@esbuild/linux-ia32': 0.25.5 - '@esbuild/linux-loong64': 0.25.5 - '@esbuild/linux-mips64el': 0.25.5 - '@esbuild/linux-ppc64': 0.25.5 - '@esbuild/linux-riscv64': 0.25.5 - '@esbuild/linux-s390x': 0.25.5 - '@esbuild/linux-x64': 0.25.5 - '@esbuild/netbsd-arm64': 0.25.5 - '@esbuild/netbsd-x64': 0.25.5 - '@esbuild/openbsd-arm64': 0.25.5 - '@esbuild/openbsd-x64': 0.25.5 - '@esbuild/sunos-x64': 0.25.5 - '@esbuild/win32-arm64': 0.25.5 - '@esbuild/win32-ia32': 0.25.5 - '@esbuild/win32-x64': 0.25.5 + '@esbuild/aix-ppc64': 0.25.6 + '@esbuild/android-arm': 0.25.6 + '@esbuild/android-arm64': 0.25.6 + '@esbuild/android-x64': 0.25.6 + '@esbuild/darwin-arm64': 0.25.6 + '@esbuild/darwin-x64': 0.25.6 + '@esbuild/freebsd-arm64': 0.25.6 + '@esbuild/freebsd-x64': 0.25.6 + '@esbuild/linux-arm': 0.25.6 + '@esbuild/linux-arm64': 0.25.6 + '@esbuild/linux-ia32': 0.25.6 + '@esbuild/linux-loong64': 0.25.6 + '@esbuild/linux-mips64el': 0.25.6 + '@esbuild/linux-ppc64': 0.25.6 + '@esbuild/linux-riscv64': 0.25.6 + '@esbuild/linux-s390x': 0.25.6 + '@esbuild/linux-x64': 0.25.6 + '@esbuild/netbsd-arm64': 0.25.6 + '@esbuild/netbsd-x64': 0.25.6 + '@esbuild/openbsd-arm64': 0.25.6 + '@esbuild/openbsd-x64': 0.25.6 + '@esbuild/openharmony-arm64': 0.25.6 + '@esbuild/sunos-x64': 0.25.6 + '@esbuild/win32-arm64': 0.25.6 + '@esbuild/win32-ia32': 0.25.6 + '@esbuild/win32-x64': 0.25.6 escalade@3.2.0: {} @@ -4678,7 +4567,7 @@ snapshots: expand-template@2.0.3: {} - fdir@6.4.5(picomatch@4.0.2): + fdir@6.4.6(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 @@ -4688,12 +4577,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - fingerprint-generator@2.1.69: - dependencies: - generative-bayesian-network: 2.1.69 - header-generator: 2.1.69 - tslib: 2.8.1 - form-data@4.0.3: dependencies: asynckit: 0.4.0 @@ -4809,13 +4692,6 @@ snapshots: dependencies: function-bind: 1.1.2 - header-generator@2.1.69: - dependencies: - browserslist: 4.25.1 - generative-bayesian-network: 2.1.69 - ow: 0.28.2 - tslib: 2.8.1 - http-cache-semantics@4.2.0: optional: true @@ -4845,7 +4721,6 @@ snapshots: iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 - optional: true ieee754@1.2.1: {} @@ -4947,8 +4822,6 @@ snapshots: is-number@7.0.0: {} - is-obj@2.0.0: {} - is-standalone-pwa@0.1.1: {} isarray@1.0.0: {} @@ -5059,8 +4932,6 @@ snapshots: rfdc: 1.4.1 wrap-ansi: 9.0.0 - lodash.isequal@4.5.0: {} - lodash@4.17.21: {} log-update@6.1.0: @@ -5218,7 +5089,7 @@ snapshots: '@swc/counter': 0.1.3 '@swc/helpers': 0.5.15 busboy: 1.6.0 - caniuse-lite: 1.0.30001726 + caniuse-lite: 1.0.30001727 postcss: 8.4.31 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) @@ -5306,14 +5177,6 @@ snapshots: dependencies: mimic-function: 5.0.1 - ow@0.28.2: - dependencies: - '@sindresorhus/is': 4.6.0 - callsites: 3.1.0 - dot-prop: 6.0.1 - lodash.isequal: 4.5.0 - vali-date: 1.0.0 - p-is-promise@3.0.0: {} p-map@4.0.0: @@ -5334,8 +5197,6 @@ snapshots: pidtree@0.6.0: {} - playwright-core@1.53.2: {} - postcss@8.4.31: dependencies: nanoid: 3.3.11 @@ -5357,7 +5218,7 @@ snapshots: mkdirp-classic: 0.5.3 napi-build-utils: 2.0.0 node-abi: 3.75.0 - pump: 3.0.2 + pump: 3.0.3 rc: 1.2.8 simple-get: 4.0.1 tar-fs: 2.1.3 @@ -5386,9 +5247,9 @@ snapshots: pstree.remy@1.1.8: {} - pump@3.0.2: + pump@3.0.3: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 once: 1.4.0 rc@1.2.8: @@ -5515,8 +5376,7 @@ snapshots: safe-buffer@5.2.1: {} - safer-buffer@2.1.2: - optional: true + safer-buffer@2.1.2: {} sax@1.4.1: {} @@ -5605,7 +5465,7 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: - agent-base: 7.1.3 + agent-base: 7.1.4 debug: 4.4.1(supports-color@5.5.0) socks: 2.8.5 transitivePeerDependencies: @@ -5709,13 +5569,13 @@ snapshots: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.2 + pump: 3.0.3 tar-stream: 2.2.0 tar-stream@2.2.0: dependencies: bl: 4.1.0 - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 fs-constants: 1.0.0 inherits: 2.0.4 readable-stream: 3.6.2 @@ -5746,7 +5606,7 @@ snapshots: tinyglobby@0.2.14: dependencies: - fdir: 6.4.5(picomatch@4.0.2) + fdir: 6.4.6(picomatch@4.0.2) picomatch: 4.0.2 tmp@0.2.3: {} @@ -5759,14 +5619,14 @@ snapshots: tr46@0.0.3: {} - ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3): + ts-node@10.9.2(@types/node@24.0.11)(typescript@5.8.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 24.0.10 + '@types/node': 24.0.11 acorn: 8.15.0 acorn-walk: 8.3.4 arg: 4.1.3 @@ -5861,15 +5721,16 @@ snapshots: v8-compile-cache-lib@3.0.1: {} - vali-date@1.0.0: {} - - vite@6.2.0(@types/node@24.0.10)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0): + vite@7.0.3(@types/node@24.0.11)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0): dependencies: - esbuild: 0.25.5 + esbuild: 0.25.6 + fdir: 6.4.6(picomatch@4.0.2) + picomatch: 4.0.2 postcss: 8.5.6 rollup: 4.44.2 + tinyglobby: 0.2.14 optionalDependencies: - '@types/node': 24.0.10 + '@types/node': 24.0.11 fsevents: 2.3.3 jiti: 2.4.2 lightningcss: 1.30.1 diff --git a/src-tauri/src/camoufox.rs b/src-tauri/src/camoufox.rs index bc26814..0997fff 100644 --- a/src-tauri/src/camoufox.rs +++ b/src-tauri/src/camoufox.rs @@ -30,6 +30,7 @@ pub struct CamoufoxConfig { pub screen_max_height: Option, pub window_width: Option, pub window_height: Option, + pub fingerprint: Option, pub ff_version: Option, pub main_world_eval: Option, pub webgl_vendor: Option, @@ -70,6 +71,7 @@ impl Default for CamoufoxConfig { screen_max_height: None, window_width: None, window_height: None, + fingerprint: None, ff_version: None, main_world_eval: None, webgl_vendor: None, @@ -265,6 +267,13 @@ impl CamoufoxLauncher { } } + // Fingerprint + if let Some(fingerprint) = &config.fingerprint { + let fingerprint_json = serde_json::to_string(fingerprint) + .map_err(|e| format!("Failed to serialize fingerprint: {e}"))?; + sidecar = sidecar.arg("--fingerprint").arg(fingerprint_json); + } + if let Some(proxy) = &config.proxy { sidecar = sidecar.arg("--proxy").arg(proxy); }