mirror of
https://wget.la/https://github.com/432539/gpt
synced 2026-08-17 03:26:59 +08:00
只开源「GPT 账号注册机 / 管理」(account-manager):账号列表/导入导出、检测/批量检测、 拿 RT、协议/浏览器注册等注册机能力。批量直开 / 协议支付 / 提取链接 / 直卡直开 等其它功能 不含实现代码,仅通过 iframe 内嵌外链访问。真实机密均由 .gitignore 忽略,仅提供脱敏示例配置。
119 lines
5.8 KiB
JavaScript
119 lines
5.8 KiB
JavaScript
// 反检测:为每个注册账号合成一套「内部自洽」的浏览器/设备指纹 + 随机姓名 + 成年生日。
|
||
// 目的:以前所有账号都写死同一 UA(Chrome/145 Windows)、同一屏幕/语言、姓名只在 6×6 里选、
|
||
// 年龄挤在 1995~2002,风控极易把这些注册归成同一批机器人。这里让「每账号一套、全程一致、
|
||
// 账号间不同」——UA / sec-ch-ua / platform / screen / navigator 全部彼此对齐(否则 sec-ch-ua
|
||
// 与 UA 不符本身就是强特征)。
|
||
import crypto from 'node:crypto';
|
||
|
||
function pick(arr) { return arr[crypto.randomInt(0, arr.length)]; }
|
||
|
||
// 每个 profile 固定「Chrome 大版本 ↔ 真实的 sec-ch-ua 品牌串」配对:sec-ch-ua 的 GREASE 品牌
|
||
// ("Not?A_Brand" 之类)与版本号是浏览器构建时生成的,随便拼会露馅,所以直接采样真实组合。
|
||
const CHROME_PROFILES = [
|
||
{ major: 140, secChUa: '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"' },
|
||
{ major: 141, secChUa: '"Google Chrome";v="141", "Not?A_Brand";v="8", "Chromium";v="141"' },
|
||
{ major: 142, secChUa: '"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"' },
|
||
{ major: 143, secChUa: '"Not;A=Brand";v="99", "Google Chrome";v="143", "Chromium";v="143"' },
|
||
{ major: 144, secChUa: '"Google Chrome";v="144", "Chromium";v="144", "Not.A/Brand";v="24"' },
|
||
{ major: 145, secChUa: '"Chromium";v="145", "Not)A;Brand";v="8", "Google Chrome";v="145"' },
|
||
{ major: 138, secChUa: '"Not)A;Brand";v="8", "Chromium";v="138", "Google Chrome";v="138"' },
|
||
{ major: 139, secChUa: '"Chromium";v="139", "Not_A Brand";v="24", "Google Chrome";v="139"' },
|
||
];
|
||
|
||
// OS 决定 UA 平台段、navigator.platform、sec-ch-ua-platform 三者必须一致。
|
||
const OS_PROFILES = [
|
||
{ uaToken: 'Windows NT 10.0; Win64; x64', platform: 'Win32', chPlatform: '"Windows"' },
|
||
{ uaToken: 'Macintosh; Intel Mac OS X 10_15_7', platform: 'MacIntel', chPlatform: '"macOS"' },
|
||
];
|
||
|
||
// 常见桌面分辨率(宽x高);taskbar/书签栏占用后 availHeight 略小于 height,贴近真机。
|
||
const SCREENS = [
|
||
{ width: 1920, height: 1080 },
|
||
{ width: 2560, height: 1440 },
|
||
{ width: 1536, height: 864 },
|
||
{ width: 1440, height: 900 },
|
||
{ width: 1366, height: 768 },
|
||
{ width: 1680, height: 1050 },
|
||
];
|
||
|
||
// 英文母语区:语言/locale 保持在英语圈内,避免 UA 是美式 Chrome 却报 zh-CN 这种矛盾。
|
||
const LOCALES = [
|
||
{ language: 'en-US', accept: 'en-US,en;q=0.9', tz: 'America/New_York' },
|
||
{ language: 'en-US', accept: 'en-US,en;q=0.9', tz: 'America/Chicago' },
|
||
{ language: 'en-US', accept: 'en-US,en;q=0.9', tz: 'America/Los_Angeles' },
|
||
{ language: 'en-GB', accept: 'en-GB,en;q=0.9', tz: 'Europe/London' },
|
||
{ language: 'en-CA', accept: 'en-CA,en;q=0.9', tz: 'America/Toronto' },
|
||
];
|
||
|
||
// 生成一套彼此自洽的指纹。同一账号整条注册流程复用同一个对象;不同账号各自独立随机。
|
||
export function generateFingerprint() {
|
||
const chrome = pick(CHROME_PROFILES);
|
||
const osp = pick(OS_PROFILES);
|
||
const screen = pick(SCREENS);
|
||
const loc = pick(LOCALES);
|
||
const hardwareConcurrency = pick([4, 8, 12, 16]);
|
||
const deviceMemory = pick([8, 16]); // Chrome 只暴露 8/16 这类粗粒度值
|
||
|
||
const userAgent =
|
||
`Mozilla/5.0 (${osp.uaToken}) AppleWebKit/537.36 (KHTML, like Gecko) ` +
|
||
`Chrome/${chrome.major}.0.0.0 Safari/537.36`;
|
||
|
||
return {
|
||
userAgent,
|
||
secChUa: chrome.secChUa,
|
||
secChUaMobile: '?0', // 桌面固定 ?0,与 UA 无移动标记一致
|
||
secChUaPlatform: osp.chPlatform,
|
||
platform: osp.platform,
|
||
language: loc.language,
|
||
acceptLanguage: loc.accept,
|
||
languages: `${loc.language},${loc.language.split('-')[0]}`,
|
||
timezone: loc.tz,
|
||
screen: {
|
||
width: screen.width,
|
||
height: screen.height,
|
||
// availHeight 减去任务栏/系统栏的典型高度,availWidth 通常等于 width。
|
||
availWidth: screen.width,
|
||
availHeight: screen.height - 40,
|
||
colorDepth: 24,
|
||
pixelDepth: 24,
|
||
},
|
||
screenStr: `${screen.width}x${screen.height}`,
|
||
hardwareConcurrency,
|
||
deviceMemory,
|
||
};
|
||
}
|
||
|
||
// 扩充姓名池:各数十个真实常见英文名,随机组合,避免总是那几对被风控聚类。
|
||
const FIRST_NAMES = [
|
||
'James', 'Michael', 'Robert', 'John', 'David', 'William', 'Richard', 'Joseph',
|
||
'Thomas', 'Christopher', 'Daniel', 'Matthew', 'Anthony', 'Andrew', 'Joshua',
|
||
'Ryan', 'Brandon', 'Justin', 'Benjamin', 'Samuel', 'Nathan', 'Aaron', 'Adam',
|
||
'Mary', 'Patricia', 'Jennifer', 'Linda', 'Elizabeth', 'Barbara', 'Susan',
|
||
'Jessica', 'Sarah', 'Karen', 'Emily', 'Emma', 'Olivia', 'Sophia', 'Ava',
|
||
'Isabella', 'Mia', 'Charlotte', 'Amelia', 'Hannah', 'Grace', 'Rachel',
|
||
'Laura', 'Megan', 'Lauren', 'Victoria',
|
||
];
|
||
const LAST_NAMES = [
|
||
'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis',
|
||
'Rodriguez', 'Martinez', 'Hernandez', 'Lopez', 'Gonzalez', 'Wilson', 'Anderson',
|
||
'Thomas', 'Taylor', 'Moore', 'Jackson', 'Martin', 'Lee', 'Perez', 'Thompson',
|
||
'White', 'Harris', 'Sanchez', 'Clark', 'Ramirez', 'Lewis', 'Robinson', 'Walker',
|
||
'Young', 'Allen', 'King', 'Wright', 'Scott', 'Torres', 'Hill', 'Green',
|
||
'Adams', 'Baker', 'Nelson', 'Carter', 'Mitchell', 'Roberts', 'Turner',
|
||
'Phillips', 'Campbell', 'Parker', 'Evans',
|
||
];
|
||
|
||
export function randomFullName() {
|
||
return `${pick(FIRST_NAMES)} ${pick(LAST_NAMES)}`;
|
||
}
|
||
|
||
// 成年生日:约 18~48 岁均匀取样,月/日在安全范围(1~28)避免非法日期,格式 YYYY-MM-DD 与旧逻辑一致。
|
||
export function randomAdultBirthdate() {
|
||
const nowYear = new Date().getUTCFullYear();
|
||
const age = 18 + crypto.randomInt(0, 31); // 18..48
|
||
const year = nowYear - age;
|
||
const month = 1 + crypto.randomInt(0, 12);
|
||
const day = 1 + crypto.randomInt(0, 28);
|
||
return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
||
}
|