Initial commit: GPT 账号注册机 (open source)

只开源「GPT 账号注册机 / 管理」(account-manager):账号列表/导入导出、检测/批量检测、
拿 RT、协议/浏览器注册等注册机能力。批量直开 / 协议支付 / 提取链接 / 直卡直开 等其它功能
不含实现代码,仅通过 iframe 内嵌外链访问。真实机密均由 .gitignore 忽略,仅提供脱敏示例配置。
This commit is contained in:
432539
2026-08-05 14:54:32 +08:00
commit fef45134d5
29 changed files with 9829 additions and 0 deletions
+204
View File
@@ -0,0 +1,204 @@
// 接码 / SMS 验证码服务 —— smsbower.app API 客户端(零依赖,使用全局 fetch)
// 协议:经典 sms-activate 风格,所有请求为 GET https://smsbower.page/stubs/handler_api.php?api_key=..&action=..
// 响应为纯文本(冒号分隔),如 ACCESS_NUMBER:<activationId>:<phone>、STATUS_OK:<code>
//
// 与 smscode.js 接口对齐(可作为调度器的替换供应商):
// acquireNumber(cfg, { log }) → { orderId, phone, order }
// pollOtp(cfg, id, { timeoutMs, intervalMs, log }) → { code, message, order }
// finishOrder(cfg, id) → setStatus status=6(完成)
// cancelOrder(cfg, id) → setStatus status=8(取消,2 分钟内不可取消时静默处理)
// getBalance(cfg) → 余额数字
//
// 配置字段:apiKey、baseUrl(默认 .page 地址)、country(默认 22=印度)、
// service(默认 "dr"=OpenAI/ChatGPT)、maxPrice、pollTimeout
const DEFAULT_BASE = 'https://smsbower.page/stubs/handler_api.php';
const DEFAULT_COUNTRY = 22; // 印度
const DEFAULT_SERVICE = 'dr'; // OpenAI / ChatGPT
function normBase(baseUrl) {
return String(baseUrl || DEFAULT_BASE).trim().replace(/\/+$/, '') || DEFAULT_BASE;
}
// 统一请求:拼接 api_key + action + 参数,返回纯文本响应(已 trim)
async function request(cfg, action, params = {}, { timeoutMs = 30000 } = {}) {
const apiKey = String((cfg && cfg.apiKey) || '').trim();
if (!apiKey) {
const e = new Error('未配置 smsbower API Key(系统设置 → 接码配置)');
e.code = 'NO_API_KEY';
throw e;
}
const q = new URLSearchParams({ api_key: apiKey, action });
for (const [k, v] of Object.entries(params)) {
if (v !== undefined && v !== null && v !== '') q.set(k, String(v));
}
const url = `${normBase(cfg && cfg.baseUrl)}?${q.toString()}`;
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
let res;
try {
res = await fetch(url, { method: 'GET', signal: ctrl.signal });
} catch (err) {
clearTimeout(timer);
const e = new Error(err.name === 'AbortError' ? `接码请求超时(action=${action}` : `接码请求失败:${err.message}`);
e.code = 'NETWORK';
throw e;
}
clearTimeout(timer);
const text = String(await res.text().catch(() => '')).trim();
if (!res.ok) {
const e = new Error(`接码接口错误:HTTP_${res.status}${text ? ' · ' + text.slice(0, 200) : ''}`);
e.code = `HTTP_${res.status}`;
e.status = res.status;
throw e;
}
return text;
}
// 通用错误码 → 带 code 的 ErrorBAD_KEY / BAD_ACTION / BAD_SERVICE / NO_ACTIVATION 等)
function apiError(token, action) {
const map = {
BAD_KEY: 'API Key 无效',
BAD_ACTION: '接口 action 无效',
BAD_SERVICE: '服务代码无效',
NO_ACTIVATION: '激活订单不存在',
NO_BALANCE: '余额不足',
NO_NUMBERS: '当前无可用号码',
};
const e = new Error(`接码接口错误:${token}${map[token] ? ' · ' + map[token] : ''}action=${action}`);
e.code = token;
return e;
}
function sleep(ms) {
return new Promise((r) => setTimeout(r, ms));
}
// ---------- 余额 ----------
// 返回余额数字。响应:ACCESS_BALANCE:<balance>
export async function getBalance(cfg) {
const text = await request(cfg, 'getBalance');
const m = /^ACCESS_BALANCE:(.+)$/.exec(text);
if (m) {
const n = Number(m[1]);
if (Number.isFinite(n)) return n;
}
throw apiError(text || 'EMPTY_RESPONSE', 'getBalance');
}
// ---------- 拿号 ----------
// 返回 { orderId, phone, order },与 smscode.acquireNumber 一致(orderId = activationId)。
// NO_NUMBERS(无库存,可回退重试)→ e.code='NO_OFFER_AVAILABLE'(与 smscode 的库存错误标记一致),
// 并附 e.providerCode='NO_NUMBERS'NO_BALANCE / BAD_KEY / BAD_SERVICE 为硬错误,直接抛出。
export async function acquireNumber(cfg, { log } = {}) {
const say = (level, msg) => { if (typeof log === 'function') log(level, msg); };
const country = cfg.country !== undefined && cfg.country !== null && cfg.country !== '' ? cfg.country : DEFAULT_COUNTRY;
const service = String(cfg.service || DEFAULT_SERVICE);
const params = { service, country };
if (cfg.maxPrice) params.maxPrice = cfg.maxPrice;
if (cfg.minPrice) params.minPrice = cfg.minPrice;
say('info', `向 smsbower 请求号码(service=${service} country=${country}${cfg.maxPrice ? ' maxPrice=' + cfg.maxPrice : ''})…`);
const text = await request(cfg, 'getNumber', params);
const m = /^ACCESS_NUMBER:([^:]+):(.+)$/.exec(text);
if (m) {
const orderId = m[1];
const phone = m[2];
const order = { id: orderId, phone_number: phone, status: 'PENDING', raw: text };
say('ok', `已获取号码:${phone}(订单 ${orderId}`);
return { orderId, phone, order };
}
if (text === 'NO_NUMBERS' || text.startsWith('NO_NUMBERS')) {
// 无库存:标记为可回退的库存错误(与 smscode 的 isStockError 判定一致)
const e = new Error(`当前无可用号码(service=${service} country=${country}`);
e.code = 'NO_OFFER_AVAILABLE';
e.providerCode = 'NO_NUMBERS';
throw e;
}
throw apiError(text || 'EMPTY_RESPONSE', 'getNumber');
}
// ---------- 查询状态 ----------
// 返回 { status, code }。status ∈ WAIT_CODE / WAIT_RETRY / CANCEL / OK
export async function getStatus(cfg, id) {
const text = await request(cfg, 'getStatus', { id });
if (text === 'STATUS_WAIT_CODE') return { status: 'WAIT_CODE', code: '' };
let m = /^STATUS_WAIT_RETRY:(.*)$/.exec(text);
if (m) return { status: 'WAIT_RETRY', code: m[1] };
if (text === 'STATUS_CANCEL') return { status: 'CANCEL', code: '' };
m = /^STATUS_OK:(.+)$/.exec(text);
if (m) return { status: 'OK', code: m[1] };
throw apiError(text || 'EMPTY_RESPONSE', 'getStatus');
}
// ---------- 轮询等待验证码 ----------
// 直到 STATUS_OK 拿到 code,或订单取消/超时抛错。返回 { code, message, order },与 smscode.pollOtp 一致。
export async function pollOtp(cfg, id, { timeoutMs = 180000, intervalMs = 4000, log } = {}) {
const start = Date.now();
const say = (level, msg) => { if (typeof log === 'function') log(level, msg); };
while (Date.now() - start < timeoutMs) {
let st;
try {
st = await getStatus(cfg, id);
} catch (e) {
if (e.code === 'NO_ACTIVATION' || e.code === 'BAD_KEY') throw e; // 不可恢复
say('warn', `查询订单失败(将重试):${e.message}`);
await sleep(intervalMs);
continue;
}
if (st.status === 'OK' && st.code) {
say('ok', `已收到验证码:${st.code}`);
const order = { id, status: 'OTP_RECEIVED', otp_code: st.code };
return { code: st.code, message: '', order };
}
if (st.status === 'CANCEL') {
const e = new Error('订单已取消,未收到验证码');
e.code = 'CANCELED';
throw e;
}
// WAIT_CODE / WAIT_RETRY:继续等待
say('info', `等待验证码…(订单 ${id} 状态 ${st.status}${st.status === 'WAIT_RETRY' && st.code ? ',上一条验证码 ' + st.code : ''}`);
await sleep(intervalMs);
}
const e = new Error(`等待验证码超时(${Math.round(timeoutMs / 1000)}s`);
e.code = 'OTP_TIMEOUT';
throw e;
}
// ---------- 状态变更 ----------
// setStatus1=已就绪 3=请求下一条验证码 6=完成 8=取消
async function setStatus(cfg, id, status) {
return request(cfg, 'setStatus', { id, status });
}
// 完成订单(收到验证码后调用,setStatus=6)。响应:ACCESS_ACTIVATION
export async function finishOrder(cfg, id) {
const text = await setStatus(cfg, id, 6);
if (text === 'ACCESS_ACTIVATION') return { id, status: 'FINISHED' };
throw apiError(text || 'EMPTY_RESPONSE', 'setStatus(6)');
}
// 取消订单(setStatus=8)。响应:ACCESS_CANCEL。
// EARLY_CANCEL_DENIED(购买 2 分钟内不可取消)按非致命处理:记 warn 后正常返回,号码到期自动退款。
export async function cancelOrder(cfg, id, { log } = {}) {
const say = (level, msg) => { if (typeof log === 'function') log(level, msg); };
const text = await setStatus(cfg, id, 8);
if (text === 'ACCESS_CANCEL') return { id, status: 'CANCELED' };
if (text === 'EARLY_CANCEL_DENIED') {
say('warn', `订单 ${id} 购买未满 2 分钟,暂不可取消(到期后将自动退款)`);
return { id, status: 'CANCEL_PENDING', earlyCancelDenied: true };
}
throw apiError(text || 'EMPTY_RESPONSE', 'setStatus(8)');
}
// 请求下一条验证码(setStatus=3),对应 smscode.resendOrder。响应:ACCESS_RETRY_GET
export async function resendOrder(cfg, id) {
const text = await setStatus(cfg, id, 3);
if (text === 'ACCESS_RETRY_GET') return { id, status: 'WAIT_RETRY' };
throw apiError(text || 'EMPTY_RESPONSE', 'setStatus(3)');
}