Refactor: Simplify recovery email handling and validation; update documentation for clarity

This commit is contained in:
2025-11-08 21:26:06 +01:00
parent 5e322af2c0
commit 773304fc85
7 changed files with 28 additions and 67 deletions

View File

@@ -21,7 +21,7 @@
}
```
> `recoveryEmail` is still **recommended**. It lets the bot verify Microsofts masked hint during login and alert you if the recovery address ever changes. You can opt out per account by setting `"recoveryRequired": false`.
> `recoveryEmail` is **optional but recommended**. It lets the bot verify Microsoft's masked hint during login and alert you if the recovery address ever changes. Simply leave it empty (`""`) if not needed.
**That's it!** Run `npm start` to test.
@@ -60,9 +60,9 @@
---
## 🚫 Skip the Recovery Email Check (Advanced)
## 🚫 Skip the Recovery Email (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.
If an account genuinely has no recovery address or you prefer not to provide it, simply leave the `recoveryEmail` field empty:
```json
{
@@ -70,13 +70,13 @@ Most users should keep recovery validation enabled. If an account genuinely has
{
"email": "example@outlook.com",
"password": "strong_password",
"recoveryRequired": false
"recoveryEmail": ""
}
]
}
```
> Without a recovery email the bot cannot detect if Microsoft shows a different masked address. Enable this override only when you accept that risk.
> The bot will automatically skip recovery validation when this field is empty. A warning will be logged during startup, but the bot will function normally.
---

View File

@@ -7,9 +7,8 @@
"enabled": true,
"email": "",
"password": "",
"totp": "",
"recoveryRequired": true,
"recoveryEmail": "",
"totp": "", // Optional: leave empty if no 2FA, or put your TOTP secret
"recoveryEmail": "", // Optional: recovery email for security challenges
"proxy": {
"proxyAxios": false,
"url": "",
@@ -24,7 +23,6 @@
"email": "",
"password": "",
"totp": "",
"recoveryRequired": true,
"recoveryEmail": "",
"proxy": {
"proxyAxios": false,
@@ -40,7 +38,6 @@
"email": "",
"password": "",
"totp": "",
"recoveryRequired": true,
"recoveryEmail": "",
"proxy": {
"proxyAxios": false,
@@ -56,7 +53,6 @@
"email": "",
"password": "",
"totp": "",
"recoveryRequired": true,
"recoveryEmail": "",
"proxy": {
"proxyAxios": false,
@@ -72,7 +68,6 @@
"email": "",
"password": "",
"totp": "",
"recoveryRequired": true,
"recoveryEmail": "",
"proxy": {
"proxyAxios": false,

View File

@@ -162,11 +162,7 @@ class Browser {
}
async generateFingerprint() {
const fingerPrintData = new FingerprintGenerator().getFingerprint({
devices: this.bot.isMobile ? ['mobile'] : ['desktop'],
operatingSystems: this.bot.isMobile ? ['android'] : ['windows'],
browsers: [{ name: 'edge' }]
})
const fingerPrintData = new FingerprintGenerator().getFingerprint()
const updatedFingerPrintData = await updateFingerprintUserAgent(fingerPrintData, this.bot.isMobile)

View File

@@ -145,7 +145,7 @@
// Updates
"update": {
"enabled": true, // Enable automatic updates (default: true)
"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)

View File

@@ -5,10 +5,8 @@ export interface Account {
password: string;
/** Optional TOTP secret in Base32 (e.g., from Microsoft Authenticator setup) */
totp?: string;
/** Recovery email used during security challenge verification */
/** Recovery email used during security challenge verification. Leave empty if not needed. */
recoveryEmail?: string;
/** Override to allow skipping recovery email checks for this account */
recoveryRequired?: boolean;
proxy: AccountProxy;
}

View File

@@ -379,27 +379,20 @@ export function loadAccounts(): Account[] {
}
a.email = String(a.email).trim()
a.password = String(a.password)
const recoveryRequired = a.recoveryRequired !== false
a.recoveryRequired = recoveryRequired
if (recoveryRequired) {
if (typeof a.recoveryEmail !== 'string') {
throw new Error(`account ${a.email || '<unknown>'} must include a recoveryEmail string (or set "recoveryRequired": false)`)
}
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 (got: "${a.recoveryEmail}") - set "recoveryRequired": false if not needed`)
}
} else {
if (typeof a.recoveryEmail === 'string' && a.recoveryEmail.trim() !== '') {
const trimmed = a.recoveryEmail.trim()
// Simplified recovery email logic: if present and non-empty, validate it
if (typeof a.recoveryEmail === 'string') {
const trimmed = a.recoveryEmail.trim()
if (trimmed !== '') {
if (!/@/.test(trimmed)) {
throw new Error(`account ${a.email} recoveryEmail must be a valid email address`)
throw new Error(`account ${a.email} recoveryEmail must be a valid email address (got: "${trimmed}")`)
}
a.recoveryEmail = trimmed
} else {
a.recoveryEmail = undefined
}
} else {
a.recoveryEmail = undefined
}
if (!a.proxy || typeof a.proxy !== 'object') {

View File

@@ -1,8 +1,8 @@
import chalk from 'chalk'
import fs from 'fs'
import path from 'path'
import chalk from 'chalk'
import { Config } from '../interface/Config'
import { Account } from '../interface/Account'
import { Config } from '../interface/Config'
import { log } from './Logger'
interface ValidationError {
@@ -105,43 +105,22 @@ export class StartupValidator {
)
}
const recoveryRequired = account.recoveryRequired !== false
if (recoveryRequired) {
if (!account.recoveryEmail || typeof account.recoveryEmail !== 'string') {
this.addError(
'accounts',
`${prefix}: Missing required field "recoveryEmail"`,
'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)) {
// Simplified: only validate recovery email if provided
if (account.recoveryEmail && typeof account.recoveryEmail === 'string' && account.recoveryEmail.trim() !== '') {
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)'
)
} else if (account.recoveryEmail.trim() === '') {
this.addError(
'accounts',
`${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)'
)
}
this.addWarning(
'accounts',
`${prefix}: No recovery email configured`,
'Recovery email is optional but recommended for security challenge verification',
'docs/accounts.md'
)
}
// Optional but recommended: TOTP