From 620a3de21caa984fee23e20aef02f33f36e13704 Mon Sep 17 00:00:00 2001 From: adrapier03 Date: Sun, 5 Jul 2026 19:49:37 +0700 Subject: [PATCH] domain setup --- README.md | 24 ++++--- chain-loop-config.js | 25 ++++++- chain-loop.js | 11 ++- config.json | 5 +- fingerprint.js | 16 ++--- index.js | 105 ++++++++++++++++++++++++--- regis-loop.js | 164 ++++++++++++++++++++++++++++++++++++++++--- regis-result.txt | 5 ++ 8 files changed, 313 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index b34cefd..5e3f3ae 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,8 @@ Edit `config.json`: ```json { "tempmail": { - "apiUrl": "https://tempmail.adrnode.com/api" + "apiUrl": "https://tempmail.adrnode.com/api", + "domain": "shitoors.fun" }, "captcha": { "provider": "2captcha", @@ -44,6 +45,7 @@ Yang **wajib** diisi: - `xiaomi.referralLink` — URL referral, format `?ref=XXXXXX` (sama dengan inviteCode) Yang opsional: +- `tempmail.domain` — domain kustom untuk pendaftaran email (misal: `"shitoors.fun"`) - `xiaomi.password` — password untuk semua akun baru (default OK) - `browser.headless` — `true` tanpa UI, `false` (default) buat lihat browser @@ -61,6 +63,7 @@ node chain-loop.js --count 5 | `--count N` | 1 | jumlah akun yang dibuat | | `--seed XXXXXX` | `config.xiaomi.inviteCode` | invite code untuk akun pertama | | `--output file.txt` | `chain-result.txt` | file output | +| `--proxy [arg]` | - | Menentukan proxy. Jika diisi string url (`http://user:pass@host:port`), akan memakai proxy tersebut. Jika bendera `--proxy` ditulis tanpa nilai (atau `--proxy proxy.txt`), program akan otomatis memuat list proxy dari file `proxy.txt` di workspace dan merotasinya per iterasi. | ```bash # 5 akun, seed dari config @@ -84,6 +87,7 @@ node regis-loop.js --count 5 |---|---|---| | `--count N` | 1 | jumlah akun yang dibuat | | `--output file.txt` | `regis-result.txt` | file output (format: email:password:refCode:apiKey) | +| `--proxy [arg]` | - | Sama seperti di `chain-loop.js`. Berguna untuk merotasi proxy per iterasi agar setiap akun terdaftar menggunakan IP berbeda. | ```bash # Membuat 5 akun baru secara bergantian tanpa referral link / redeem code sama sekali @@ -94,18 +98,18 @@ node regis-loop.js --count 5 ## Per-akun flow ``` -[1] Bikin temp email -[2] Launch browser dengan random fingerprint (UA, viewport, locale, GPU, dst) +[1] Bikin temp email (menggunakan domain kustom jika diatur) +[2] Launch browser dengan random fingerprint (dan proxy yang dirotasi jika diaktifkan) [3] Buka referral link (?ref=) [4] Sign up form (email + password + confirm + terms checkbox) [5] Solve captcha (reCAPTCHA via 2Captcha + image captcha) [6] Verify email (kode 6 digit dari tempmail) -[7] Klik Console → Balance → "Enter invite code" → isi 6-box → Redeem - → cek restriction (kalau kena, STOP) - → reload halaman, verify balance bertambah ~$2 +[7] Pengecekan Balance & Terms: + - **Regis Loop**: Klik Console → Balance → deteksi & setujui Terms modal → cek balance (baca saldo). + - **Chain Loop**: Klik Console → Balance → deteksi & setujui Terms modal → "Enter invite code" → isi 6-box → Redeem → cek restriction (kalau kena, STOP) → reload halaman → verify balance bertambah ~$2. [8] Create API key (atau ambil existing kalau sudah ada) [9] Fill Ultraspeed beta application form -[10] Klik "Refer & earn" → ambil ref code akun ini → seed untuk akun berikut +[10] Klik "Refer & earn" → ambil ref code akun ini ``` ## Output @@ -136,9 +140,13 @@ akan di-skip otomatis, aman untuk re-run. **Verifikasi balance** — Setelah redeem invite code, halaman di-reload dan balance dibaca ulang. Harus bertambah ~$2.00. Kalau tidak, iterasi dianggap gagal. -**Restriction detection** — Kalau setelah redeem muncul notif "risk control restrictions", +**Restriction detection** — Kalau setelah redeem atau saat membuka halaman balance muncul notif "risk control restrictions", loop berhenti total (akun kena cap, gak bisa lanjut). +**Proxy Auto-Rotation & Sanitized Logs** — Mendukung rotasi proxy otomatis per iterasi dengan membaca file `proxy.txt`. Username/password autentikasi disembunyikan dari logs untuk menjaga kerahasiaan. + +**Custom Email Domain** — Mendukung domain email kustom via properti `tempmail.domain` di `config.json`. + ## Stop conditions Loop berhenti kalau: diff --git a/chain-loop-config.js b/chain-loop-config.js index 0c857ab..7c3ae68 100644 --- a/chain-loop-config.js +++ b/chain-loop-config.js @@ -18,7 +18,7 @@ import { readFileSync, appendFileSync, existsSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; -import { MimoRegistration } from './index.js'; +import { MimoRegistration, loadProxyList } from './index.js'; import './extras.js'; // attach getReferralCode import { generateFingerprint, buildInitScript, buildExtraHeaders } from './fingerprint.js'; @@ -50,6 +50,27 @@ const outputFile = outputIdx !== -1 const failLog = join(outputDir, 'chain-fail.log'); +const proxyIdx = args.indexOf('--proxy'); +let proxyList = []; +if (proxyIdx !== -1) { + const nextArg = args[proxyIdx + 1]; + let proxyPath = 'proxy.txt'; + if (nextArg && !nextArg.startsWith('-')) { + proxyPath = nextArg; + } + const resolvedPath = join(__dirname, proxyPath); + if (existsSync(resolvedPath)) { + proxyList = loadProxyList(resolvedPath); + console.log(`Loaded ${proxyList.length} proxies from ${proxyPath}`); + } else if (nextArg && !nextArg.startsWith('-')) { + proxyList = [nextArg]; + } else { + console.log(`Proxy option enabled but ${proxyPath} not found.`); + } +} else if (config.proxy) { + proxyList = [config.proxy]; +} + // ---- File helpers ----------------------------------------------------- function saveResult(row) { @@ -75,4 +96,4 @@ function logFail(email, error) { appendFileSync(failLog, line, 'utf8'); } -export { config, saveResult, logFail, count, seedRef, outputFile, failLog, __dirname }; +export { config, saveResult, logFail, count, seedRef, outputFile, failLog, __dirname, proxyList }; diff --git a/chain-loop.js b/chain-loop.js index 313bf6c..75b4501 100644 --- a/chain-loop.js +++ b/chain-loop.js @@ -17,12 +17,12 @@ import { chromium } from 'playwright'; import { join } from 'path'; -import { MimoRegistration } from './index.js'; +import { MimoRegistration, parseProxy } from './index.js'; import './extras.js'; // attach getReferralCode import { generateFingerprint, buildInitScript, buildExtraHeaders } from './fingerprint.js'; import { - config, saveResult, logFail, count, seedRef, outputFile, failLog, __dirname, + config, saveResult, logFail, count, seedRef, outputFile, failLog, __dirname, proxyList, } from './chain-loop-config.js'; // ---- One-iteration runner -------------------------------------------- @@ -34,6 +34,12 @@ async function runIteration(idx, total, currentRef) { // Per-iter: clone config + override invite code & referral link const iterConfig = JSON.parse(JSON.stringify(config)); + if (proxyList && proxyList.length > 0) { + const selectedProxy = proxyList[idx % proxyList.length]; + iterConfig.proxy = selectedProxy; + const cleanProxyName = selectedProxy.split('@').pop(); + console.log(` ↳ Using proxy [${(idx % proxyList.length) + 1}/${proxyList.length}]: ${cleanProxyName}`); + } iterConfig.xiaomi.inviteCode = currentRef; iterConfig.xiaomi.referralLink = `https://platform.xiaomimimo.com/?ref=${encodeURIComponent(currentRef)}`; @@ -67,6 +73,7 @@ async function runIteration(idx, total, currentRef) { reg.browser = await chromium.launch({ headless: iterConfig.browser.headless, channel: 'chrome', + proxy: parseProxy(iterConfig.proxy), args: [ `--window-size=${fp.viewport.width},${fp.viewport.height}`, '--disable-blink-features=AutomationControlled', diff --git a/config.json b/config.json index 379962d..3bcf0fc 100644 --- a/config.json +++ b/config.json @@ -1,10 +1,11 @@ { "tempmail": { - "apiUrl": "https://tempmail.adrnode.com/api" + "apiUrl": "https://tempmail.adrnode.com/api", + "domain": "foxsight.xyz" }, "captcha": { "provider": "2captcha", - "apiKey": "YOUR_2CAPTCHA_API_KEY" + "apiKey": "82d7c3c7dfca21006510df3c6993b807" }, "xiaomi": { "referralLink": "https://platform.xiaomimimo.com/?ref=XXXXXX", diff --git a/fingerprint.js b/fingerprint.js index 4a54603..d533552 100644 --- a/fingerprint.js +++ b/fingerprint.js @@ -34,10 +34,10 @@ const VIEWPORTS = [ { width: 1280, height: 800 }, ]; -const LOCALES = ['en-US', 'en-GB', 'id-ID', 'en-AU', 'en-CA', 'en-SG']; +const LOCALES = ['en-US', 'en-GB', 'en-AU', 'en-CA', 'en-SG']; const TIMEZONES = [ - 'Asia/Jakarta', 'Asia/Singapore', 'Asia/Bangkok', + 'Asia/Singapore', 'Asia/Bangkok', 'Asia/Kuala_Lumpur', 'Asia/Manila', 'Asia/Ho_Chi_Minh', ]; @@ -52,11 +52,11 @@ const WEBGL_RENDERERS = [ { vendor: 'Google Inc. (NVIDIA)', renderer: 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)' }, { vendor: 'Google Inc. (NVIDIA)', renderer: 'ANGLE (NVIDIA, NVIDIA GeForce RTX 4060 Ti Direct3D11 vs_5_0 ps_5_0, D3D11)' }, { vendor: 'Google Inc. (NVIDIA)', renderer: 'ANGLE (NVIDIA, NVIDIA GeForce GTX 1050 Ti Direct3D11 vs_5_0 ps_5_0, D3D11)' }, - { vendor: 'Google Inc. (Intel)', renderer: 'ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0, D3D11)' }, - { vendor: 'Google Inc. (Intel)', renderer: 'ANGLE (Intel, Intel(R) Iris(R) Xe Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)' }, - { vendor: 'Google Inc. (Intel)', renderer: 'ANGLE (Intel, Intel(R) HD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)' }, - { vendor: 'Google Inc. (AMD)', renderer: 'ANGLE (AMD, AMD Radeon RX 6600 XT Direct3D11 vs_5_0 ps_5_0, D3D11)' }, - { vendor: 'Google Inc. (AMD)', renderer: 'ANGLE (AMD, AMD Radeon Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)' }, + { vendor: 'Google Inc. (Intel)', renderer: 'ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0, D3D11)' }, + { vendor: 'Google Inc. (Intel)', renderer: 'ANGLE (Intel, Intel(R) Iris(R) Xe Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)' }, + { vendor: 'Google Inc. (Intel)', renderer: 'ANGLE (Intel, Intel(R) HD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)' }, + { vendor: 'Google Inc. (AMD)', renderer: 'ANGLE (AMD, AMD Radeon RX 6600 XT Direct3D11 vs_5_0 ps_5_0, D3D11)' }, + { vendor: 'Google Inc. (AMD)', renderer: 'ANGLE (AMD, AMD Radeon Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)' }, ]; // ---- Helpers ------------------------------------------------------------ @@ -249,7 +249,7 @@ export function buildInitScript(fp) { // CLI test: `node fingerprint.js` — print 3 contoh fingerprint if (import.meta.url === `file:///${process.argv[1].replace(/\\/g, '/')}` || - (process.argv[1] && process.argv[1].endsWith('fingerprint.js'))) { + (process.argv[1] && process.argv[1].endsWith('fingerprint.js'))) { for (let i = 0; i < 3; i++) { const fp = generateFingerprint(); console.log(`\n--- Sample ${i + 1} ---`); diff --git a/index.js b/index.js index 88af09a..1bf4d36 100644 --- a/index.js +++ b/index.js @@ -23,8 +23,9 @@ const config = JSON.parse(readFileSync(join(__dirname, 'config.json'), 'utf8')); // ============================================================================ class TempmailClient { - constructor(apiUrl) { + constructor(apiUrl, domain) { this.apiUrl = apiUrl; + this.domain = domain; this.sessionId = null; } @@ -48,13 +49,19 @@ class TempmailClient { async createInbox() { await this.initSession(); - const response = await fetch(`${this.apiUrl}/inboxes`, { + const headers = { + 'Content-Type': 'application/json', + 'x-session-id': this.sessionId + }; + const options = { method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-session-id': this.sessionId - } - }); + headers + }; + if (this.domain) { + options.body = JSON.stringify({ domain: this.domain }); + } + + const response = await fetch(`${this.apiUrl}/inboxes`, options); if (!response.ok) { throw new Error(`Tempmail API error: ${response.status}`); @@ -219,7 +226,7 @@ class CaptchaSolver { class MimoRegistration { constructor(config) { this.config = config; - this.tempmail = new TempmailClient(config.tempmail.apiUrl); + this.tempmail = new TempmailClient(config.tempmail.apiUrl, config.tempmail.domain); this.captcha = new CaptchaSolver(config.captcha.apiKey); this.browser = null; this.page = null; @@ -249,9 +256,15 @@ class MimoRegistration { console.log(` ↳ CPU/Mem : ${fp.hardwareConcurrency} cores / ${fp.deviceMemory} GB`); console.log(` ↳ GPU : ${fp.webgl.renderer.substring(0, 70)}…`); + const proxyConfig = parseProxy(config.proxy); + if (proxyConfig) { + console.log(` ↳ Proxy : ${proxyConfig.server}`); + } + this.browser = await chromium.launch({ headless: config.browser.headless, channel: 'chrome', + proxy: proxyConfig, args: [ // Hindari flag --headless yg kelihatan, dan window-size konsisten dgn viewport `--window-size=${fp.viewport.width},${fp.viewport.height}`, @@ -2007,6 +2020,33 @@ async function main() { } else if (config.registration && config.registration.count) { count = parseInt(config.registration.count, 10) || 1; } + + const proxyArgIndex = process.argv.indexOf('--proxy'); + let proxyList = []; + if (proxyArgIndex !== -1) { + const nextArg = process.argv[proxyArgIndex + 1]; + // if nextArg is another flag or empty, assume default proxy.txt + let proxyPath = 'proxy.txt'; + if (nextArg && !nextArg.startsWith('-')) { + proxyPath = nextArg; + } + + // Check if the parameter is a file path that exists, or default proxy.txt exists + const { existsSync } = await import('fs'); + const resolvedPath = join(__dirname, proxyPath); + if (existsSync(resolvedPath)) { + proxyList = loadProxyList(resolvedPath); + console.log(`Loaded ${proxyList.length} proxies from ${proxyPath}`); + } else if (nextArg && !nextArg.startsWith('-')) { + // Direct proxy string instead of file + proxyList = [nextArg]; + } else { + // Default file doesn't exist either + console.log(`Proxy option enabled but ${proxyPath} not found.`); + } + } else if (config.proxy) { + proxyList = [config.proxy]; + } console.log(`Starting loop to create ${count} account(s)...`); @@ -2018,7 +2058,12 @@ async function main() { console.log(` [Loop ${i + 1}/${count}] Starting Auto-Registration`); console.log('='.repeat(70)); - const registration = new MimoRegistration(config); + const iterConfig = JSON.parse(JSON.stringify(config)); + if (proxyList.length > 0) { + iterConfig.proxy = proxyList[i % proxyList.length]; + } + + const registration = new MimoRegistration(iterConfig); try { const result = await registration.run(); @@ -2082,4 +2127,44 @@ if (import.meta.url === `file:///${process.argv[1].replace(/\\/g, '/')}` || main(); } -export { MimoRegistration, TempmailClient, CaptchaSolver }; +function loadProxyList(filePath) { + try { + const { readFileSync } = require('fs'); // or use fs import + } catch (e) {} + // Since we already import readFileSync from 'fs' at the top of this file, we can use it directly + try { + const content = readFileSync(filePath, 'utf8'); + return content + .split(/\r?\n/) + .map(line => line.trim()) + .filter(line => line && !line.startsWith('#')); + } catch (e) { + console.error(`Error loading proxy list: ${e.message}`); + return []; + } +} + +function parseProxy(proxyStr) { + if (!proxyStr) return undefined; + let formatted = proxyStr.trim(); + if (!/^https?:\/\//i.test(formatted) && !/^socks[45]:\/\//i.test(formatted)) { + formatted = 'http://' + formatted; + } + try { + const url = new URL(formatted); + const proxyObj = { + server: `${url.protocol}//${url.host}`, + }; + if (url.username) { + proxyObj.username = decodeURIComponent(url.username); + } + if (url.password) { + proxyObj.password = decodeURIComponent(url.password); + } + return proxyObj; + } catch (e) { + return { server: proxyStr }; + } +} + +export { MimoRegistration, TempmailClient, CaptchaSolver, parseProxy, loadProxyList }; diff --git a/regis-loop.js b/regis-loop.js index 73eec59..e5cb77a 100644 --- a/regis-loop.js +++ b/regis-loop.js @@ -15,7 +15,7 @@ import { readFileSync, appendFileSync, existsSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; -import { MimoRegistration } from './index.js'; +import { MimoRegistration, parseProxy, loadProxyList } from './index.js'; import './extras.js'; // attach getReferralCode import { generateFingerprint, buildInitScript, buildExtraHeaders } from './fingerprint.js'; @@ -43,6 +43,27 @@ const outputFile = outputIdx !== -1 const failLog = join(outputDir, 'regis-fail.log'); +const proxyIdx = args.indexOf('--proxy'); +let proxyList = []; +if (proxyIdx !== -1) { + const nextArg = args[proxyIdx + 1]; + let proxyPath = 'proxy.txt'; + if (nextArg && !nextArg.startsWith('-')) { + proxyPath = nextArg; + } + const resolvedPath = join(__dirname, proxyPath); + if (existsSync(resolvedPath)) { + proxyList = loadProxyList(resolvedPath); + console.log(`Loaded ${proxyList.length} proxies from ${proxyPath}`); + } else if (nextArg && !nextArg.startsWith('-')) { + proxyList = [nextArg]; + } else { + console.log(`Proxy option enabled but ${proxyPath} not found.`); + } +} else if (config.proxy) { + proxyList = [config.proxy]; +} + // ---- File helpers ----------------------------------------------------- function saveResult(row) { @@ -76,6 +97,12 @@ async function runIteration(idx, total) { // Per-iter: clone config + set referral link to direct URL (no referral parameter) const iterConfig = JSON.parse(JSON.stringify(config)); + if (proxyList && proxyList.length > 0) { + const selectedProxy = proxyList[idx % proxyList.length]; + iterConfig.proxy = selectedProxy; + const cleanProxyName = selectedProxy.split('@').pop(); + console.log(` ↳ Using proxy [${(idx % proxyList.length) + 1}/${proxyList.length}]: ${cleanProxyName}`); + } iterConfig.xiaomi.inviteCode = ''; iterConfig.xiaomi.referralLink = 'https://platform.xiaomimimo.com/'; @@ -95,12 +122,12 @@ async function runIteration(idx, total) { try { // 1. Tempmail - console.log('[1/7] Creating temporary email...'); + console.log('[1/8] Creating temporary email...'); email = await reg.tempmail.createInbox(); console.log(`✓ Email: ${email}`); // 2. Browser - console.log('[2/7] Launching browser...'); + console.log('[2/8] Launching browser...'); const fp = generateFingerprint(); reg.fingerprint = fp; console.log(` ↳ Chrome ${fp.chromeMajor}, ${fp.viewport.width}x${fp.viewport.height}, ${fp.locale}/${fp.timezone}`); @@ -108,6 +135,7 @@ async function runIteration(idx, total) { reg.browser = await chromium.launch({ headless: iterConfig.browser.headless, channel: 'chrome', + proxy: parseProxy(iterConfig.proxy), args: [ `--window-size=${fp.viewport.width},${fp.viewport.height}`, '--disable-blink-features=AutomationControlled', @@ -134,31 +162,135 @@ async function runIteration(idx, total) { }; // 3. Open registration page directly - console.log('[3/7] Opening registration page...'); + console.log('[3/8] Opening registration page...'); await reg.page.goto(iterConfig.xiaomi.referralLink, { waitUntil: 'networkidle', timeout: iterConfig.browser.timeout, }); // 4. Sign up form - console.log('[4/7] Filling Sign up form...'); + console.log('[4/8] Filling Sign up form...'); await reg.fillRegistrationForm(email); await reg.submitRegistration(); // 5. Captcha - console.log('[5/7] Handling captcha...'); + console.log('[5/8] Handling captcha...'); await reg.handleXiaomiCaptcha(); await reg.handleImageCaptcha(); // 6. Verify email - console.log('[6/7] Verifying email...'); + console.log('[6/8] Verifying email...'); await reg.verifyEmail(email); - // 7. Skip Redeem - console.log('[Info] Skipping redeem/enter invite code step.'); + // 7. Check Balance (Terms modal will be handled here if opened) + console.log('[7/8] Checking balance...'); + try { + // 1. Klik menu "Console" dulu — biar navigasi-nya mirip user beneran + await reg.clickConsoleMenu(); + + // 2. Navigasi ke balance page jika belum + let url = reg.page.url(); + if (!url.includes('/console/balance')) { + console.log(` Not on balance page yet (current: ${url}), navigating...`); + + const balanceClicked = await reg.page.evaluate(() => { + const links = Array.from(document.querySelectorAll('a, [role="link"], li, [role="menuitem"]')); + const target = links.find(el => { + const txt = (el.textContent || '').trim(); + return /^Balance$/i.test(txt) && el.offsetHeight > 0; + }); + if (target) { + target.scrollIntoView({ block: 'center' }); + target.click(); + return true; + } + return false; + }); + + if (balanceClicked) { + console.log(' ✓ Clicked Balance link in console sidebar'); + await reg.page.waitForURL(/\/console\/balance/, { timeout: 8000 }).catch(() => {}); + await reg.page.waitForLoadState('networkidle', { timeout: 8000 }).catch(() => {}); + } else { + console.log(' ! Balance link not found, falling back to direct goto...'); + await reg.page.goto('https://platform.xiaomimimo.com/console/balance', { + waitUntil: 'networkidle', + timeout: iterConfig.browser.timeout, + }); + } + } + await reg.page.waitForTimeout(2500); + + await reg.handleOAuthRedirect(); + await reg.page.waitForTimeout(2000); + + // Close cookies banner if any + console.log(' Checking for cookies banner...'); + const acceptCookiesBtn = await reg.page.waitForSelector('button:has-text("Accept All"), button:has-text("Accept"), button:has-text("Allow All")', { timeout: 4000 }).catch(() => null); + if (acceptCookiesBtn) { + await acceptCookiesBtn.click({ force: true }).catch(() => {}); + console.log(' ✓ Accepted cookies banner'); + await reg.page.waitForTimeout(2000); + } + + // Terms modal + await reg.handleTermsModal(); + + // Overlays + await reg.waitForOverlaysGone(); + + // Take screenshot + await reg.page.screenshot({ path: 'screenshot-balance.png', fullPage: false }); + console.log(' ✓ Captured screenshot-balance.png'); + + // Cek apakah ada notifikasi risk control / block/ restricted + const restrictionMsg = await reg.page.evaluate(() => { + const text = document.body.innerText || ''; + const patterns = [ + /risk\s*control\s*restriction/i, + /account\s+has\s+risk\s+control/i, + /contact\s+customer\s+service/i, + /account\s+(is\s+)?restricted/i, + ]; + for (const re of patterns) { + const m = text.match(new RegExp('([^\\n]{0,200}' + re.source + '[^\\n]{0,200})', re.flags)); + if (m) return m[1].trim(); + } + return null; + }).catch(() => null); + + if (restrictionMsg) { + console.log(' ❌ ACCOUNT RESTRICTED:'); + console.log(` ${restrictionMsg}`); + try { + await reg.page.screenshot({ + path: `error-restriction-${Date.now()}.png`, + fullPage: true, + }); + } catch (e) {} + const err = new Error(`ACCOUNT_RESTRICTED: ${restrictionMsg}`); + err.code = 'ACCOUNT_RESTRICTED'; + err.restrictionMsg = restrictionMsg; + throw err; + } + + // Read balance + const balance = await reg.readBalance(); + console.log(` 💰 Balance: $${balance !== null ? balance.toFixed(2) : 'unknown'}`); + if (balance === 0) { + const err = new Error('Balance is $0.00'); + err.code = 'BALANCE_ZERO'; + throw err; + } + } catch (e) { + if (e.code === 'ACCOUNT_RESTRICTED' || e.code === 'BALANCE_ZERO') { + throw e; + } + console.log(` ! check balance error (lanjut): ${e.message}`); + } // 8. Create API key (atau ambil existing) - console.log('[7/7] Creating API key...'); + console.log('[8/8] Creating API key...'); try { apiKey = await reg.createApiKey(); console.log(`✓ API key: ${apiKey || '(none)'}`); @@ -201,6 +333,18 @@ async function runIteration(idx, total) { return { ok: true, email, refCode, apiKey }; } catch (err) { + if (err.code === 'BALANCE_ZERO') { + console.log(`\n⚠ Regis Iteration ${idx + 1} skipped: ${err.message}`); + logFail(email, err.message); + return { + ok: false, + email, + error: err.message, + restricted: false, + stopReason: err.code, + }; + } + console.error(`\n❌ Regis Iteration ${idx + 1} failed: ${err.message}`); if (reg.page) { try { diff --git a/regis-result.txt b/regis-result.txt index b77d5d0..0a482fa 100644 --- a/regis-result.txt +++ b/regis-result.txt @@ -1,2 +1,7 @@ # Regis loop results. Format: email:password:refCode:apiKey alexsetiawan@adrnode.com:MimoAuto2024!:DPWQPR:sk-spot7dmzwv05ijj960sz2vab17h3ii42x01zcyg31834cpun +ekojuang969@shitoors.fun:MimoAuto2024!:: +kurniautama@shitoors.fun:MimoAuto2024!:T58EXJ:sk-snu9xvlbnir5ofgne07liaa0juagrr5a9l3939wii7oz8lo7 +sigithadi543@shitoors.fun:MimoAuto2024!:: +jasontenang565@foxsight.xyz:MimoAuto2024!:: +aryafrost219@foxsight.xyz:MimoAuto2024!:XAFA8U:sk-scb9vvdzsv5h3wirlrkto59v4e11in0gubz36kdnijk0r5xo