mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-11 17:56:15 +00:00
feat: Refactor and modularize flow handling for improved maintainability
- Extracted BuyModeHandler, DesktopFlow, MobileFlow, and SummaryReporter into separate modules for better organization and testability. - Enhanced type safety and added interfaces for various return types in Load, Logger, UserAgent, and flow modules. - Implemented comprehensive error handling and logging throughout the new modules. - Added unit tests for DesktopFlow, MobileFlow, and SummaryReporter to ensure functionality and correctness. - Updated existing utility functions to support new flow structures and improve code clarity.
This commit is contained in:
@@ -7,6 +7,10 @@ import { Account } from '../interface/Account'
|
||||
import { Config, ConfigBrowser, ConfigSaveFingerprint, ConfigScheduling } from '../interface/Config'
|
||||
import { Util } from './Utils'
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const utils = new Util()
|
||||
|
||||
let configCache: Config
|
||||
@@ -72,11 +76,10 @@ function stripJsonComments(input: string): string {
|
||||
// Normalize both legacy (flat) and new (nested) config schemas into the flat Config interface
|
||||
function normalizeConfig(raw: unknown): Config {
|
||||
// TYPE SAFETY NOTE: Using `any` here is necessary for backwards compatibility
|
||||
// The config format has evolved from flat structure to nested structure over time
|
||||
// We need to support both formats dynamically without knowing which one we'll receive
|
||||
// Alternative approaches (discriminated unions, multiple interfaces) would require
|
||||
// runtime type checking on every property access, making the code much more complex
|
||||
// The validation happens implicitly through the Config interface return type
|
||||
// JUSTIFIED USE OF `any`: The config format has evolved from flat → nested structure over time
|
||||
// This needs to support BOTH formats for backward compatibility with existing user configs
|
||||
// Runtime validation happens through explicit property checks and the Config interface return type ensures type safety at function boundary
|
||||
// Alternative approaches (discriminated unions, conditional types) would require extensive runtime checks making code significantly more complex
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const n = (raw || {}) as any
|
||||
|
||||
@@ -350,9 +353,9 @@ export function loadAccounts(): Account[] {
|
||||
if (!Array.isArray(parsed)) throw new Error('accounts must be an array')
|
||||
// minimal shape validation
|
||||
for (const entry of parsed) {
|
||||
// TYPE SAFETY NOTE: Using `any` for account validation
|
||||
// Accounts come from user-provided JSON with unknown structure
|
||||
// We validate each property explicitly below rather than trusting the type
|
||||
// JUSTIFIED USE OF `any`: Accounts come from untrusted user JSON with unpredictable structure
|
||||
// We perform explicit runtime validation of each property below (typeof checks, regex validation, etc.)
|
||||
// This is safer than trusting a type assertion to a specific interface
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const a = entry as any
|
||||
if (!a || typeof a.email !== 'string' || typeof a.password !== 'string') {
|
||||
@@ -452,7 +455,12 @@ export function loadConfig(): Config {
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadSessionData(sessionPath: string, email: string, isMobile: boolean, saveFingerprint: ConfigSaveFingerprint) {
|
||||
interface SessionData {
|
||||
cookies: Cookie[]
|
||||
fingerprint?: BrowserFingerprintWithHeaders
|
||||
}
|
||||
|
||||
export async function loadSessionData(sessionPath: string, email: string, isMobile: boolean, saveFingerprint: ConfigSaveFingerprint): Promise<SessionData> {
|
||||
try {
|
||||
// Fetch cookie file
|
||||
const cookieFile = path.join(__dirname, '../browser/', sessionPath, email, `${isMobile ? 'mobile_cookies' : 'desktop_cookies'}.json`)
|
||||
|
||||
@@ -58,7 +58,7 @@ function getBuffer(url: string): WebhookBuffer {
|
||||
return buf
|
||||
}
|
||||
|
||||
async function sendBatch(url: string, buf: WebhookBuffer) {
|
||||
async function sendBatch(url: string, buf: WebhookBuffer): Promise<void> {
|
||||
if (buf.sending) return
|
||||
buf.sending = true
|
||||
while (buf.lines.length > 0) {
|
||||
|
||||
@@ -4,7 +4,25 @@ import { BrowserFingerprintWithHeaders } from 'fingerprint-generator'
|
||||
import { log } from './Logger'
|
||||
import { Retry } from './Retry'
|
||||
|
||||
import { ChromeVersion, EdgeVersion, Architecture, Platform } from '../interface/UserAgentUtil'
|
||||
import { Architecture, ChromeVersion, EdgeVersion, Platform } from '../interface/UserAgentUtil'
|
||||
|
||||
interface UserAgentMetadata {
|
||||
mobile: boolean
|
||||
isMobile: boolean
|
||||
platform: string
|
||||
fullVersionList: Array<{ brand: string; version: string }>
|
||||
brands: Array<{ brand: string; version: string }>
|
||||
platformVersion: string
|
||||
architecture: string
|
||||
bitness: string
|
||||
model: string
|
||||
uaFullVersion: string
|
||||
}
|
||||
|
||||
interface UserAgentResult {
|
||||
userAgent: string
|
||||
userAgentMetadata: UserAgentMetadata
|
||||
}
|
||||
|
||||
const NOT_A_BRAND_VERSION = '99'
|
||||
const EDGE_VERSION_URL = 'https://edgeupdates.microsoft.com/api/products'
|
||||
@@ -24,7 +42,7 @@ type EdgeVersionResult = {
|
||||
let edgeVersionCache: { data: EdgeVersionResult; expiresAt: number } | null = null
|
||||
let edgeVersionInFlight: Promise<EdgeVersionResult> | null = null
|
||||
|
||||
export async function getUserAgent(isMobile: boolean) {
|
||||
export async function getUserAgent(isMobile: boolean): Promise<UserAgentResult> {
|
||||
const system = getSystemComponents(isMobile)
|
||||
const app = await getAppComponents(isMobile)
|
||||
|
||||
@@ -133,7 +151,17 @@ export function getSystemComponents(mobile: boolean): string {
|
||||
return 'Windows NT 10.0; Win64; x64'
|
||||
}
|
||||
|
||||
export async function getAppComponents(isMobile: boolean) {
|
||||
interface AppComponents {
|
||||
not_a_brand_version: string
|
||||
not_a_brand_major_version: string
|
||||
edge_version: string
|
||||
edge_major_version: string
|
||||
chrome_version: string
|
||||
chrome_major_version: string
|
||||
chrome_reduced_version: string
|
||||
}
|
||||
|
||||
export async function getAppComponents(isMobile: boolean): Promise<AppComponents> {
|
||||
const versions = await getEdgeVersions(isMobile)
|
||||
const edgeVersion = isMobile ? versions.android : versions.windows as string
|
||||
const edgeMajorVersion = edgeVersion?.split('.')[0]
|
||||
|
||||
Reference in New Issue
Block a user