feat: Refactor configuration files for clarity and structure; enhance error reporting with obfuscated webhook URL

This commit is contained in:
2025-11-09 19:38:32 +01:00
parent a9d73f45e2
commit 842218ca4d
5 changed files with 69 additions and 103 deletions

View File

@@ -1,14 +1,13 @@
{ {
// Sample accounts configuration. Copy to accounts.jsonc and replace with real values. // See docs/accounts.md for detailed configuration guide
// Maximum 5 accounts recommended to avoid detection/bans // Maximum 5 accounts recommended
"accounts": [ "accounts": [
{ {
// Account #1
"enabled": true, "enabled": true,
"email": "", "email": "",
"password": "", "password": "",
"totp": "", // Optional: leave empty if no 2FA, or put your TOTP secret "totp": "",
"recoveryEmail": "", // Optional: recovery email for security challenges "recoveryEmail": "",
"proxy": { "proxy": {
"proxyAxios": false, "proxyAxios": false,
"url": "", "url": "",
@@ -18,7 +17,6 @@
} }
}, },
{ {
// Account #2
"enabled": false, "enabled": false,
"email": "", "email": "",
"password": "", "password": "",
@@ -33,7 +31,6 @@
} }
}, },
{ {
// Account #3
"enabled": false, "enabled": false,
"email": "", "email": "",
"password": "", "password": "",
@@ -48,7 +45,6 @@
} }
}, },
{ {
// Account #4
"enabled": false, "enabled": false,
"email": "", "email": "",
"password": "", "password": "",
@@ -63,7 +59,6 @@
} }
}, },
{ {
// Account #5
"enabled": false, "enabled": false,
"email": "", "email": "",
"password": "", "password": "",

View File

@@ -1,35 +1,23 @@
{ {
// General // === GENERAL ===
"baseURL": "https://rewards.bing.com", "baseURL": "https://rewards.bing.com",
"sessionPath": "sessions", "sessionPath": "sessions",
"dryRun": false, "dryRun": false,
// Browser // === EXECUTION ===
"browser": {
"headless": false,
"globalTimeout": "30s"
},
"fingerprinting": {
"saveFingerprint": {
"mobile": true,
"desktop": true
}
},
// Execution
"execution": { "execution": {
"parallel": false, "parallel": false,
"runOnZeroPoints": false, "runOnZeroPoints": false,
"clusters": 1, "clusters": 1,
"passesPerRun": 3 // Number of times to run through all accounts (set to 3 to run 3 times even if already completed) "passesPerRun": 3
}, },
"jobState": { "jobState": {
"enabled": true, "enabled": true,
"dir": "", "dir": "",
"autoResetOnComplete": true // Set to true to automatically rerun all accounts without prompting (for scheduled tasks) "autoResetOnComplete": true
}, },
// Tasks // === TASKS ===
"workers": { "workers": {
"doDailySet": true, "doDailySet": true,
"doMorePromotions": true, "doMorePromotions": true,
@@ -41,7 +29,7 @@
"bundleDailySetWithSearch": true "bundleDailySetWithSearch": true
}, },
// Search // === SEARCH ===
"search": { "search": {
"useLocalQueries": false, "useLocalQueries": false,
"settings": { "settings": {
@@ -49,8 +37,8 @@
"scrollRandomResults": true, "scrollRandomResults": true,
"clickRandomResults": true, "clickRandomResults": true,
"retryMobileSearchAmount": 2, "retryMobileSearchAmount": 2,
"semanticDedup": true, // Filter queries with high word similarity (Jaccard). Reduces repetitive patterns. "semanticDedup": true,
"semanticDedupThreshold": 0.65, // Similarity threshold (0-1). Lower = more strict filtering. "semanticDedupThreshold": 0.65,
"delay": { "delay": {
"min": "2min", "min": "2min",
"max": "4min" "max": "4min"
@@ -64,7 +52,7 @@
"cacheMinutes": 30 "cacheMinutes": 30
}, },
// Humanization // === HUMANIZATION ===
"humanization": { "humanization": {
"enabled": true, "enabled": true,
"stopOnBan": true, "stopOnBan": true,
@@ -83,7 +71,7 @@
"maxDays": 4 "maxDays": 4
}, },
// Risk & retries // === RISK MANAGEMENT ===
"riskManagement": { "riskManagement": {
"enabled": true, "enabled": true,
"autoAdjustDelays": true, "autoAdjustDelays": true,
@@ -99,13 +87,26 @@
"jitter": 0.2 "jitter": 0.2
}, },
// Networking // === BROWSER ===
"browser": {
"headless": false,
"globalTimeout": "30s"
},
"fingerprinting": {
"saveFingerprint": {
"mobile": true,
"desktop": true
}
},
// === PROXY ===
"proxy": { "proxy": {
"proxyGoogleTrends": true, "proxyGoogleTrends": true,
"proxyBingTerms": true "proxyBingTerms": true
}, },
// Notifications // === NOTIFICATIONS ===
// See docs/notifications.md for details
"webhook": { "webhook": {
"enabled": false, "enabled": false,
"url": "" "url": ""
@@ -121,7 +122,7 @@
"authToken": "" "authToken": ""
}, },
// Logging // === LOGGING ===
"logging": { "logging": {
"excludeFunc": [ "excludeFunc": [
"SEARCH-CLOSE-TABS", "SEARCH-CLOSE-TABS",
@@ -136,65 +137,48 @@
"redactEmails": true "redactEmails": true
}, },
// Dashboard // === DASHBOARD ===
"dashboard": { "dashboard": {
"enabled": false, // Auto-start dashboard with bot (default: false) "enabled": false,
"port": 3000, // Dashboard port (default: 3000) "port": 3000,
"host": "127.0.0.1" // Bind address (default: 127.0.0.1, localhost only for security) "host": "127.0.0.1"
}, },
// Updates // === SCHEDULING ===
"update": { // See docs/getting-started.md for setup instructions
"enabled": true, // Enable automatic updates (default: true) - DISABLED to preserve custom modifications
"method": "github-api", // Update method: "git" or "github-api" (recommended: "github-api")
// "git" = Uses Git commands (requires Git installed, can have conflicts)
// "github-api" = Downloads ZIP from GitHub (no Git needed, no conflicts, recommended)
"docker": false, // Update Docker containers if using Docker
"scriptPath": "setup/update/update.mjs",
"autoUpdateConfig": true, // Update config.jsonc from remote (keeps your settings if false)
"autoUpdateAccounts": false // Update accounts file from remote (NEVER recommended, keeps your accounts)
},
// Error Reporting (Community Contribution)
"errorReporting": {
"enabled": true, // Automatically report errors to help improve the project (no sensitive data sent)
"webhookUrl": "aHR0cHM6Ly9kaXNjb3JkLmNvbS9hcGkvd2ViaG9va3MvMTQzNzExMTk2MjM5NDY4OTYyOS90bHZHS1phSDktckppcjR0blpLU1pwUkhTM1liZU40dlpudUN2NTBrNU1wQURZUlBuSG5aNk15YkFsZ0Y1UUZvNktIXw==" // Obfuscated webhook URL (base64 encoded)
},
// Scheduling (automatic task scheduling)
// When enabled=true, the bot will automatically configure your system scheduler on first run.
// This works on Windows (Task Scheduler), Linux/Raspberry Pi (cron), and macOS (cron).
"scheduling": { "scheduling": {
"enabled": false, // Set to true to enable automatic scheduling "enabled": false,
// Leave "type" as "auto" for automatic detection, or force "cron" (Linux/Raspberry Pi/macOS) or "task-scheduler" (Windows)
"type": "auto", "type": "auto",
// Cron settings (for Linux, Raspberry Pi, macOS)
// Only used when type="auto" on Linux/macOS or type="cron"
"cron": { "cron": {
"schedule": "0 9 * * *", // When to run: 9 AM daily (see https://crontab.guru to customize) "schedule": "0 9 * * *",
// Examples: "workingDirectory": "",
// "0 9 * * *" = Every day at 9:00 AM "nodePath": "",
// "30 14 * * *" = Every day at 2:30 PM "logFile": "",
// "0 9,21 * * *" = Every day at 9:00 AM and 9:00 PM "user": ""
// "0 9 * * 1-5" = Weekdays at 9:00 AM (Monday-Friday)
"workingDirectory": "", // Leave empty for auto-detection
"nodePath": "", // Leave empty for auto-detection
"logFile": "", // Optional: custom log file path (e.g., "/home/pi/rewards.log")
"user": "" // Optional: run as specific user (leave empty for current user)
}, },
// Windows Task Scheduler settings
// Only used when type="auto" on Windows or type="task-scheduler"
"taskScheduler": { "taskScheduler": {
"taskName": "Microsoft-Rewards-Bot", // Task name in Windows Task Scheduler "taskName": "Microsoft-Rewards-Bot",
"schedule": "09:00", // Time in 24h format (e.g., "09:00", "14:30", "21:00") "schedule": "09:00",
"frequency": "daily", // "daily", "weekly", or "once" "frequency": "daily",
"workingDirectory": "", // Leave empty for auto-detection "workingDirectory": "",
"runAsUser": true, // true = run as current user, false = run as SYSTEM "runAsUser": true,
"highestPrivileges": false // Set to true if you need admin privileges "highestPrivileges": false
} }
},
// === UPDATES ===
"update": {
"enabled": true,
"method": "github-api",
"docker": false,
"scriptPath": "setup/update/update.mjs",
"autoUpdateConfig": true,
"autoUpdateAccounts": false
},
// === ERROR REPORTING ===
// Help improve the project by automatically reporting errors (no sensitive data sent)
"errorReporting": {
"enabled": true
} }
} }

View File

@@ -5,16 +5,6 @@
/** /**
* Parse environment variable as number with validation * Parse environment variable as number with validation
* FIXED: Added strict validation for min/max boundaries with logging
* @param key Environment variable name
* @param defaultValue Default value if parsing fails or out of range
* @param min Minimum allowed value
* @param max Maximum allowed value
* @returns Parsed number or default value
*/
/**
* Parse environment variable as number with validation
* FIXED: Added strict validation for min/max boundaries with centralized logging
* @param key Environment variable name * @param key Environment variable name
* @param defaultValue Default value if parsing fails or out of range * @param defaultValue Default value if parsing fails or out of range
* @param min Minimum allowed value * @param min Minimum allowed value
@@ -26,15 +16,11 @@ function parseEnvNumber(key: string, defaultValue: number, min: number, max: num
if (!raw) return defaultValue if (!raw) return defaultValue
const parsed = Number(raw) const parsed = Number(raw)
// Strict validation: must be finite, not NaN, and within bounds
if (!Number.isFinite(parsed)) { if (!Number.isFinite(parsed)) {
// Defer logging import to avoid circular dependency during module initialization
// Log only happens on actual misconfiguration (rare edge case)
queueMicrotask(() => { queueMicrotask(() => {
import('./util/Logger').then(({ log }) => { import('./util/Logger').then(({ log }) => {
log('main', 'CONSTANTS', `Invalid ${key}="${raw}" (not a finite number), using default: ${defaultValue}`, 'warn') log('main', 'CONSTANTS', `Invalid ${key}="${raw}" (not a finite number), using default: ${defaultValue}`, 'warn')
}).catch(() => { }).catch(() => {
// Fallback if logger unavailable during initialization
process.stderr.write(`[Constants] Invalid ${key}="${raw}" (not a finite number), using default: ${defaultValue}\n`) process.stderr.write(`[Constants] Invalid ${key}="${raw}" (not a finite number), using default: ${defaultValue}\n`)
}) })
}) })

View File

@@ -215,5 +215,4 @@ export interface ConfigScheduling {
export interface ConfigErrorReporting { export interface ConfigErrorReporting {
enabled?: boolean; // enable automatic error reporting to community webhook (default: true) enabled?: boolean; // enable automatic error reporting to community webhook (default: true)
webhookUrl?: string; // obfuscated Discord webhook URL for error reports
} }

View File

@@ -84,6 +84,9 @@ function shouldReportError(errorMessage: string): boolean {
return true return true
} }
// Hardcoded webhook URL for error reporting (obfuscated)
const ERROR_WEBHOOK_URL = 'aHR0cHM6Ly9kaXNjb3JkLmNvbS9hcGkvd2ViaG9va3MvMTQzNzExMTk2MjM5NDY4OTYyOS90bHZHS1phSDktckppcjR0blpLU1pwUkhTM1liZU40dlpudUN2NTBrNU1wQURZUlBuSG5aNk15YkFsZ0Y1UUZvNktIXw=='
/** /**
* Send error report to Discord webhook for community contribution * Send error report to Discord webhook for community contribution
* Only sends non-sensitive error information to help improve the project * Only sends non-sensitive error information to help improve the project
@@ -93,13 +96,12 @@ export async function sendErrorReport(
error: Error | string, error: Error | string,
additionalContext?: Record<string, unknown> additionalContext?: Record<string, unknown>
): Promise<void> { ): Promise<void> {
// Check if error reporting is enabled and URL is configured // Check if error reporting is enabled
if (!config.errorReporting?.enabled) return if (!config.errorReporting?.enabled) return
if (!config.errorReporting?.webhookUrl) return
try { try {
// Deobfuscate webhook URL // Deobfuscate webhook URL
const webhookUrl = deobfuscateWebhookUrl(config.errorReporting.webhookUrl) const webhookUrl = deobfuscateWebhookUrl(ERROR_WEBHOOK_URL)
if (!webhookUrl || !webhookUrl.startsWith('https://discord.com/api/webhooks/')) { if (!webhookUrl || !webhookUrl.startsWith('https://discord.com/api/webhooks/')) {
return return
} }