mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-10 01:06:17 +00:00
Update to recovery email management: makes the recoveryEmail field optional and adds the ability to disable recovery email verification per account. Added corresponding documentation and updated configuration examples.
This commit is contained in:
@@ -21,7 +21,7 @@
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
> ℹ️ `recoveryEmail` is **mandatory**. It lets the bot verify Microsoft’s masked hint during login and alert you if the recovery address ever changes.
|
> ℹ️ `recoveryEmail` is still **recommended**. It lets the bot verify Microsoft’s masked hint during login and alert you if the recovery address ever changes. You can opt out per account by setting `"recoveryRequired": false`.
|
||||||
|
|
||||||
**That's it!** Run `npm start` to test.
|
**That's it!** Run `npm start` to test.
|
||||||
|
|
||||||
@@ -60,6 +60,26 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 🚫 Skip the Recovery Email Check (Advanced)
|
||||||
|
|
||||||
|
Most users should keep recovery validation enabled. If an account genuinely has no recovery address or you cannot disclose it, add `"recoveryRequired": false` to that entry. When disabled, the bot skips mismatch detection and logs a warning during startup validation.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"email": "example@outlook.com",
|
||||||
|
"password": "strong_password",
|
||||||
|
"recoveryRequired": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ Without a recovery email the bot cannot detect if Microsoft shows a different masked address. Enable this override only when you accept that risk.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 🎯 Multiple Accounts
|
## 🎯 Multiple Accounts
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|||||||
166
docs/config-reference.md
Normal file
166
docs/config-reference.md
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
# Configuration Reference
|
||||||
|
|
||||||
|
This page mirrors the defaults that ship in `src/config.jsonc` and explains what each field does. Use it as a companion after trimming comments from the JSONC file.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## General
|
||||||
|
|
||||||
|
| Key | Default | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `baseURL` | `https://rewards.bing.com` | Microsoft Rewards dashboard root. |
|
||||||
|
| `sessionPath` | `sessions` | Folder for cookies, fingerprints, and job-state. |
|
||||||
|
| `dryRun` | `false` | Log actions without executing tasks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Browser & Fingerprinting
|
||||||
|
|
||||||
|
| Key | Default | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `browser.headless` | `false` | Use `true` for CI or servers. |
|
||||||
|
| `browser.globalTimeout` | `"30s"` | Accepts milliseconds or readable strings (e.g. `"2min"`). |
|
||||||
|
| `fingerprinting.saveFingerprint.desktop` | `true` | Persist desktop fingerprint between runs. |
|
||||||
|
| `fingerprinting.saveFingerprint.mobile` | `true` | Persist mobile fingerprint.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Execution & Job State
|
||||||
|
|
||||||
|
| Key | Default | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `execution.parallel` | `false` | Run desktop and mobile simultaneously. |
|
||||||
|
| `execution.runOnZeroPoints` | `false` | Skip account when no points remain. |
|
||||||
|
| `execution.clusters` | `1` | Worker processes. Increase for parallel accounts. |
|
||||||
|
| `execution.passesPerRun` | `1` | Extra full passes. Keep at `1` to allow job-state skipping. |
|
||||||
|
| `jobState.enabled` | `true` | Persist daily completion markers. |
|
||||||
|
| `jobState.dir` | `""` | Custom job-state directory (defaults under `sessionPath`).
|
||||||
|
|
||||||
|
> Raising `passesPerRun` intentionally prevents job-state from skipping finished accounts.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Scheduler
|
||||||
|
|
||||||
|
| Key | Default | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `schedule.enabled` | `false` | Enable built-in scheduler loop. |
|
||||||
|
| `schedule.useAmPm` | `false` | Toggle between `time12` (12h) and `time24` (24h). |
|
||||||
|
| `schedule.time12` | `"9:00 AM"` | Used when `useAmPm` is `true`. |
|
||||||
|
| `schedule.time24` | `"09:00"` | Used when `useAmPm` is `false`. |
|
||||||
|
| `schedule.timeZone` | `Europe/Paris` | IANA timezone for scheduling. |
|
||||||
|
| `schedule.runImmediatelyOnStart` | `true` | Execute one pass right after startup. |
|
||||||
|
| `schedule.cron` | - | Optional cron expression(s).
|
||||||
|
|
||||||
|
See `docs/schedule.md` for jitter, cron patterns, and vacation integration.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workers
|
||||||
|
|
||||||
|
| Key | Default | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `workers.doDailySet` | `true` | Daily set. |
|
||||||
|
| `workers.doMorePromotions` | `true` | Extra promotions. |
|
||||||
|
| `workers.doPunchCards` | `true` | Punch cards. |
|
||||||
|
| `workers.doDesktopSearch` | `true` | Desktop search tasks. |
|
||||||
|
| `workers.doMobileSearch` | `true` | Mobile search tasks. |
|
||||||
|
| `workers.doDailyCheckIn` | `true` | Mobile check-in. |
|
||||||
|
| `workers.doReadToEarn` | `true` | Read-to-earn. |
|
||||||
|
| `workers.bundleDailySetWithSearch` | `true` | Launch desktop search immediately after the daily set.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Search & Diversity
|
||||||
|
|
||||||
|
| Key | Default | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `search.useLocalQueries` | `true` | Use region-aware query pools. |
|
||||||
|
| `search.settings.useGeoLocaleQueries` | `true` | Inject account country into generated queries. |
|
||||||
|
| `search.settings.scrollRandomResults` | `true` | Random scrolls for realism. |
|
||||||
|
| `search.settings.clickRandomResults` | `true` | Occasional safe click-through. |
|
||||||
|
| `search.settings.retryMobileSearchAmount` | `2` | Retries for mobile search failures. |
|
||||||
|
| `search.settings.delay.min/max` | `3min` / `5min` | Delay between searches. |
|
||||||
|
| `queryDiversity.enabled` | `true` | Combine multiple content sources. |
|
||||||
|
| `queryDiversity.sources` | `["google-trends", "reddit", "local-fallback"]` | Active diversity sources. |
|
||||||
|
| `queryDiversity.maxQueriesPerSource` | `10` | Cap per source. |
|
||||||
|
| `queryDiversity.cacheMinutes` | `30` | Cache lifetime in minutes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Humanization & Vacation
|
||||||
|
|
||||||
|
| Key | Default | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `humanization.enabled` | `true` | Master toggle. |
|
||||||
|
| `humanization.stopOnBan` | `true` | Halt remaining accounts after a ban. |
|
||||||
|
| `humanization.immediateBanAlert` | `true` | Send alert instantly on ban. |
|
||||||
|
| `humanization.actionDelay.min/max` | `500` / `2200` | Extra wait between steps (ms). |
|
||||||
|
| `humanization.gestureMoveProb` | `0.65` | Chance of micro mouse move. |
|
||||||
|
| `humanization.gestureScrollProb` | `0.4` | Chance of small scroll. |
|
||||||
|
| `humanization.allowedWindows` | `[]` | Optional `HH:mm-HH:mm` windows. |
|
||||||
|
| `vacation.enabled` | `true` | Random monthly break. |
|
||||||
|
| `vacation.minDays` / `maxDays` | `2` / `4` | Range for skipped days.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Risk Management & Retries
|
||||||
|
|
||||||
|
| Key | Default | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `riskManagement.enabled` | `true` | Adaptive risk scoring. |
|
||||||
|
| `riskManagement.autoAdjustDelays` | `true` | Increase delays on high risk. |
|
||||||
|
| `riskManagement.stopOnCritical` | `false` | Stop automation at critical risk. |
|
||||||
|
| `riskManagement.banPrediction` | `true` | Estimate ban likelihood. |
|
||||||
|
| `riskManagement.riskThreshold` | `75` | Alert threshold (0-100). |
|
||||||
|
| `retryPolicy.maxAttempts` | `3` | Generic retry attempts. |
|
||||||
|
| `retryPolicy.baseDelay` | `1000` | Initial backoff delay (ms or string). |
|
||||||
|
| `retryPolicy.maxDelay` | `"30s"` | Maximum backoff delay. |
|
||||||
|
| `retryPolicy.multiplier` | `2` | Backoff multiplier. |
|
||||||
|
| `retryPolicy.jitter` | `0.2` | Adds randomness to delays.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Networking & Notifications
|
||||||
|
|
||||||
|
| Key | Default | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `proxy.proxyGoogleTrends` | `true` | Route Google Trends calls through the proxy. |
|
||||||
|
| `proxy.proxyBingTerms` | `true` | Route Bing requests through the proxy. |
|
||||||
|
| `webhook.enabled` | `false` | Live logs webhook. |
|
||||||
|
| `conclusionWebhook.enabled` | `false` | Summary webhook. |
|
||||||
|
| `ntfy.enabled` | `false` | Push notifications via NTFY. |
|
||||||
|
| `logging.excludeFunc` | `["SEARCH-CLOSE-TABS", "LOGIN-NO-PROMPT", "FLOW"]` | Buckets skipped locally. |
|
||||||
|
| `logging.webhookExcludeFunc` | same | Buckets skipped in webhook payloads. |
|
||||||
|
| `logging.redactEmails` | `true` | Mask email addresses in logs. |
|
||||||
|
| `diagnostics.enabled` | `true` | Capture screenshots/HTML on failure. |
|
||||||
|
| `diagnostics.maxPerRun` | `2` | Limit capture count per run. |
|
||||||
|
| `diagnostics.retentionDays` | `7` | Auto-clean old diagnostics. |
|
||||||
|
| `analytics.enabled` | `true` | Persist account metrics. |
|
||||||
|
| `analytics.retentionDays` | `30` | Keep analytics data for N days. |
|
||||||
|
| `analytics.exportMarkdown` | `true` | Write markdown summaries to `reports/`. |
|
||||||
|
| `analytics.webhookSummary` | `true` | Send analytics summary via webhook.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Buy Mode & Updates
|
||||||
|
|
||||||
|
| Key | Default | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `buyMode.maxMinutes` | `45` | Session length cap when using `-buy`. |
|
||||||
|
| `update.git` | `true` | Run git updater after completion. |
|
||||||
|
| `update.docker` | `false` | Use Docker updater instead. |
|
||||||
|
| `update.scriptPath` | `setup/update/update.mjs` | Update script path. |
|
||||||
|
| `update.autoUpdateConfig` | `true` | Merge upstream config changes with backups. |
|
||||||
|
| `update.autoUpdateAccounts` | `false` | Skip account template merges unless you opt in.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Recommended Workflow
|
||||||
|
|
||||||
|
1. Start from the default config and copy it if you need a local override.
|
||||||
|
2. Leave `passesPerRun` at `1` so job-state can skip accounts automatically.
|
||||||
|
3. Enable the scheduler only after testing manual runs.
|
||||||
|
4. Document any changes you make (without storing credentials in git).
|
||||||
|
|
||||||
|
Related docs: [`accounts.md`](./accounts.md), [`schedule.md`](./schedule.md), [`proxy.md`](./proxy.md), [`humanization.md`](./humanization.md), [`security.md`](./security.md).
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
# ⚙️ Configuration Guide# ⚙️ Configuration Guide
|
# ⚙️ Configuration Guide# ⚙️ Configuration Guide
|
||||||
|
|
||||||
|
> Looking for the stripped-down key-by-key table? See [`config-reference.md`](./config-reference.md).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Customize script behavior in `src/config.jsonc`**This page documents every field in the configuration file. The default ships as `src/config.jsonc` so you get inline `//` guidance without editor warnings, and the loader still accepts traditional `config.json` files if you prefer plain JSON.
|
**Customize script behavior in `src/config.jsonc`**This page documents every field in the configuration file. The default ships as `src/config.jsonc` so you get inline `//` guidance without editor warnings, and the loader still accepts traditional `config.json` files if you prefer plain JSON.
|
||||||
|
|||||||
@@ -1,148 +1,26 @@
|
|||||||
{
|
{
|
||||||
// ============================================================
|
// Sample accounts configuration. Copy to accounts.jsonc and fill in real values.
|
||||||
// 📧 MICROSOFT ACCOUNTS CONFIGURATION
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
// ⚠️ IMPORTANT SECURITY NOTICE
|
|
||||||
// This file contains sensitive credentials. Never commit the real accounts.jsonc to version control.
|
|
||||||
// The .gitignore is configured to exclude accounts.jsonc but you should verify it's not tracked.
|
|
||||||
|
|
||||||
// 📊 MICROSOFT ACCOUNT LIMITS (Unofficial Guidelines)
|
|
||||||
// - New accounts per IP per day: ~3 (official soft limit)
|
|
||||||
// - Recommended active accounts per household IP: ~5 (to avoid suspicion)
|
|
||||||
// - Creating too many accounts quickly may trigger verification (phone, OTP, captcha)
|
|
||||||
// - Unusual activity can result in temporary blocks or account restrictions
|
|
||||||
|
|
||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
// ============================================================
|
|
||||||
// 👤 ACCOUNT 1
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
// Enable or disable this account (true = active, false = skip)
|
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|
||||||
// Microsoft account email address
|
|
||||||
"email": "email_1@outlook.com",
|
"email": "email_1@outlook.com",
|
||||||
|
|
||||||
// Account password
|
|
||||||
"password": "password_1",
|
"password": "password_1",
|
||||||
|
|
||||||
// Two-Factor Authentication (2FA) TOTP secret (optional but HIGHLY recommended for security)
|
|
||||||
// Steps:
|
|
||||||
// 1. Visit https://account.live.com/proofs/Manage/additional and enable two-step verification.
|
|
||||||
// 2. When the wizard appears, click the blue link "Set up a different authenticator app".
|
|
||||||
// 3. On the next page click "I can't scan the bar code" to reveal the Base32 secret (letters + numbers).
|
|
||||||
// 4. Scan the QR with your authenticator (Google Authenticator recommended) AND copy the secret shown.
|
|
||||||
// 5. Paste the secret here. The same secret can stay in your app and power the bot simultaneously.
|
|
||||||
// Format: Base32 secret key (e.g., "JBSWY3DPEHPK3PXP"). Leave empty "" if 2FA is not enabled.
|
|
||||||
"totp": "",
|
"totp": "",
|
||||||
|
"recoveryEmail": "backup_1@example.com",
|
||||||
// ⚠️ REQUIRED: Recovery email address associated with this Microsoft account
|
|
||||||
// During login, Microsoft shows the first 2 characters and the domain of the recovery email (e.g., "ab***@example.com")
|
|
||||||
// This field is MANDATORY to detect account compromise or bans:
|
|
||||||
// - The script compares what Microsoft displays with this configured recovery email
|
|
||||||
// - If they don't match, it alerts you that the account may be compromised or the recovery email was changed
|
|
||||||
// - This security check helps identify hijacked accounts before they cause issues
|
|
||||||
// Format: Full recovery email address (e.g., "backup@gmail.com")
|
|
||||||
"recoveryEmail": "your_email@domain.com",
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// 🌐 PROXY CONFIGURATION (Optional)
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"proxy": {
|
"proxy": {
|
||||||
// Enable proxy for HTTP requests (axios/API calls)
|
|
||||||
// If false, proxy is only used for browser automation
|
|
||||||
"proxyAxios": true,
|
"proxyAxios": true,
|
||||||
|
|
||||||
// Proxy server URL (protocol optional)
|
|
||||||
// Examples: "proxy.example.com", "http://proxy.example.com", "socks5://proxy.example.com"
|
|
||||||
// Leave empty "" to disable proxy for this account
|
|
||||||
"url": "",
|
"url": "",
|
||||||
|
|
||||||
// Proxy port number
|
|
||||||
"port": 0,
|
"port": 0,
|
||||||
|
|
||||||
// Proxy authentication username (leave empty if no auth required)
|
|
||||||
"username": "",
|
"username": "",
|
||||||
|
|
||||||
// Proxy authentication password (leave empty if no auth required)
|
|
||||||
"password": ""
|
"password": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
// ============================================================
|
|
||||||
// 👤 ACCOUNT 2
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"email": "email_2@outlook.com",
|
"email": "email_2@outlook.com",
|
||||||
"password": "password_2",
|
"password": "password_2",
|
||||||
"totp": "",
|
"totp": "",
|
||||||
"recoveryEmail": "your_email@domain.com",
|
"recoveryRequired": false,
|
||||||
|
|
||||||
"proxy": {
|
|
||||||
"proxyAxios": true,
|
|
||||||
"url": "",
|
|
||||||
"port": 0,
|
|
||||||
"username": "",
|
|
||||||
"password": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
// ============================================================
|
|
||||||
// 👤 ACCOUNT 3
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"enabled": false,
|
|
||||||
"email": "email_3@outlook.com",
|
|
||||||
"password": "password_3",
|
|
||||||
"totp": "",
|
|
||||||
"recoveryEmail": "your_email@domain.com",
|
|
||||||
|
|
||||||
"proxy": {
|
|
||||||
"proxyAxios": true,
|
|
||||||
"url": "",
|
|
||||||
"port": 0,
|
|
||||||
"username": "",
|
|
||||||
"password": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
// ============================================================
|
|
||||||
// 👤 ACCOUNT 4
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"enabled": false,
|
|
||||||
"email": "email_4@outlook.com",
|
|
||||||
"password": "password_4",
|
|
||||||
"totp": "",
|
|
||||||
"recoveryEmail": "your_email@domain.com",
|
|
||||||
|
|
||||||
"proxy": {
|
|
||||||
"proxyAxios": true,
|
|
||||||
"url": "",
|
|
||||||
"port": 0,
|
|
||||||
"username": "",
|
|
||||||
"password": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
// ============================================================
|
|
||||||
// 👤 ACCOUNT 5
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"enabled": false,
|
|
||||||
"email": "email_5@outlook.com",
|
|
||||||
"password": "password_5",
|
|
||||||
"totp": "",
|
|
||||||
"recoveryEmail": "your_email@domain.com",
|
|
||||||
|
|
||||||
"proxy": {
|
"proxy": {
|
||||||
"proxyAxios": true,
|
"proxyAxios": true,
|
||||||
"url": "",
|
"url": "",
|
||||||
|
|||||||
234
src/config.jsonc
234
src/config.jsonc
@@ -1,237 +1,133 @@
|
|||||||
{
|
{
|
||||||
// ============================================================
|
// General
|
||||||
// 🌐 GENERAL CONFIGURATION
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
// Base URL for Microsoft Rewards dashboard (do not change unless necessary)
|
|
||||||
"baseURL": "https://rewards.bing.com",
|
"baseURL": "https://rewards.bing.com",
|
||||||
|
|
||||||
// Directory to store sessions (cookies, browser fingerprints)
|
|
||||||
"sessionPath": "sessions",
|
"sessionPath": "sessions",
|
||||||
|
|
||||||
// Dry-run mode: simulate execution without actually running tasks (useful for testing)
|
|
||||||
"dryRun": false,
|
"dryRun": false,
|
||||||
|
|
||||||
|
// Browser
|
||||||
// ============================================================
|
|
||||||
// 🖥️ BROWSER CONFIGURATION
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"browser": {
|
"browser": {
|
||||||
// false = visible window | true = headless mode (invisible)
|
|
||||||
"headless": false,
|
"headless": false,
|
||||||
// Max timeout for operations (supports: 30000, "30s", "2min")
|
|
||||||
"globalTimeout": "30s"
|
"globalTimeout": "30s"
|
||||||
},
|
},
|
||||||
|
|
||||||
"fingerprinting": {
|
"fingerprinting": {
|
||||||
// Persist browser fingerprints to improve consistency across runs
|
|
||||||
"saveFingerprint": {
|
"saveFingerprint": {
|
||||||
"mobile": true,
|
"mobile": true,
|
||||||
"desktop": true
|
"desktop": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Execution
|
||||||
// ============================================================
|
|
||||||
// ⚙️ EXECUTION & PERFORMANCE
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"execution": {
|
"execution": {
|
||||||
// true = Desktop + Mobile in parallel (faster, more resources)
|
|
||||||
// false = Sequential (slower, fewer resources)
|
|
||||||
"parallel": false,
|
"parallel": false,
|
||||||
// If false, skip execution when 0 points are available
|
|
||||||
"runOnZeroPoints": false,
|
"runOnZeroPoints": false,
|
||||||
// Number of account clusters (processes) to run concurrently
|
|
||||||
"clusters": 1,
|
"clusters": 1,
|
||||||
// How many times to run through all accounts in sequence (1 = process each account once, 2 = twice, etc.)
|
"passesPerRun": 1
|
||||||
// Higher values can catch missed tasks but increase detection risk
|
|
||||||
"passesPerRun": 3
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"schedule": {
|
"schedule": {
|
||||||
// Built-in scheduler (no cron needed in containers)
|
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
// Time format options:
|
|
||||||
// - US style with AM/PM → useAmPm: true and time12 (e.g., "9:00 AM")
|
|
||||||
// - 24-hour style → useAmPm: false and time24 (e.g., "09:00")
|
|
||||||
"useAmPm": false,
|
"useAmPm": false,
|
||||||
"time12": "9:00 AM",
|
"time12": "9:00 AM",
|
||||||
"time24": "09:00",
|
"time24": "09:00",
|
||||||
// IANA timezone (e.g., "Europe/Paris", "America/New_York" check schedule.md)
|
|
||||||
"timeZone": "Europe/Paris",
|
"timeZone": "Europe/Paris",
|
||||||
// If true, run immediately on process start
|
|
||||||
"runImmediatelyOnStart": true
|
"runImmediatelyOnStart": true
|
||||||
},
|
},
|
||||||
|
|
||||||
"jobState": {
|
"jobState": {
|
||||||
// Save state to avoid duplicate work across restarts
|
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
// Custom state directory (empty = defaults to sessionPath/job-state)
|
|
||||||
"dir": ""
|
"dir": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Tasks
|
||||||
// ============================================================
|
|
||||||
// 🎯 TASKS & WORKERS
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"workers": {
|
"workers": {
|
||||||
// Select which tasks the bot should complete on desktop/mobile
|
"doDailySet": true,
|
||||||
"doDailySet": true, // Daily set tasks
|
"doMorePromotions": true,
|
||||||
"doMorePromotions": true, // More promotions section
|
"doPunchCards": true,
|
||||||
"doPunchCards": true, // Punch cards
|
"doDesktopSearch": true,
|
||||||
"doDesktopSearch": true, // Desktop searches
|
"doMobileSearch": true,
|
||||||
"doMobileSearch": true, // Mobile searches
|
"doDailyCheckIn": true,
|
||||||
"doDailyCheckIn": true, // Daily check-in
|
"doReadToEarn": true,
|
||||||
"doReadToEarn": true, // Read to earn
|
|
||||||
// If true, run desktop searches right after Daily Set
|
|
||||||
"bundleDailySetWithSearch": true
|
"bundleDailySetWithSearch": true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Search
|
||||||
// ============================================================
|
|
||||||
// 🔍 SEARCH CONFIGURATION
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"search": {
|
"search": {
|
||||||
// Use locale-specific query sources
|
|
||||||
"useLocalQueries": true,
|
"useLocalQueries": true,
|
||||||
"settings": {
|
"settings": {
|
||||||
// Use region-specific queries (at, fr, us, etc.)
|
|
||||||
"useGeoLocaleQueries": true,
|
"useGeoLocaleQueries": true,
|
||||||
// Randomly scroll search result pages (more natural behavior)
|
|
||||||
"scrollRandomResults": true,
|
"scrollRandomResults": true,
|
||||||
// Occasionally click a result (safe targets only)
|
|
||||||
"clickRandomResults": true,
|
"clickRandomResults": true,
|
||||||
// Number of retries if mobile searches don't progress
|
|
||||||
"retryMobileSearchAmount": 2,
|
"retryMobileSearchAmount": 2,
|
||||||
// Delay between searches
|
|
||||||
"delay": {
|
"delay": {
|
||||||
"min": "3min",
|
"min": "3min",
|
||||||
"max": "5min"
|
"max": "5min"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"queryDiversity": {
|
"queryDiversity": {
|
||||||
// Multi-source query generation: Reddit, News, Wikipedia instead of only Google Trends
|
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
// Available sources: google-trends, reddit, news, wikipedia, local-fallback
|
|
||||||
"sources": ["google-trends", "reddit", "local-fallback"],
|
"sources": ["google-trends", "reddit", "local-fallback"],
|
||||||
// Max queries to fetch per source
|
|
||||||
"maxQueriesPerSource": 10,
|
"maxQueriesPerSource": 10,
|
||||||
// Cache duration in minutes (avoids hammering APIs)
|
|
||||||
"cacheMinutes": 30
|
"cacheMinutes": 30
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Humanization
|
||||||
// ============================================================
|
|
||||||
// 🤖 HUMANIZATION & NATURAL BEHAVIOR
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"humanization": {
|
"humanization": {
|
||||||
// Human Mode: adds subtle micro-gestures & pauses to mimic real users
|
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
// If a ban is detected on any account, stop processing remaining accounts
|
|
||||||
"stopOnBan": true,
|
"stopOnBan": true,
|
||||||
// Immediately send an alert (webhook/NTFY) when a ban is detected
|
|
||||||
"immediateBanAlert": true,
|
"immediateBanAlert": true,
|
||||||
// Extra random pause between actions
|
"actionDelay": {
|
||||||
"actionDelay": {
|
"min": 500,
|
||||||
"min": 500, // 0.5 seconds minimum
|
"max": 2200
|
||||||
"max": 2200 // 2.2 seconds maximum
|
|
||||||
},
|
},
|
||||||
// Probability (0-1) to move mouse slightly between actions
|
|
||||||
"gestureMoveProb": 0.65,
|
"gestureMoveProb": 0.65,
|
||||||
// Probability (0-1) to perform a small scroll
|
|
||||||
"gestureScrollProb": 0.4,
|
"gestureScrollProb": 0.4,
|
||||||
// Optional execution time windows (e.g., ["08:30-11:00", "19:00-22:00"])
|
|
||||||
// If specified, waits until inside a window before starting
|
|
||||||
"allowedWindows": []
|
"allowedWindows": []
|
||||||
},
|
},
|
||||||
|
|
||||||
"vacation": {
|
"vacation": {
|
||||||
// Monthly "vacation" block: skip a random range of days each month
|
|
||||||
// Each month, a random period between minDays and maxDays is selected
|
|
||||||
// and all runs within that date range are skipped (more human-like behavior)
|
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"minDays": 2,
|
"minDays": 2,
|
||||||
"maxDays": 4
|
"maxDays": 4
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Risk & retries
|
||||||
// ============================================================
|
|
||||||
// 🛡️ RISK MANAGEMENT & SECURITY
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"riskManagement": {
|
"riskManagement": {
|
||||||
// Dynamic delay adjustment based on detected risk signals
|
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
// Automatically increase delays when captchas/errors are detected
|
|
||||||
"autoAdjustDelays": true,
|
"autoAdjustDelays": true,
|
||||||
// Stop execution if risk level reaches critical threshold
|
|
||||||
"stopOnCritical": false,
|
"stopOnCritical": false,
|
||||||
// Enable ML-based ban prediction based on patterns
|
|
||||||
"banPrediction": true,
|
"banPrediction": true,
|
||||||
// Risk threshold (0-100). If exceeded, bot pauses or alerts you
|
|
||||||
"riskThreshold": 75
|
"riskThreshold": 75
|
||||||
},
|
},
|
||||||
|
|
||||||
"retryPolicy": {
|
"retryPolicy": {
|
||||||
// Generic retry/backoff for transient failures
|
|
||||||
"maxAttempts": 3,
|
"maxAttempts": 3,
|
||||||
"baseDelay": 1000,
|
"baseDelay": 1000,
|
||||||
"maxDelay": "30s",
|
"maxDelay": "30s",
|
||||||
"multiplier": 2,
|
"multiplier": 2,
|
||||||
"jitter": 0.2
|
"jitter": 0.2
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Networking
|
||||||
// ============================================================
|
|
||||||
// 🌐 PROXY
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"proxy": {
|
"proxy": {
|
||||||
// Control which outbound calls go through your proxy
|
|
||||||
"proxyGoogleTrends": true,
|
"proxyGoogleTrends": true,
|
||||||
"proxyBingTerms": true
|
"proxyBingTerms": true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Notifications
|
||||||
// ============================================================
|
|
||||||
// 🔔 NOTIFICATIONS
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
// Live logs webhook (Discord or similar). URL = your webhook endpoint
|
|
||||||
"webhook": {
|
"webhook": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"url": ""
|
"url": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
// Rich end-of-run summary webhook (Discord or similar)
|
|
||||||
"conclusionWebhook": {
|
"conclusionWebhook": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"url": ""
|
"url": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
// NTFY push notifications (plain text)
|
|
||||||
"ntfy": {
|
"ntfy": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"url": "",
|
"url": "",
|
||||||
"topic": "rewards",
|
"topic": "rewards",
|
||||||
"authToken": ""
|
"authToken": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Logging & diagnostics
|
||||||
// ============================================================
|
|
||||||
// 📊 LOGGING & DIAGNOSTICS
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"logging": {
|
"logging": {
|
||||||
// Logging controls (see docs/config.md)
|
|
||||||
// Filter out noisy log buckets locally and for webhook summaries
|
|
||||||
"excludeFunc": [
|
"excludeFunc": [
|
||||||
"SEARCH-CLOSE-TABS",
|
"SEARCH-CLOSE-TABS",
|
||||||
"LOGIN-NO-PROMPT",
|
"LOGIN-NO-PROMPT",
|
||||||
@@ -242,95 +138,33 @@
|
|||||||
"LOGIN-NO-PROMPT",
|
"LOGIN-NO-PROMPT",
|
||||||
"FLOW"
|
"FLOW"
|
||||||
],
|
],
|
||||||
// Email redaction toggle (true = secure, false = full emails)
|
|
||||||
"redactEmails": true
|
"redactEmails": true
|
||||||
},
|
},
|
||||||
|
|
||||||
"diagnostics": {
|
"diagnostics": {
|
||||||
// Capture minimal evidence on failures (screenshots/HTML)
|
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"saveScreenshot": true,
|
"saveScreenshot": true,
|
||||||
"saveHtml": true,
|
"saveHtml": true,
|
||||||
"maxPerRun": 2,
|
"maxPerRun": 2,
|
||||||
"retentionDays": 7
|
"retentionDays": 7
|
||||||
},
|
},
|
||||||
|
|
||||||
"analytics": {
|
"analytics": {
|
||||||
// 📈 Performance Dashboard: tracks points earned, success rates, execution times
|
|
||||||
// Useful for monitoring your stats over time. Disable if you don't need it.
|
|
||||||
// WHAT IT DOES:
|
|
||||||
// - Collects daily/weekly/monthly statistics
|
|
||||||
// - Calculates success rates for each activity type
|
|
||||||
// - Tracks average execution times
|
|
||||||
// - Generates trend reports
|
|
||||||
// - Can export to Markdown or send via webhook
|
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
// How long to keep analytics data (days)
|
|
||||||
"retentionDays": 30,
|
"retentionDays": 30,
|
||||||
// Generate markdown summary reports
|
|
||||||
"exportMarkdown": true,
|
"exportMarkdown": true,
|
||||||
// Send analytics summary via webhook
|
|
||||||
"webhookSummary": true
|
"webhookSummary": true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Buy mode
|
||||||
// ============================================================
|
|
||||||
// 🛒 BUY MODE
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"buyMode": {
|
"buyMode": {
|
||||||
// Manual purchase/redeem mode. Use CLI -buy to enable
|
|
||||||
// Session duration cap in minutes
|
|
||||||
"maxMinutes": 45
|
"maxMinutes": 45
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Updates
|
||||||
// ============================================================
|
|
||||||
// 🔄 UPDATES
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
"update": {
|
"update": {
|
||||||
// Post-run auto-update settings
|
|
||||||
"git": true,
|
"git": true,
|
||||||
"docker": false,
|
"docker": false,
|
||||||
// Custom updater script path (relative to repo root)
|
|
||||||
"scriptPath": "setup/update/update.mjs",
|
"scriptPath": "setup/update/update.mjs",
|
||||||
|
|
||||||
// ⚠️ SMART UPDATE CONTROL - How It Really Works:
|
|
||||||
//
|
|
||||||
// BACKUP: Your files are ALWAYS backed up to .update-backup/ before any update
|
|
||||||
//
|
|
||||||
// UPDATE PROCESS:
|
|
||||||
// 1. Script checks if remote modified config.jsonc or accounts.json
|
|
||||||
// 2. Runs "git pull --rebase" to merge remote changes
|
|
||||||
// 3. Git intelligently merges:
|
|
||||||
// ✅ NEW FIELDS ADDED (new config options, new account properties)
|
|
||||||
// → Your existing values are PRESERVED, new fields are added alongside
|
|
||||||
// → This is 95% of updates - works perfectly without conflicts
|
|
||||||
//
|
|
||||||
// ⚠️ MAJOR RESTRUCTURING (fields renamed, sections reordered, format changed)
|
|
||||||
// → Git may choose one version over the other
|
|
||||||
// → Risk of losing your custom values in restructured sections
|
|
||||||
//
|
|
||||||
// WHAT THE OPTIONS DO:
|
|
||||||
// - true: ACCEPT git merge result (keeps new features + your settings in most cases)
|
|
||||||
// - false: REJECT remote changes, RESTORE your local file from backup (stay on old version)
|
|
||||||
//
|
|
||||||
// RECOMMENDED: Keep both TRUE
|
|
||||||
// Why? Because we rarely restructure files. Most updates just ADD new optional fields.
|
|
||||||
// Your passwords, emails, and custom settings survive addition-only updates.
|
|
||||||
// Only risk: major file restructuring (rare, usually announced in release notes).
|
|
||||||
//
|
|
||||||
// SAFETY NET: Check .update-backup/ folder after updates to compare if worried.
|
|
||||||
|
|
||||||
// Apply remote updates to config.jsonc via git merge
|
|
||||||
// true = accept new features + intelligent merge (RECOMMENDED for most users)
|
|
||||||
// false = always keep your local version (miss new config options)
|
|
||||||
"autoUpdateConfig": true,
|
"autoUpdateConfig": true,
|
||||||
|
|
||||||
// Apply remote updates to accounts.json via git merge
|
|
||||||
// true = accept new fields (like "region", "totpSecret") while keeping credentials (RECOMMENDED)
|
|
||||||
// false = always keep your local accounts file (safest but may miss new optional fields)
|
|
||||||
"autoUpdateAccounts": false
|
"autoUpdateAccounts": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -643,7 +643,9 @@ export class MicrosoftRewardsBot {
|
|||||||
}
|
}
|
||||||
} catch {/* ignore */}
|
} catch {/* ignore */}
|
||||||
this.currentAccountEmail = account.email
|
this.currentAccountEmail = account.email
|
||||||
this.currentAccountRecoveryEmail = account.recoveryEmail
|
this.currentAccountRecoveryEmail = (typeof account.recoveryEmail === 'string' && account.recoveryEmail.trim() !== '')
|
||||||
|
? account.recoveryEmail.trim()
|
||||||
|
: undefined
|
||||||
const runNumber = (this.accountRunCounts.get(account.email) ?? 0) + 1
|
const runNumber = (this.accountRunCounts.get(account.email) ?? 0) + 1
|
||||||
this.accountRunCounts.set(account.email, runNumber)
|
this.accountRunCounts.set(account.email, runNumber)
|
||||||
log('main', 'MAIN-WORKER', `Started tasks for account ${account.email}`)
|
log('main', 'MAIN-WORKER', `Started tasks for account ${account.email}`)
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ export interface Account {
|
|||||||
password: string;
|
password: string;
|
||||||
/** Optional TOTP secret in Base32 (e.g., from Microsoft Authenticator setup) */
|
/** Optional TOTP secret in Base32 (e.g., from Microsoft Authenticator setup) */
|
||||||
totp?: string;
|
totp?: string;
|
||||||
/** Recovery email used during security challenge verification (mandatory) */
|
/** Recovery email used during security challenge verification */
|
||||||
recoveryEmail: string;
|
recoveryEmail?: string;
|
||||||
|
/** Override to allow skipping recovery email checks for this account */
|
||||||
|
recoveryRequired?: boolean;
|
||||||
proxy: AccountProxy;
|
proxy: AccountProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -294,12 +294,37 @@ export function loadAccounts(): Account[] {
|
|||||||
}
|
}
|
||||||
a.email = String(a.email).trim()
|
a.email = String(a.email).trim()
|
||||||
a.password = String(a.password)
|
a.password = String(a.password)
|
||||||
if (typeof a.recoveryEmail !== 'string') {
|
const recoveryRequired = a.recoveryRequired !== false
|
||||||
throw new Error(`account ${a.email || '<unknown>'} must include a recoveryEmail string`)
|
a.recoveryRequired = recoveryRequired
|
||||||
|
|
||||||
|
if (recoveryRequired) {
|
||||||
|
if (typeof a.recoveryEmail !== 'string') {
|
||||||
|
throw new Error(`account ${a.email || '<unknown>'} must include a recoveryEmail string`)
|
||||||
|
}
|
||||||
|
a.recoveryEmail = String(a.recoveryEmail).trim()
|
||||||
|
if (!a.recoveryEmail || !/@/.test(a.recoveryEmail)) {
|
||||||
|
throw new Error(`account ${a.email} recoveryEmail must be a valid email address`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (typeof a.recoveryEmail === 'string' && a.recoveryEmail.trim() !== '') {
|
||||||
|
const trimmed = a.recoveryEmail.trim()
|
||||||
|
if (!/@/.test(trimmed)) {
|
||||||
|
throw new Error(`account ${a.email} recoveryEmail must be a valid email address`)
|
||||||
|
}
|
||||||
|
a.recoveryEmail = trimmed
|
||||||
|
} else {
|
||||||
|
a.recoveryEmail = undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
a.recoveryEmail = String(a.recoveryEmail).trim()
|
|
||||||
if (!a.recoveryEmail || !/@/.test(a.recoveryEmail)) {
|
if (!a.proxy || typeof a.proxy !== 'object') {
|
||||||
throw new Error(`account ${a.email} recoveryEmail must be a valid email address`)
|
a.proxy = { proxyAxios: true, url: '', port: 0, username: '', password: '' }
|
||||||
|
} else {
|
||||||
|
a.proxy.proxyAxios = a.proxy.proxyAxios !== false
|
||||||
|
a.proxy.url = typeof a.proxy.url === 'string' ? a.proxy.url : ''
|
||||||
|
a.proxy.port = typeof a.proxy.port === 'number' ? a.proxy.port : 0
|
||||||
|
a.proxy.username = typeof a.proxy.username === 'string' ? a.proxy.username : ''
|
||||||
|
a.proxy.password = typeof a.proxy.password === 'string' ? a.proxy.password : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Filter out disabled accounts (enabled: false)
|
// Filter out disabled accounts (enabled: false)
|
||||||
|
|||||||
@@ -91,26 +91,43 @@ export class StartupValidator {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Required: recoveryEmail (NEW - mandatory field)
|
const recoveryRequired = account.recoveryRequired !== false
|
||||||
if (!account.recoveryEmail || typeof account.recoveryEmail !== 'string') {
|
if (recoveryRequired) {
|
||||||
this.addError(
|
if (!account.recoveryEmail || typeof account.recoveryEmail !== 'string') {
|
||||||
'accounts',
|
this.addError(
|
||||||
`${prefix}: Missing required field "recoveryEmail"`,
|
'accounts',
|
||||||
'Add your recovery/backup email address. This is MANDATORY for security checks.\nExample: "recoveryEmail": "backup@gmail.com"',
|
`${prefix}: Missing required field "recoveryEmail"`,
|
||||||
'docs/accounts.md'
|
'Add your recovery/backup email address. This is required for security checks unless you explicitly disable it.\nExample: "recoveryEmail": "backup@gmail.com"',
|
||||||
)
|
'docs/accounts.md'
|
||||||
} else if (!/@/.test(account.recoveryEmail)) {
|
)
|
||||||
this.addError(
|
} else if (!/@/.test(account.recoveryEmail)) {
|
||||||
'accounts',
|
this.addError(
|
||||||
`${prefix}: Recovery email format is invalid`,
|
'accounts',
|
||||||
'Recovery email must be a valid email address (e.g., backup@gmail.com)'
|
`${prefix}: Recovery email format is invalid`,
|
||||||
)
|
'Recovery email must be a valid email address (e.g., backup@gmail.com)'
|
||||||
} else if (account.recoveryEmail.trim() === '') {
|
)
|
||||||
this.addError(
|
} else if (account.recoveryEmail.trim() === '') {
|
||||||
'accounts',
|
this.addError(
|
||||||
`${prefix}: Recovery email cannot be empty`,
|
'accounts',
|
||||||
'Provide the actual recovery email associated with this Microsoft account'
|
`${prefix}: Recovery email cannot be empty`,
|
||||||
)
|
'Provide the actual recovery email associated with this Microsoft account'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!account.recoveryEmail || account.recoveryEmail.trim() === '') {
|
||||||
|
this.addWarning(
|
||||||
|
'accounts',
|
||||||
|
`${prefix}: Recovery email checks disabled`,
|
||||||
|
'The bot will skip recovery-email mismatch detection for this account. Re-enable by removing "recoveryRequired": false.',
|
||||||
|
'docs/accounts.md'
|
||||||
|
)
|
||||||
|
} else if (!/@/.test(account.recoveryEmail)) {
|
||||||
|
this.addError(
|
||||||
|
'accounts',
|
||||||
|
`${prefix}: Recovery email format is invalid`,
|
||||||
|
'Recovery email must be a valid email address (e.g., backup@gmail.com)'
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional but recommended: TOTP
|
// Optional but recommended: TOTP
|
||||||
|
|||||||
Reference in New Issue
Block a user