mirror of
https://github.com/TheNetsky/Microsoft-Rewards-Script.git
synced 2026-01-11 10:56:17 +00:00
269 lines
7.6 KiB
JavaScript
269 lines
7.6 KiB
JavaScript
import fs from 'fs'
|
|
import path from 'path'
|
|
import { fileURLToPath } from 'url'
|
|
|
|
export function getDirname(importMetaUrl) {
|
|
const __filename = fileURLToPath(importMetaUrl)
|
|
return path.dirname(__filename)
|
|
}
|
|
|
|
export function getProjectRoot(currentDir) {
|
|
let dir = currentDir
|
|
while (dir !== path.parse(dir).root) {
|
|
if (fs.existsSync(path.join(dir, 'package.json'))) {
|
|
return dir
|
|
}
|
|
dir = path.dirname(dir)
|
|
}
|
|
throw new Error('Could not find project root (package.json not found)')
|
|
}
|
|
|
|
export function log(level, ...args) {
|
|
console.log(`[${level}]`, ...args)
|
|
}
|
|
|
|
export function parseArgs(argv = process.argv.slice(2)) {
|
|
const args = {}
|
|
|
|
for (let i = 0; i < argv.length; i++) {
|
|
const arg = argv[i]
|
|
|
|
if (arg.startsWith('-')) {
|
|
const key = arg.substring(1)
|
|
|
|
if (i + 1 < argv.length && !argv[i + 1].startsWith('-')) {
|
|
args[key] = argv[i + 1]
|
|
i++
|
|
} else {
|
|
args[key] = true
|
|
}
|
|
}
|
|
}
|
|
|
|
return args
|
|
}
|
|
|
|
export function validateEmail(email) {
|
|
if (!email) {
|
|
log('ERROR', 'Missing -email argument')
|
|
log('ERROR', 'Usage: node script.js -email you@example.com')
|
|
process.exit(1)
|
|
}
|
|
|
|
if (typeof email !== 'string') {
|
|
log('ERROR', `Invalid email type: expected string, got ${typeof email}`)
|
|
log('ERROR', 'Usage: node script.js -email you@example.com')
|
|
process.exit(1)
|
|
}
|
|
|
|
if (!email.includes('@')) {
|
|
log('ERROR', `Invalid email format: "${email}"`)
|
|
log('ERROR', 'Email must contain "@" symbol')
|
|
log('ERROR', 'Example: you@example.com')
|
|
process.exit(1)
|
|
}
|
|
|
|
return email
|
|
}
|
|
|
|
export function loadJsonFile(possiblePaths, required = true) {
|
|
for (const filePath of possiblePaths) {
|
|
if (fs.existsSync(filePath)) {
|
|
try {
|
|
const content = fs.readFileSync(filePath, 'utf8')
|
|
return { data: JSON.parse(content), path: filePath }
|
|
} catch (error) {
|
|
log('ERROR', `Failed to parse JSON file: ${filePath}`)
|
|
log('ERROR', `Parse error: ${error.message}`)
|
|
if (required) process.exit(1)
|
|
return null
|
|
}
|
|
}
|
|
}
|
|
|
|
if (required) {
|
|
log('ERROR', 'Required file not found')
|
|
log('ERROR', 'Searched in the following locations:')
|
|
possiblePaths.forEach(p => log('ERROR', ` - ${p}`))
|
|
process.exit(1)
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
export function loadConfig(projectRoot, isDev = false) {
|
|
const possiblePaths = isDev
|
|
? [path.join(projectRoot, 'src', 'config.json')]
|
|
: [
|
|
path.join(projectRoot, 'dist', 'config.json'),
|
|
path.join(projectRoot, 'config.json')
|
|
]
|
|
|
|
const result = loadJsonFile(possiblePaths, true)
|
|
|
|
const missingFields = []
|
|
if (!result.data.baseURL) missingFields.push('baseURL')
|
|
if (!result.data.sessionPath) missingFields.push('sessionPath')
|
|
if (result.data.headless === undefined) missingFields.push('headless')
|
|
if (!result.data.workers) missingFields.push('workers')
|
|
|
|
if (missingFields.length > 0) {
|
|
log('ERROR', 'Invalid config.json - missing required fields:')
|
|
missingFields.forEach(field => log('ERROR', ` - ${field}`))
|
|
log('ERROR', `Config file: ${result.path}`)
|
|
process.exit(1)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
export function loadAccounts(projectRoot, isDev = false) {
|
|
const possiblePaths = isDev
|
|
? [path.join(projectRoot, 'src', 'accounts.dev.json')]
|
|
: [
|
|
path.join(projectRoot, 'dist', 'accounts.json'),
|
|
path.join(projectRoot, 'accounts.json'),
|
|
path.join(projectRoot, 'accounts.example.json')
|
|
]
|
|
|
|
return loadJsonFile(possiblePaths, true)
|
|
}
|
|
|
|
export function findAccountByEmail(accounts, email) {
|
|
if (!email || typeof email !== 'string') return null
|
|
return accounts.find(a => a?.email && typeof a.email === 'string' && a.email.toLowerCase() === email.toLowerCase()) || null
|
|
}
|
|
|
|
export function getRuntimeBase(projectRoot, isDev = false) {
|
|
return path.join(projectRoot, isDev ? 'src' : 'dist')
|
|
}
|
|
|
|
export function getSessionPath(runtimeBase, sessionPath, email) {
|
|
return path.join(runtimeBase, 'browser', sessionPath, email)
|
|
}
|
|
|
|
export async function loadCookies(sessionBase, type = 'desktop') {
|
|
const cookiesFile = path.join(sessionBase, `session_${type}.json`)
|
|
|
|
if (!fs.existsSync(cookiesFile)) {
|
|
return []
|
|
}
|
|
|
|
try {
|
|
const content = await fs.promises.readFile(cookiesFile, 'utf8')
|
|
return JSON.parse(content)
|
|
} catch (error) {
|
|
log('WARN', `Failed to load cookies from: ${cookiesFile}`)
|
|
log('WARN', `Error: ${error.message}`)
|
|
return []
|
|
}
|
|
}
|
|
|
|
export async function loadFingerprint(sessionBase, type = 'desktop') {
|
|
const fpFile = path.join(sessionBase, `session_fingerprint_${type}.json`)
|
|
|
|
if (!fs.existsSync(fpFile)) {
|
|
return null
|
|
}
|
|
|
|
try {
|
|
const content = await fs.promises.readFile(fpFile, 'utf8')
|
|
return JSON.parse(content)
|
|
} catch (error) {
|
|
log('WARN', `Failed to load fingerprint from: ${fpFile}`)
|
|
log('WARN', `Error: ${error.message}`)
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function getUserAgent(fingerprint) {
|
|
if (!fingerprint) return null
|
|
return fingerprint?.fingerprint?.userAgent || fingerprint?.userAgent || null
|
|
}
|
|
|
|
export function buildProxyConfig(account) {
|
|
if (!account.proxy || !account.proxy.url || !account.proxy.port) {
|
|
return null
|
|
}
|
|
|
|
const proxy = {
|
|
server: `${account.proxy.url}:${account.proxy.port}`
|
|
}
|
|
|
|
if (account.proxy.username && account.proxy.password) {
|
|
proxy.username = account.proxy.username
|
|
proxy.password = account.proxy.password
|
|
}
|
|
|
|
return proxy
|
|
}
|
|
|
|
export function setupCleanupHandlers(cleanupFn) {
|
|
const cleanup = async () => {
|
|
try {
|
|
await cleanupFn()
|
|
} catch (error) {
|
|
log('ERROR', 'Cleanup failed:', error.message)
|
|
}
|
|
process.exit(0)
|
|
}
|
|
|
|
process.on('SIGINT', cleanup)
|
|
process.on('SIGTERM', cleanup)
|
|
}
|
|
|
|
export function validateDeletionPath(targetPath, projectRoot) {
|
|
const normalizedTarget = path.normalize(targetPath)
|
|
const normalizedRoot = path.normalize(projectRoot)
|
|
|
|
if (!normalizedTarget.startsWith(normalizedRoot)) {
|
|
return {
|
|
valid: false,
|
|
error: 'Path is outside project root'
|
|
}
|
|
}
|
|
|
|
if (normalizedTarget === normalizedRoot) {
|
|
return {
|
|
valid: false,
|
|
error: 'Cannot delete project root'
|
|
}
|
|
}
|
|
|
|
const pathSegments = normalizedTarget.split(path.sep)
|
|
if (pathSegments.length < 3) {
|
|
return {
|
|
valid: false,
|
|
error: 'Path is too shallow (safety check failed)'
|
|
}
|
|
}
|
|
|
|
return { valid: true, error: null }
|
|
}
|
|
|
|
export function safeRemoveDirectory(dirPath, projectRoot) {
|
|
const validation = validateDeletionPath(dirPath, projectRoot)
|
|
|
|
if (!validation.valid) {
|
|
log('ERROR', 'Directory deletion failed - safety check:')
|
|
log('ERROR', ` Reason: ${validation.error}`)
|
|
log('ERROR', ` Target: ${dirPath}`)
|
|
log('ERROR', ` Project root: ${projectRoot}`)
|
|
return false
|
|
}
|
|
|
|
if (!fs.existsSync(dirPath)) {
|
|
log('INFO', `Directory does not exist: ${dirPath}`)
|
|
return true
|
|
}
|
|
|
|
try {
|
|
fs.rmSync(dirPath, { recursive: true, force: true })
|
|
log('SUCCESS', `Directory removed: ${dirPath}`)
|
|
return true
|
|
} catch (error) {
|
|
log('ERROR', `Failed to remove directory: ${dirPath}`)
|
|
log('ERROR', `Error: ${error.message}`)
|
|
return false
|
|
}
|
|
} |