import { randomBytes } from "node:crypto"; import { qqDnaEmailPool } from "@/lib/flock/qqdna-email-pool"; const PLUS_ALIAS_DOMAINS = new Set([ "gmail.com", "googlemail.com", "outlook.com", "hotmail.com", "live.com", "yahoo.com", "icloud.com", "me.com", ]); /** 录制验证可用的 QQ(随机虚构 QQ 会被官网拒绝) */ const VERIFIED_QQ_BASE = "3457189488@qq.com"; /** 轮询取池,避免同次批量撞同一邮箱 */ let poolCursor = 0; function takeFromPool(pool: string[]): string { if (pool.length === 0) { throw new Error("empty email pool"); } const item = pool[poolCursor % pool.length]!; poolCursor += 1; return item; } /** 解析逗号/分号/换行分隔的池 */ export function parseFlockEnvPool(raw: string | undefined): string[] { if (!raw?.trim()) { return []; } return raw .split(/[,;\n]+/) .map((s) => s.trim()) .filter(Boolean); } function pickPoolItem(pool: string[]): string { return takeFromPool(pool); } function randomUsPhone10(): string { const areaCodes = [ 212, 213, 310, 312, 404, 408, 415, 469, 512, 617, 626, 702, 713, 718, 753, 786, 818, 832, 917, 972, ]; const area = areaCodes[randomBytes(1)[0]! % areaCodes.length]!; // 避开 N11 保留号段(411 等),否则官网可能禁用提交 let exchange = 200 + (randomBytes(1)[0]! % 800); if (exchange % 100 === 11) { exchange += 1; } const line = String(1000 + (randomBytes(2).readUInt16BE(0) % 9000)); return `${area}${exchange}${line}`.slice(0, 10); } /** * 短 QQ 邮箱:1/2/3 开头 + 9 位随机数字 * 注意:虚构 QQ 号常被 Flock 以「We had an issue creating your account」拒绝 * 仅 FLOCK_EMAIL_MODE=random_qq 时使用 */ export function createRandomQqEmail(): string { const prefix = 1 + (randomBytes(1)[0]! % 3); const nineDigits = String(randomBytes(4).readUInt32BE(0) % 1_000_000_000).padStart( 9, "0", ); return `${prefix}${nineDigits}@qq.com`; } /** * 已验证 QQ + 短别名:3457189488+a1b2c3@qq.com(总计较短) * 官网曾对该格式成功出过价 */ export function createVerifiedQqAliasedEmail(): string { const tag = randomBytes(3).toString("hex"); // 6 字符 return `3457189488+${tag}@qq.com`; } /** Gmail/Outlook 等 + 子地址 */ export function buildFlockAliasedEmail(baseEmail: string, unique: string): string { const trimmed = baseEmail.trim(); const at = trimmed.lastIndexOf("@"); if (at < 1) { return trimmed; } const local = trimmed.slice(0, at).split("+")[0]!; const domain = trimmed.slice(at + 1).toLowerCase(); const tag = unique.replace(/[^a-z0-9]/gi, "").slice(0, 8) || randomBytes(3).toString("hex"); if (PLUS_ALIAS_DOMAINS.has(domain)) { return `${local}+${tag}@${domain}`; } if (domain === "qq.com") { return `${local}+${tag.slice(0, 6)}@qq.com`; } return createVerifiedQqAliasedEmail(); } function resolveFreshEmail(id: string, ts: string): string { const emailPool = parseFlockEnvPool(process.env.FLOCK_EMAIL_POOL); if (emailPool.length > 0) { return pickPoolItem(emailPool); } const mode = process.env.FLOCK_EMAIL_MODE?.trim().toLowerCase(); // qq.qqdna.com 号码库拼 @qq.com(用户指定探针模式) if (mode === "qqdna" || mode === "qq_dna") { return takeFromPool(qqDnaEmailPool()); } if (mode === "random_qq") { return createRandomQqEmail(); } const aliasBase = process.env.FLOCK_EMAIL_ALIAS_BASE?.trim() || process.env.FLOCK_TEST_EMAIL?.trim() || VERIFIED_QQ_BASE; const domain = aliasBase.split("@")[1]?.toLowerCase() ?? ""; if (PLUS_ALIAS_DOMAINS.has(domain) || domain === "qq.com") { return buildFlockAliasedEmail(aliasBase, `${ts}${id}`); } return createVerifiedQqAliasedEmail(); } const FIRST_NAMES = [ "James", "Michael", "Robert", "David", "Daniel", "Emily", "Sarah", "Jessica", "Amanda", "Lauren", ] as const; const LAST_NAMES = [ "Johnson", "Williams", "Brown", "Miller", "Davis", "Wilson", "Anderson", "Taylor", "Thomas", "Moore", ] as const; const COMPANIES = [ "Pacific Freight Solutions", "Horizon Logistics LLC", "Summit Cargo Partners", "Northstar Shipping Co", "Blue Ridge Transport", "Atlas Trucking Group", "Crescent Supply Chain", "Midwest Load Line", ] as const; function pickName(list: readonly string[]): string { return list[randomBytes(1)[0]! % list.length]!; } /** * 每次查价生成新注册账号: * - 优先 FLOCK_EMAIL_POOL * - FLOCK_EMAIL_MODE=qqdna:qq.qqdna.com 号码 + @qq.com * - FLOCK_EMAIL_MODE=random_qq:虚构 {1|2|3}{9位}@qq.com * - 默认:已验证 QQ + 短 +别名 * 姓名/公司用真人风格(避免 Guest3493 触发风控) */ export function createFreshFlockTestAccount(): { firstName: string; lastName: string; company: string; phone: string; email: string; shipmentsPerMonth: string; } { const id = randomBytes(5).toString("hex"); const ts = Date.now().toString(36); const phonePool = parseFlockEnvPool(process.env.FLOCK_PHONE_POOL).map((p) => p.replace(/\D/g, "").slice(-10), ); const email = resolveFreshEmail(id, ts); const phone = phonePool.length > 0 ? pickPoolItem(phonePool) : randomUsPhone10(); return { firstName: process.env.FLOCK_TEST_FIRST_NAME?.trim() || pickName(FIRST_NAMES), lastName: process.env.FLOCK_TEST_LAST_NAME?.trim() || pickName(LAST_NAMES), company: process.env.FLOCK_TEST_COMPANY?.trim() || pickName(COMPANIES), phone, email, shipmentsPerMonth: process.env.FLOCK_TEST_SHIPMENTS_MONTH?.trim() || "1-25", }; }