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
+241
View File
@@ -0,0 +1,241 @@
// 接码 / SMS 验证码服务 —— smscode.gg API 客户端(零依赖,使用全局 fetch)
// 文档:https://smscode.gg/docs Base URL: https://api.smscode.gg/v1
// 鉴权:Authorization: Bearer <apiKey>
// 统一响应包络:{ success:true, data:{...} } / { success:false, error:{ code, message } }
//
// 订单生命周期:
// 1. createOrder → 下单拿号(product_id 精确档位 或 catalog_product_id 路由)
// 2. pollOtp → 轮询 GET /orders/{id} 直到 status=OTP_RECEIVED 拿到 otp_code
// 3. finishOrder → 收到验证码后标记完成(立即释放号码)
// 或 cancelOrder → 未收到验证码时取消(退款)
const DEFAULT_BASE = 'https://api.smscode.gg/v1';
function normBase(baseUrl) {
return String(baseUrl || DEFAULT_BASE).trim().replace(/\/+$/, '') || DEFAULT_BASE;
}
// 统一请求:注入 Bearer、解析包络、处理 429/超时/HTTP 错误
async function request(cfg, method, pathAndQuery, { body, idempotencyKey, timeoutMs = 30000 } = {}) {
const base = normBase(cfg && cfg.baseUrl);
const apiKey = String((cfg && cfg.apiKey) || '').trim();
if (!apiKey) {
const e = new Error('未配置接码 API Key(系统设置 → 接码配置)');
e.code = 'NO_API_KEY';
throw e;
}
const url = `${base}${pathAndQuery}`;
const headers = {
authorization: `Bearer ${apiKey}`,
accept: 'application/json',
};
if (body !== undefined) headers['content-type'] = 'application/json';
if (idempotencyKey) headers['idempotency-key'] = idempotencyKey;
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
let res;
try {
res = await fetch(url, {
method,
headers,
body: body === undefined ? undefined : JSON.stringify(body),
signal: ctrl.signal,
});
} catch (err) {
clearTimeout(timer);
const e = new Error(err.name === 'AbortError' ? `接码请求超时(${method} ${pathAndQuery}` : `接码请求失败:${err.message}`);
e.code = 'NETWORK';
throw e;
}
clearTimeout(timer);
if (res.status === 429) {
const retry = Number(res.headers.get('retry-after')) || 5;
const e = new Error(`接码接口限流(429),请 ${retry}s 后重试`);
e.code = 'RATE_LIMIT_EXCEEDED';
e.retryAfter = retry;
throw e;
}
const data = await res.json().catch(() => ({}));
if (!res.ok || data.success === false) {
const err = (data && data.error) || {};
const e = new Error(`接码接口错误:${err.code || res.status}${err.message ? ' · ' + err.message : ''}`);
e.code = err.code || `HTTP_${res.status}`;
e.status = res.status;
throw e;
}
return data.data;
}
// ---------- 目录(catalog ----------
export async function listCountries(cfg) {
return request(cfg, 'GET', '/catalog/countries');
}
export async function listServices(cfg, countryId) {
const q = countryId ? `?country_id=${encodeURIComponent(countryId)}` : '';
return request(cfg, 'GET', `/catalog/services${q}`);
}
export async function listProducts(cfg, { countryId, platformId, operatorId, limit = 50, page = 1 } = {}) {
const p = new URLSearchParams();
if (countryId) p.set('country_id', countryId);
if (platformId) p.set('platform_id', platformId);
if (operatorId) p.set('operator_id', operatorId);
p.set('limit', limit);
p.set('page', page);
return request(cfg, 'GET', `/catalog/products?${p.toString()}`);
}
export async function getBalance(cfg) {
return request(cfg, 'GET', '/balance');
}
// ---------- 订单 ----------
// 下单拿号。优先使用 productId(精确档位),否则用 catalogProductId(路由下单)。
export async function createOrder(cfg, { productId, catalogProductId, operatorId, maxPrice, quantity = 1 } = {}) {
const body = { quantity };
if (productId) body.product_id = Number(productId);
else if (catalogProductId) {
body.catalog_product_id = Number(catalogProductId);
if (operatorId) body.operator_id = Number(operatorId);
if (maxPrice) body.max_price = /^\d+$/.test(String(maxPrice)) ? Number(maxPrice) : String(maxPrice);
} else {
const e = new Error('下单需提供 productId 或 catalogProductId');
e.code = 'VALIDATION_ERROR';
throw e;
}
const idempotencyKey = `getrt-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
const data = await request(cfg, 'POST', '/orders/create', { body, idempotencyKey });
const order = (data.orders && data.orders[0]) || data;
if (!order || !order.id) {
const e = new Error('下单未返回有效订单');
e.code = 'NO_ORDER';
throw e;
}
return order; // { id, status, phone_number, ... }
}
export async function getOrder(cfg, id) {
return request(cfg, 'GET', `/orders/${encodeURIComponent(id)}`);
}
export async function finishOrder(cfg, id) {
return request(cfg, 'POST', '/orders/finish', { body: { id: Number(id) } });
}
export async function cancelOrder(cfg, id) {
return request(cfg, 'POST', '/orders/cancel', { body: { id: Number(id) } });
}
export async function resendOrder(cfg, id) {
return request(cfg, 'POST', '/orders/resend', { body: { id: Number(id) } });
}
// 轮询等待验证码:直到 status=OTP_RECEIVED 且拿到 otp_code,或超时。
// log(level,msg) 可选,用于向上层推送进度。
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 order;
try {
order = await getOrder(cfg, id);
} catch (e) {
say('warn', `查询订单失败(将重试):${e.message}`);
await sleep(intervalMs);
continue;
}
const status = String(order.status || '').toUpperCase();
if (order.otp_code) {
say('ok', `已收到验证码:${order.otp_code}`);
return { code: order.otp_code, message: order.otp_message || '', order };
}
if (status === 'CANCELED' || status === 'EXPIRED') {
const e = new Error(`订单已${status === 'CANCELED' ? '取消' : '过期'},未收到验证码`);
e.code = status;
throw e;
}
say('info', `等待验证码…(订单 ${id} 状态 ${status || '未知'}`);
await sleep(intervalMs);
}
const e = new Error(`等待验证码超时(${Math.round(timeoutMs / 1000)}s`);
e.code = 'OTP_TIMEOUT';
throw e;
}
function sleep(ms) {
return new Promise((r) => setTimeout(r, ms));
}
// 一站式:拿号 → 轮询验证码。返回 { orderId, phone, code }。
// 判断下单失败是否属于“无库存/无号码”类(可回退下一档位),而非鉴权/余额类(应立即抛出)。
function isStockError(e) {
const code = String((e && e.code) || '').toUpperCase();
if (['NO_OFFER_AVAILABLE', 'PROVIDER_ERROR', 'NO_ORDER'].includes(code)) return true;
const msg = String((e && e.message) || '').toLowerCase();
if ((e && e.status === 422) && /(no[_\s-]?number|no[_\s-]?offer|out.?of.?stock|no.?stock|stock|available|sold.?out)/.test(msg)) return true;
return false;
}
// 拉取 country+service 的产品档位,构造“有货 + 按价格升序”的候选下单顺序。
// 若配置了 productId 且该档位有货,则置于队首。返回 [{ productId, price, available }]。
export async function buildCandidates(cfg, { log } = {}) {
const say = (level, msg) => { if (typeof log === 'function') log(level, msg); };
const products = await listProducts(cfg, { countryId: cfg.countryId, platformId: cfg.serviceId, limit: 10000, page: 1 });
const list = Array.isArray(products) ? products : [];
const inStock = list
.filter((p) => p && p.active !== false && (Number(p.available) || 0) > 0)
.map((p) => ({ productId: p.id, price: Number(p.price) || 0, available: Number(p.available) || 0 }))
.sort((a, b) => a.price - b.price);
const configured = Number(cfg.productId) || 0;
let ordered = inStock;
if (configured) {
const hit = inStock.find((c) => Number(c.productId) === configured);
if (hit) ordered = [hit, ...inStock.filter((c) => Number(c.productId) !== configured)];
else say('warn', `配置的 productId=${configured} 当前无货,改用有货档位(按价格升序)`);
}
say('info', `候选档位(有货,共 ${ordered.length}):${ordered.slice(0, 8).map((c) => `#${c.productId}@${c.price}(${c.available})`).join(' → ')}${ordered.length > 8 ? ' …' : ''}`);
return ordered;
}
// 拿号(带无货自动回退)。返回 { orderId, phone, order },与旧签名一致。
// 调用方应在使用完验证码后调用 finishOrder;失败时调用 cancelOrder(若 can_cancel)。
export async function acquireNumber(cfg, { log } = {}) {
const say = (level, msg) => { if (typeof log === 'function') log(level, msg); };
// 未配置 country+service:维持旧行为(单一 productId / catalogProductId)。
if (!cfg.countryId || !cfg.serviceId) {
const order = await createOrder(cfg, {
productId: cfg.productId,
catalogProductId: cfg.catalogProductId,
operatorId: cfg.operatorId,
maxPrice: cfg.maxPrice,
});
say('ok', `已获取号码:${order.phone_number}(订单 ${order.id}`);
return { orderId: order.id, phone: order.phone_number, order };
}
const candidates = await buildCandidates(cfg, { log });
if (!candidates.length) {
const e = new Error(`所有档位均无库存/下单失败(country=${cfg.countryId} service=${cfg.serviceId}`);
e.code = 'NO_OFFER_AVAILABLE';
throw e;
}
for (let i = 0; i < candidates.length; i++) {
const c = candidates[i];
try {
say('info', `尝试下单档位 #${c.productId}(价格 ${c.price} IDR,库存 ${c.available}`);
const order = await createOrder(cfg, { productId: c.productId });
say('ok', `已获取号码:${order.phone_number}(订单 ${order.id},档位 #${c.productId} 价格 ${c.price} IDR`);
return { orderId: order.id, phone: order.phone_number, order };
} catch (e) {
if (isStockError(e)) {
say('warn', `档位 #${c.productId} 无库存/下单失败(${e.code || e.message}),尝试下一档位…`);
continue;
}
throw e; // 鉴权/余额等非库存错误:立即抛出
}
}
const e = new Error(`所有档位均无库存/下单失败(country=${cfg.countryId} service=${cfg.serviceId}`);
e.code = 'NO_OFFER_AVAILABLE';
throw e;
}