qwenproxy-cli 1.6.11 → 1.6.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clean-cache.js +350 -18
- package/dist/delete-chats.js +900 -474
- package/dist/index.js +484 -58
- package/dist/login.js +373 -27
- package/dist/reset-cooldowns.js +684 -350
- package/dist/sync-clients.js +4 -1
- package/package.json +1 -1
- package/src/core/config.ts +4 -1
- package/src/core/model-alias.ts +1 -0
- package/src/core/version.ts +1 -1
- package/src/services/auth-playwright.ts +3 -2
- package/src/services/captcha-coordinator.ts +6 -4
- package/src/services/captcha-solver.ts +400 -2
- package/src/services/playwright.ts +62 -22
- package/src/services/qwen-chat-pool.ts +52 -9
- package/src/services/qwen-headers.ts +18 -1
- package/src/services/qwen.ts +6 -4
- package/src/services/session-keeper.ts +70 -8
package/dist/delete-chats.js
CHANGED
|
@@ -1093,7 +1093,7 @@ var init_config = __esm({
|
|
|
1093
1093
|
// Version header on Qwen API requests = the deployed web bundle version
|
|
1094
1094
|
// (fallback when dynamic DOM detection is not yet completed).
|
|
1095
1095
|
// Override via env when Qwen ships a new bundle.
|
|
1096
|
-
QWEN_WEB_VERSION: z.string().default("0.3.
|
|
1096
|
+
QWEN_WEB_VERSION: z.string().default("0.3.43"),
|
|
1097
1097
|
// Controls bx-ua/bx-umidtoken injection on the GENERAL API paths
|
|
1098
1098
|
// (chats/new, settings): those work without them (live-probed). The
|
|
1099
1099
|
// completions path is the exception — the 0.2.86 HAR shows the real
|
|
@@ -1136,6 +1136,7 @@ var init_config = __esm({
|
|
|
1136
1136
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
1137
1137
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
1138
1138
|
CAPTCHA_SOLVER_TIMEOUT_MS: z.string().default("15000"),
|
|
1139
|
+
CAPTCHA_SLIDER_TIMEOUT_MS: z.string().default("8000"),
|
|
1139
1140
|
CAPTCHA_SOLVER_RETRY_DELAY_MS: z.string().default("1000"),
|
|
1140
1141
|
CAPTCHA_SOLVER_SETTLE_MS: z.string().default("2000"),
|
|
1141
1142
|
CAPTCHA_ACCOUNT_COOLDOWN_MS: z.string().default("120000"),
|
|
@@ -1287,6 +1288,8 @@ var init_config = __esm({
|
|
|
1287
1288
|
enabled: env.CAPTCHA_SOLVER_ENABLED === "true",
|
|
1288
1289
|
maxAttempts: Math.max(1, Math.min(5, parseInt(env.CAPTCHA_SOLVER_MAX_ATTEMPTS))),
|
|
1289
1290
|
timeoutMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_TIMEOUT_MS)),
|
|
1291
|
+
/** Max wait for a challenge slider to become visible (slow WAF renders). */
|
|
1292
|
+
sliderTimeoutMs: Math.max(500, parseInt(env.CAPTCHA_SLIDER_TIMEOUT_MS)),
|
|
1290
1293
|
retryDelayMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_RETRY_DELAY_MS)),
|
|
1291
1294
|
settleMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_SETTLE_MS)),
|
|
1292
1295
|
/** Rest an account whose challenge could not be cleared before reusing it. */
|
|
@@ -1446,6 +1449,367 @@ var init_config = __esm({
|
|
|
1446
1449
|
}
|
|
1447
1450
|
});
|
|
1448
1451
|
|
|
1452
|
+
// src/services/qwen-url.ts
|
|
1453
|
+
function qwenUrl(path6 = "") {
|
|
1454
|
+
const normalizedPath = path6.replace(/^\/+/, "");
|
|
1455
|
+
return normalizedPath ? `${QWEN_BASE_URL}/${normalizedPath}` : QWEN_BASE_URL;
|
|
1456
|
+
}
|
|
1457
|
+
function qwenOrigin() {
|
|
1458
|
+
return QWEN_ORIGIN;
|
|
1459
|
+
}
|
|
1460
|
+
var QWEN_BASE_URL, QWEN_ORIGIN;
|
|
1461
|
+
var init_qwen_url = __esm({
|
|
1462
|
+
"src/services/qwen-url.ts"() {
|
|
1463
|
+
"use strict";
|
|
1464
|
+
init_config();
|
|
1465
|
+
QWEN_BASE_URL = config.qwen.baseUrl.trim().replace(/\/+$/, "");
|
|
1466
|
+
QWEN_ORIGIN = new URL(QWEN_BASE_URL).origin;
|
|
1467
|
+
}
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1470
|
+
// src/services/fingerprint.ts
|
|
1471
|
+
function mulberry32(seed) {
|
|
1472
|
+
return () => {
|
|
1473
|
+
seed |= 0;
|
|
1474
|
+
seed = seed + 1831565813 | 0;
|
|
1475
|
+
let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
|
|
1476
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
1477
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
function seedFromString(value) {
|
|
1481
|
+
let hash = 0;
|
|
1482
|
+
for (let i = 0; i < value.length; i++) {
|
|
1483
|
+
hash = (hash << 5) - hash + value.charCodeAt(i) | 0;
|
|
1484
|
+
}
|
|
1485
|
+
return hash >>> 0;
|
|
1486
|
+
}
|
|
1487
|
+
function pick(rng, values) {
|
|
1488
|
+
return values[Math.floor(rng() * values.length)];
|
|
1489
|
+
}
|
|
1490
|
+
function randInt(rng, min, max) {
|
|
1491
|
+
return Math.floor(rng() * (max - min + 1)) + min;
|
|
1492
|
+
}
|
|
1493
|
+
function updateChromeMajor(major) {
|
|
1494
|
+
if (typeof major === "number" && major >= 100) {
|
|
1495
|
+
dynamicChromeMajor = major;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
function getChromeMajor() {
|
|
1499
|
+
return dynamicChromeMajor;
|
|
1500
|
+
}
|
|
1501
|
+
function getSystemLocale() {
|
|
1502
|
+
return process.env.QWEN_LOCALE || (typeof Intl !== "undefined" && Intl.DateTimeFormat ? Intl.DateTimeFormat().resolvedOptions().locale : "") || "pt-BR";
|
|
1503
|
+
}
|
|
1504
|
+
function getLanguageProfiles(locale = getSystemLocale()) {
|
|
1505
|
+
const primary = locale.split("-")[0];
|
|
1506
|
+
if (primary === "en") {
|
|
1507
|
+
return [
|
|
1508
|
+
["en-US", "en"],
|
|
1509
|
+
["en-US", "en", "es"],
|
|
1510
|
+
["en", "en-US"],
|
|
1511
|
+
["en-US", "en;q=0.9"]
|
|
1512
|
+
];
|
|
1513
|
+
}
|
|
1514
|
+
return [
|
|
1515
|
+
[locale, primary, "en-US", "en"],
|
|
1516
|
+
[locale, primary, "en-US", "en", "es"],
|
|
1517
|
+
[locale, "en-US", "en", primary],
|
|
1518
|
+
[locale, primary, "en"],
|
|
1519
|
+
[locale, `${primary};q=0.9`, "en-US;q=0.8", "en;q=0.7"]
|
|
1520
|
+
];
|
|
1521
|
+
}
|
|
1522
|
+
function rotateFingerprintSeed(accountId) {
|
|
1523
|
+
const next = (rotationSalts.get(accountId) ?? 0) + 1;
|
|
1524
|
+
rotationSalts.set(accountId, next);
|
|
1525
|
+
profileCache.delete(accountId);
|
|
1526
|
+
return next;
|
|
1527
|
+
}
|
|
1528
|
+
function getFingerprintProfile(accountId) {
|
|
1529
|
+
const cached = profileCache.get(accountId);
|
|
1530
|
+
if (cached) return cached;
|
|
1531
|
+
const salt = rotationSalts.get(accountId) ?? 0;
|
|
1532
|
+
const seed = seedFromString(salt === 0 ? accountId : `${accountId}#r${salt}`);
|
|
1533
|
+
const rng = mulberry32(seed);
|
|
1534
|
+
const viewport = pick(rng, VIEWPORTS);
|
|
1535
|
+
const webgl = pick(rng, WEBGL_PROFILES);
|
|
1536
|
+
const languages = [...pick(rng, getLanguageProfiles())];
|
|
1537
|
+
const hardwareConcurrency = pick(rng, HARDWARE_CONCURRENCIES);
|
|
1538
|
+
const deviceMemory = pick(rng, DEVICE_MEMORIES);
|
|
1539
|
+
const platformInfo = pick(rng, PLATFORM_VERSIONS);
|
|
1540
|
+
const notABrand = pick(rng, NOT_A_BRAND_VARIANTS);
|
|
1541
|
+
const major = dynamicChromeMajor;
|
|
1542
|
+
const build = randInt(rng, 7300, 7600);
|
|
1543
|
+
const patch = randInt(rng, 0, 160);
|
|
1544
|
+
const chromeVersion = `${major}.0.${build}.${patch}`;
|
|
1545
|
+
const brands = [
|
|
1546
|
+
{ brand: notABrand.brand, version: notABrand.version },
|
|
1547
|
+
{ brand: "Google Chrome", version: String(major) },
|
|
1548
|
+
{ brand: "Chromium", version: String(major) }
|
|
1549
|
+
];
|
|
1550
|
+
const fullVersionList = [
|
|
1551
|
+
{ brand: notABrand.brand, version: chromeVersion },
|
|
1552
|
+
{ brand: "Google Chrome", version: chromeVersion },
|
|
1553
|
+
{ brand: "Chromium", version: chromeVersion }
|
|
1554
|
+
];
|
|
1555
|
+
const secChUa = brands.map((brand) => `"${brand.brand}";v="${brand.version}"`).join(", ");
|
|
1556
|
+
const userAgent = `Mozilla/5.0 (Windows NT ${platformInfo.major}.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`;
|
|
1557
|
+
const profile = {
|
|
1558
|
+
accountId,
|
|
1559
|
+
seed,
|
|
1560
|
+
userAgent,
|
|
1561
|
+
appVersion: userAgent.replace("Mozilla/", ""),
|
|
1562
|
+
chromeMajor: CHROME_MAJOR,
|
|
1563
|
+
chromeVersion,
|
|
1564
|
+
brands,
|
|
1565
|
+
fullVersionList,
|
|
1566
|
+
secChUa,
|
|
1567
|
+
platform: "Win32",
|
|
1568
|
+
platformVersion: platformInfo.platformVersion,
|
|
1569
|
+
architecture: "x86",
|
|
1570
|
+
bitness: "64",
|
|
1571
|
+
languages,
|
|
1572
|
+
locale: languages[0].split(";")[0],
|
|
1573
|
+
timezoneId: "America/Sao_Paulo",
|
|
1574
|
+
viewport,
|
|
1575
|
+
hardwareConcurrency,
|
|
1576
|
+
deviceMemory,
|
|
1577
|
+
webglVendor: webgl.vendor,
|
|
1578
|
+
webglRenderer: webgl.renderer,
|
|
1579
|
+
colorDepth: 24,
|
|
1580
|
+
pixelDepth: 24,
|
|
1581
|
+
canvasNoiseSeed: randInt(rng, 1, 2147483647),
|
|
1582
|
+
audioNoiseSeed: randInt(rng, 1, 2147483647),
|
|
1583
|
+
webglNoiseSeed: randInt(rng, 1, 2147483647),
|
|
1584
|
+
outerWidthOffset: randInt(rng, 0, 20),
|
|
1585
|
+
outerHeightOffset: randInt(rng, 75, 95)
|
|
1586
|
+
};
|
|
1587
|
+
profileCache.set(accountId, profile);
|
|
1588
|
+
return profile;
|
|
1589
|
+
}
|
|
1590
|
+
function clearFingerprintCache(accountId) {
|
|
1591
|
+
if (accountId) profileCache.delete(accountId);
|
|
1592
|
+
else profileCache.clear();
|
|
1593
|
+
}
|
|
1594
|
+
var dynamicChromeMajor, CHROME_MAJOR, VIEWPORTS, WEBGL_PROFILES, HARDWARE_CONCURRENCIES, DEVICE_MEMORIES, PLATFORM_VERSIONS, NOT_A_BRAND_VARIANTS, profileCache, rotationSalts;
|
|
1595
|
+
var init_fingerprint = __esm({
|
|
1596
|
+
"src/services/fingerprint.ts"() {
|
|
1597
|
+
"use strict";
|
|
1598
|
+
dynamicChromeMajor = 151;
|
|
1599
|
+
CHROME_MAJOR = 151;
|
|
1600
|
+
VIEWPORTS = [
|
|
1601
|
+
{ width: 1366, height: 768 },
|
|
1602
|
+
{ width: 1440, height: 900 },
|
|
1603
|
+
{ width: 1536, height: 864 },
|
|
1604
|
+
{ width: 1600, height: 900 },
|
|
1605
|
+
{ width: 1680, height: 1050 },
|
|
1606
|
+
{ width: 1920, height: 1080 },
|
|
1607
|
+
{ width: 1920, height: 1200 },
|
|
1608
|
+
{ width: 1280, height: 720 },
|
|
1609
|
+
{ width: 1280, height: 800 },
|
|
1610
|
+
{ width: 1536, height: 864 }
|
|
1611
|
+
];
|
|
1612
|
+
WEBGL_PROFILES = [
|
|
1613
|
+
{
|
|
1614
|
+
vendor: "Google Inc. (Intel)",
|
|
1615
|
+
renderer: "ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1616
|
+
},
|
|
1617
|
+
{
|
|
1618
|
+
vendor: "Google Inc. (Intel)",
|
|
1619
|
+
renderer: "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1620
|
+
},
|
|
1621
|
+
{
|
|
1622
|
+
vendor: "Google Inc. (Intel)",
|
|
1623
|
+
renderer: "ANGLE (Intel, Intel(R) UHD Graphics 770 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1624
|
+
},
|
|
1625
|
+
{
|
|
1626
|
+
vendor: "Google Inc. (NVIDIA)",
|
|
1627
|
+
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1628
|
+
},
|
|
1629
|
+
{
|
|
1630
|
+
vendor: "Google Inc. (NVIDIA)",
|
|
1631
|
+
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
vendor: "Google Inc. (NVIDIA)",
|
|
1635
|
+
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3080 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
vendor: "Google Inc. (NVIDIA)",
|
|
1639
|
+
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4060 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1640
|
+
},
|
|
1641
|
+
{
|
|
1642
|
+
vendor: "Google Inc. (NVIDIA)",
|
|
1643
|
+
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1644
|
+
},
|
|
1645
|
+
{
|
|
1646
|
+
vendor: "Google Inc. (NVIDIA)",
|
|
1647
|
+
renderer: "ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 SUPER Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1648
|
+
},
|
|
1649
|
+
{
|
|
1650
|
+
vendor: "Google Inc. (AMD)",
|
|
1651
|
+
renderer: "ANGLE (AMD, AMD Radeon RX 6600 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1652
|
+
},
|
|
1653
|
+
{
|
|
1654
|
+
vendor: "Google Inc. (AMD)",
|
|
1655
|
+
renderer: "ANGLE (AMD, AMD Radeon RX 7600 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1656
|
+
},
|
|
1657
|
+
{
|
|
1658
|
+
vendor: "Google Inc. (AMD)",
|
|
1659
|
+
renderer: "ANGLE (AMD, AMD Radeon RX 580 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
1660
|
+
}
|
|
1661
|
+
];
|
|
1662
|
+
HARDWARE_CONCURRENCIES = [4, 6, 8, 8, 8, 12, 16, 16, 24, 32];
|
|
1663
|
+
DEVICE_MEMORIES = [4, 8, 8, 8, 16, 16, 32];
|
|
1664
|
+
PLATFORM_VERSIONS = [
|
|
1665
|
+
{ platform: "Windows", platformVersion: "14.0.0", major: "10" },
|
|
1666
|
+
{ platform: "Windows", platformVersion: "15.0.0", major: "11" },
|
|
1667
|
+
{ platform: "Windows", platformVersion: "14.0.0", major: "10" },
|
|
1668
|
+
{ platform: "Windows", platformVersion: "15.0.0", major: "11" }
|
|
1669
|
+
];
|
|
1670
|
+
NOT_A_BRAND_VARIANTS = [
|
|
1671
|
+
{ brand: "Not/A)Brand", version: "99" },
|
|
1672
|
+
{ brand: "Not)A_Brand", version: "99" },
|
|
1673
|
+
{ brand: "Not/A)Brand", version: "8" },
|
|
1674
|
+
{ brand: "Not?A_Brand", version: "24" },
|
|
1675
|
+
{ brand: "Not/A)Brand", version: "99" }
|
|
1676
|
+
];
|
|
1677
|
+
profileCache = /* @__PURE__ */ new Map();
|
|
1678
|
+
rotationSalts = /* @__PURE__ */ new Map();
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1681
|
+
|
|
1682
|
+
// src/utils/timezone.ts
|
|
1683
|
+
function formatAsciiTimezone(date = /* @__PURE__ */ new Date()) {
|
|
1684
|
+
const dayName = DAYS[date.getDay()];
|
|
1685
|
+
const monthName = MONTHS[date.getMonth()];
|
|
1686
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
1687
|
+
const year = date.getFullYear();
|
|
1688
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
1689
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
1690
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
1691
|
+
const offsetMinutes = -date.getTimezoneOffset();
|
|
1692
|
+
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
1693
|
+
const absOffset = Math.abs(offsetMinutes);
|
|
1694
|
+
const offsetHours = String(Math.floor(absOffset / 60)).padStart(2, "0");
|
|
1695
|
+
const offsetMins = String(absOffset % 60).padStart(2, "0");
|
|
1696
|
+
const tzOffset = `GMT${sign}${offsetHours}${offsetMins}`;
|
|
1697
|
+
return `${dayName} ${monthName} ${day} ${year} ${hours}:${minutes}:${seconds} ${tzOffset}`;
|
|
1698
|
+
}
|
|
1699
|
+
function sanitizeHeaderForFetch(val) {
|
|
1700
|
+
if (typeof val !== "string") return "";
|
|
1701
|
+
return val.replace(/[^\x00-\xFF]/g, "");
|
|
1702
|
+
}
|
|
1703
|
+
var DAYS, MONTHS;
|
|
1704
|
+
var init_timezone = __esm({
|
|
1705
|
+
"src/utils/timezone.ts"() {
|
|
1706
|
+
"use strict";
|
|
1707
|
+
DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
1708
|
+
MONTHS = [
|
|
1709
|
+
"Jan",
|
|
1710
|
+
"Feb",
|
|
1711
|
+
"Mar",
|
|
1712
|
+
"Apr",
|
|
1713
|
+
"May",
|
|
1714
|
+
"Jun",
|
|
1715
|
+
"Jul",
|
|
1716
|
+
"Aug",
|
|
1717
|
+
"Sep",
|
|
1718
|
+
"Oct",
|
|
1719
|
+
"Nov",
|
|
1720
|
+
"Dec"
|
|
1721
|
+
];
|
|
1722
|
+
}
|
|
1723
|
+
});
|
|
1724
|
+
|
|
1725
|
+
// src/services/qwen-headers.ts
|
|
1726
|
+
import { v4 as uuidv4 } from "uuid";
|
|
1727
|
+
function getSystemAcceptLanguage(customLocale) {
|
|
1728
|
+
const locale = customLocale || getSystemLocale();
|
|
1729
|
+
const primary = locale.split("-")[0];
|
|
1730
|
+
if (locale.toLowerCase() === "en-us" || locale.toLowerCase() === "en") {
|
|
1731
|
+
return "en-US,en;q=0.9";
|
|
1732
|
+
}
|
|
1733
|
+
if (locale.toLowerCase().startsWith("pt")) {
|
|
1734
|
+
return "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7";
|
|
1735
|
+
}
|
|
1736
|
+
return `${locale},${primary};q=0.9,en-US;q=0.8,en;q=0.7`;
|
|
1737
|
+
}
|
|
1738
|
+
function getDefaultQwenUserAgent(major = getChromeMajor()) {
|
|
1739
|
+
return `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${major}.0.0.0 Safari/537.36`;
|
|
1740
|
+
}
|
|
1741
|
+
function updateQwenWebVersion(version) {
|
|
1742
|
+
if (version && typeof version === "string" && /^\d+\.\d+\.\d+/.test(version)) {
|
|
1743
|
+
dynamicWebVersion = version.trim();
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
function getQwenWebVersion() {
|
|
1747
|
+
return dynamicWebVersion || config.qwen.webVersion;
|
|
1748
|
+
}
|
|
1749
|
+
function updateQwenBxVersion(version) {
|
|
1750
|
+
if (version && typeof version === "string" && /^\d+\.\d+\.\d+/.test(version)) {
|
|
1751
|
+
dynamicBxVersion = version.trim();
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
function getQwenBxVersion() {
|
|
1755
|
+
return dynamicBxVersion || config.auth.bxV;
|
|
1756
|
+
}
|
|
1757
|
+
function buildQwenRequestHeaders(opts) {
|
|
1758
|
+
const headers = {
|
|
1759
|
+
...opts.extra ?? {},
|
|
1760
|
+
Accept: "application/json",
|
|
1761
|
+
"Accept-Language": opts.extra?.["Accept-Language"] || opts.acceptLanguage || getSystemAcceptLanguage(),
|
|
1762
|
+
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
1763
|
+
"Content-Type": "application/json",
|
|
1764
|
+
Cookie: opts.cookie,
|
|
1765
|
+
Origin: qwenOrigin(),
|
|
1766
|
+
Referer: opts.extra?.Referer ?? (opts.chatSessionId ? qwenUrl(`/c/${encodeURIComponent(opts.chatSessionId)}`) : qwenUrl("/")),
|
|
1767
|
+
"Sec-Fetch-Dest": "empty",
|
|
1768
|
+
"Sec-Fetch-Mode": "cors",
|
|
1769
|
+
"Sec-Fetch-Site": "same-origin",
|
|
1770
|
+
Connection: "keep-alive",
|
|
1771
|
+
"User-Agent": opts.userAgent || getDefaultQwenUserAgent(),
|
|
1772
|
+
"X-Request-Id": uuidv4(),
|
|
1773
|
+
"bx-v": opts.bxV || getQwenBxVersion(),
|
|
1774
|
+
source: "web",
|
|
1775
|
+
version: opts.version || getQwenWebVersion(),
|
|
1776
|
+
timezone: opts.extra?.timezone || opts.extra?.Timezone || formatAsciiTimezone(),
|
|
1777
|
+
Timezone: opts.extra?.Timezone || opts.extra?.timezone || formatAsciiTimezone(),
|
|
1778
|
+
// Use the real browser client-hints when captured (anti-hardcoded); fall
|
|
1779
|
+
// back to the static fingerprint otherwise.
|
|
1780
|
+
"sec-ch-ua": opts.secChUa || `"Google Chrome";v="${getChromeMajor()}", "Chromium";v="${getChromeMajor()}", "Not.A/Brand";v="99"`,
|
|
1781
|
+
"sec-ch-ua-mobile": opts.secChUaMobile || "?0",
|
|
1782
|
+
"sec-ch-ua-platform": opts.secChUaPlatform || '"Windows"'
|
|
1783
|
+
};
|
|
1784
|
+
const tokenMatch = opts.cookie?.match(/(?:^|;\s*)token=([^;]+)/);
|
|
1785
|
+
if (tokenMatch && !headers["Authorization"] && !headers["authorization"]) {
|
|
1786
|
+
const bearer = decodeURIComponent(tokenMatch[1].trim());
|
|
1787
|
+
if (bearer && bearer !== '""' && bearer !== "null") {
|
|
1788
|
+
headers["Authorization"] = `Bearer ${bearer}`;
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
if (config.qwen.sendBxUa) {
|
|
1792
|
+
if (opts.bxUa) headers["bx-ua"] = opts.bxUa;
|
|
1793
|
+
if (opts.bxUmidtoken) headers["bx-umidtoken"] = opts.bxUmidtoken;
|
|
1794
|
+
}
|
|
1795
|
+
return headers;
|
|
1796
|
+
}
|
|
1797
|
+
var dynamicWebVersion, dynamicBxVersion, QWEN_WEB_VERSION, DEFAULT_QWEN_USER_AGENT, QWEN_TIMEZONE_HEADER;
|
|
1798
|
+
var init_qwen_headers = __esm({
|
|
1799
|
+
"src/services/qwen-headers.ts"() {
|
|
1800
|
+
"use strict";
|
|
1801
|
+
init_qwen_url();
|
|
1802
|
+
init_config();
|
|
1803
|
+
init_fingerprint();
|
|
1804
|
+
init_timezone();
|
|
1805
|
+
dynamicWebVersion = null;
|
|
1806
|
+
dynamicBxVersion = null;
|
|
1807
|
+
QWEN_WEB_VERSION = config.qwen.webVersion;
|
|
1808
|
+
DEFAULT_QWEN_USER_AGENT = getDefaultQwenUserAgent(151);
|
|
1809
|
+
QWEN_TIMEZONE_HEADER = (/* @__PURE__ */ new Date()).toString().split(" (")[0];
|
|
1810
|
+
}
|
|
1811
|
+
});
|
|
1812
|
+
|
|
1449
1813
|
// src/core/logger.ts
|
|
1450
1814
|
import "dotenv/config";
|
|
1451
1815
|
function maskEmail(email) {
|
|
@@ -2200,237 +2564,31 @@ function getAccountCooldownInfo(accountId) {
|
|
|
2200
2564
|
err.message
|
|
2201
2565
|
);
|
|
2202
2566
|
}
|
|
2203
|
-
}
|
|
2204
|
-
return null;
|
|
2205
|
-
}
|
|
2206
|
-
return { onCooldown: true, remainingMs: remaining, reason: entry.reason };
|
|
2207
|
-
}
|
|
2208
|
-
function markAccountHeadersReady(accountId) {
|
|
2209
|
-
if (!accountId || accountId === "global") return;
|
|
2210
|
-
headersReadyAccounts.add(accountId);
|
|
2211
|
-
}
|
|
2212
|
-
function unmarkAccountHeadersReady(accountId) {
|
|
2213
|
-
if (!accountId) return;
|
|
2214
|
-
headersReadyAccounts.delete(accountId);
|
|
2215
|
-
}
|
|
2216
|
-
function isAccountHeadersReady(accountId) {
|
|
2217
|
-
return headersReadyAccounts.has(accountId);
|
|
2218
|
-
}
|
|
2219
|
-
var cooldowns, headersReadyAccounts;
|
|
2220
|
-
var init_account_manager = __esm({
|
|
2221
|
-
"src/core/account-manager.ts"() {
|
|
2222
|
-
"use strict";
|
|
2223
|
-
init_accounts();
|
|
2224
|
-
init_account_priority();
|
|
2225
|
-
init_logger();
|
|
2226
|
-
cooldowns = /* @__PURE__ */ new Map();
|
|
2227
|
-
headersReadyAccounts = /* @__PURE__ */ new Set();
|
|
2228
|
-
}
|
|
2229
|
-
});
|
|
2230
|
-
|
|
2231
|
-
// src/services/fingerprint.ts
|
|
2232
|
-
function mulberry32(seed) {
|
|
2233
|
-
return () => {
|
|
2234
|
-
seed |= 0;
|
|
2235
|
-
seed = seed + 1831565813 | 0;
|
|
2236
|
-
let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
|
|
2237
|
-
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
2238
|
-
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
2239
|
-
};
|
|
2240
|
-
}
|
|
2241
|
-
function seedFromString(value) {
|
|
2242
|
-
let hash = 0;
|
|
2243
|
-
for (let i = 0; i < value.length; i++) {
|
|
2244
|
-
hash = (hash << 5) - hash + value.charCodeAt(i) | 0;
|
|
2245
|
-
}
|
|
2246
|
-
return hash >>> 0;
|
|
2247
|
-
}
|
|
2248
|
-
function pick(rng, values) {
|
|
2249
|
-
return values[Math.floor(rng() * values.length)];
|
|
2250
|
-
}
|
|
2251
|
-
function randInt(rng, min, max) {
|
|
2252
|
-
return Math.floor(rng() * (max - min + 1)) + min;
|
|
2253
|
-
}
|
|
2254
|
-
function updateChromeMajor(major) {
|
|
2255
|
-
if (typeof major === "number" && major >= 100) {
|
|
2256
|
-
dynamicChromeMajor = major;
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
|
-
function getChromeMajor() {
|
|
2260
|
-
return dynamicChromeMajor;
|
|
2261
|
-
}
|
|
2262
|
-
function getSystemLocale() {
|
|
2263
|
-
return process.env.QWEN_LOCALE || (typeof Intl !== "undefined" && Intl.DateTimeFormat ? Intl.DateTimeFormat().resolvedOptions().locale : "") || "pt-BR";
|
|
2264
|
-
}
|
|
2265
|
-
function getLanguageProfiles(locale = getSystemLocale()) {
|
|
2266
|
-
const primary = locale.split("-")[0];
|
|
2267
|
-
if (primary === "en") {
|
|
2268
|
-
return [
|
|
2269
|
-
["en-US", "en"],
|
|
2270
|
-
["en-US", "en", "es"],
|
|
2271
|
-
["en", "en-US"],
|
|
2272
|
-
["en-US", "en;q=0.9"]
|
|
2273
|
-
];
|
|
2274
|
-
}
|
|
2275
|
-
return [
|
|
2276
|
-
[locale, primary, "en-US", "en"],
|
|
2277
|
-
[locale, primary, "en-US", "en", "es"],
|
|
2278
|
-
[locale, "en-US", "en", primary],
|
|
2279
|
-
[locale, primary, "en"],
|
|
2280
|
-
[locale, `${primary};q=0.9`, "en-US;q=0.8", "en;q=0.7"]
|
|
2281
|
-
];
|
|
2282
|
-
}
|
|
2283
|
-
function getFingerprintProfile(accountId) {
|
|
2284
|
-
const cached = profileCache.get(accountId);
|
|
2285
|
-
if (cached) return cached;
|
|
2286
|
-
const salt = rotationSalts.get(accountId) ?? 0;
|
|
2287
|
-
const seed = seedFromString(salt === 0 ? accountId : `${accountId}#r${salt}`);
|
|
2288
|
-
const rng = mulberry32(seed);
|
|
2289
|
-
const viewport = pick(rng, VIEWPORTS);
|
|
2290
|
-
const webgl = pick(rng, WEBGL_PROFILES);
|
|
2291
|
-
const languages = [...pick(rng, getLanguageProfiles())];
|
|
2292
|
-
const hardwareConcurrency = pick(rng, HARDWARE_CONCURRENCIES);
|
|
2293
|
-
const deviceMemory = pick(rng, DEVICE_MEMORIES);
|
|
2294
|
-
const platformInfo = pick(rng, PLATFORM_VERSIONS);
|
|
2295
|
-
const notABrand = pick(rng, NOT_A_BRAND_VARIANTS);
|
|
2296
|
-
const major = dynamicChromeMajor;
|
|
2297
|
-
const build = randInt(rng, 7300, 7600);
|
|
2298
|
-
const patch = randInt(rng, 0, 160);
|
|
2299
|
-
const chromeVersion = `${major}.0.${build}.${patch}`;
|
|
2300
|
-
const brands = [
|
|
2301
|
-
{ brand: notABrand.brand, version: notABrand.version },
|
|
2302
|
-
{ brand: "Google Chrome", version: String(major) },
|
|
2303
|
-
{ brand: "Chromium", version: String(major) }
|
|
2304
|
-
];
|
|
2305
|
-
const fullVersionList = [
|
|
2306
|
-
{ brand: notABrand.brand, version: chromeVersion },
|
|
2307
|
-
{ brand: "Google Chrome", version: chromeVersion },
|
|
2308
|
-
{ brand: "Chromium", version: chromeVersion }
|
|
2309
|
-
];
|
|
2310
|
-
const secChUa = brands.map((brand) => `"${brand.brand}";v="${brand.version}"`).join(", ");
|
|
2311
|
-
const userAgent = `Mozilla/5.0 (Windows NT ${platformInfo.major}.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`;
|
|
2312
|
-
const profile = {
|
|
2313
|
-
accountId,
|
|
2314
|
-
seed,
|
|
2315
|
-
userAgent,
|
|
2316
|
-
appVersion: userAgent.replace("Mozilla/", ""),
|
|
2317
|
-
chromeMajor: CHROME_MAJOR,
|
|
2318
|
-
chromeVersion,
|
|
2319
|
-
brands,
|
|
2320
|
-
fullVersionList,
|
|
2321
|
-
secChUa,
|
|
2322
|
-
platform: "Win32",
|
|
2323
|
-
platformVersion: platformInfo.platformVersion,
|
|
2324
|
-
architecture: "x86",
|
|
2325
|
-
bitness: "64",
|
|
2326
|
-
languages,
|
|
2327
|
-
locale: languages[0].split(";")[0],
|
|
2328
|
-
timezoneId: "America/Sao_Paulo",
|
|
2329
|
-
viewport,
|
|
2330
|
-
hardwareConcurrency,
|
|
2331
|
-
deviceMemory,
|
|
2332
|
-
webglVendor: webgl.vendor,
|
|
2333
|
-
webglRenderer: webgl.renderer,
|
|
2334
|
-
colorDepth: 24,
|
|
2335
|
-
pixelDepth: 24,
|
|
2336
|
-
canvasNoiseSeed: randInt(rng, 1, 2147483647),
|
|
2337
|
-
audioNoiseSeed: randInt(rng, 1, 2147483647),
|
|
2338
|
-
webglNoiseSeed: randInt(rng, 1, 2147483647),
|
|
2339
|
-
outerWidthOffset: randInt(rng, 0, 20),
|
|
2340
|
-
outerHeightOffset: randInt(rng, 75, 95)
|
|
2341
|
-
};
|
|
2342
|
-
profileCache.set(accountId, profile);
|
|
2343
|
-
return profile;
|
|
2567
|
+
}
|
|
2568
|
+
return null;
|
|
2569
|
+
}
|
|
2570
|
+
return { onCooldown: true, remainingMs: remaining, reason: entry.reason };
|
|
2344
2571
|
}
|
|
2345
|
-
function
|
|
2346
|
-
if (accountId
|
|
2347
|
-
|
|
2572
|
+
function markAccountHeadersReady(accountId) {
|
|
2573
|
+
if (!accountId || accountId === "global") return;
|
|
2574
|
+
headersReadyAccounts.add(accountId);
|
|
2348
2575
|
}
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2576
|
+
function unmarkAccountHeadersReady(accountId) {
|
|
2577
|
+
if (!accountId) return;
|
|
2578
|
+
headersReadyAccounts.delete(accountId);
|
|
2579
|
+
}
|
|
2580
|
+
function isAccountHeadersReady(accountId) {
|
|
2581
|
+
return headersReadyAccounts.has(accountId);
|
|
2582
|
+
}
|
|
2583
|
+
var cooldowns, headersReadyAccounts;
|
|
2584
|
+
var init_account_manager = __esm({
|
|
2585
|
+
"src/core/account-manager.ts"() {
|
|
2352
2586
|
"use strict";
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
{ width: 1536, height: 864 },
|
|
2359
|
-
{ width: 1600, height: 900 },
|
|
2360
|
-
{ width: 1680, height: 1050 },
|
|
2361
|
-
{ width: 1920, height: 1080 },
|
|
2362
|
-
{ width: 1920, height: 1200 },
|
|
2363
|
-
{ width: 1280, height: 720 },
|
|
2364
|
-
{ width: 1280, height: 800 },
|
|
2365
|
-
{ width: 1536, height: 864 }
|
|
2366
|
-
];
|
|
2367
|
-
WEBGL_PROFILES = [
|
|
2368
|
-
{
|
|
2369
|
-
vendor: "Google Inc. (Intel)",
|
|
2370
|
-
renderer: "ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2371
|
-
},
|
|
2372
|
-
{
|
|
2373
|
-
vendor: "Google Inc. (Intel)",
|
|
2374
|
-
renderer: "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2375
|
-
},
|
|
2376
|
-
{
|
|
2377
|
-
vendor: "Google Inc. (Intel)",
|
|
2378
|
-
renderer: "ANGLE (Intel, Intel(R) UHD Graphics 770 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2379
|
-
},
|
|
2380
|
-
{
|
|
2381
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2382
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2383
|
-
},
|
|
2384
|
-
{
|
|
2385
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2386
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2387
|
-
},
|
|
2388
|
-
{
|
|
2389
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2390
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3080 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2391
|
-
},
|
|
2392
|
-
{
|
|
2393
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2394
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4060 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2395
|
-
},
|
|
2396
|
-
{
|
|
2397
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2398
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2399
|
-
},
|
|
2400
|
-
{
|
|
2401
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2402
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 SUPER Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2403
|
-
},
|
|
2404
|
-
{
|
|
2405
|
-
vendor: "Google Inc. (AMD)",
|
|
2406
|
-
renderer: "ANGLE (AMD, AMD Radeon RX 6600 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2407
|
-
},
|
|
2408
|
-
{
|
|
2409
|
-
vendor: "Google Inc. (AMD)",
|
|
2410
|
-
renderer: "ANGLE (AMD, AMD Radeon RX 7600 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2411
|
-
},
|
|
2412
|
-
{
|
|
2413
|
-
vendor: "Google Inc. (AMD)",
|
|
2414
|
-
renderer: "ANGLE (AMD, AMD Radeon RX 580 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2415
|
-
}
|
|
2416
|
-
];
|
|
2417
|
-
HARDWARE_CONCURRENCIES = [4, 6, 8, 8, 8, 12, 16, 16, 24, 32];
|
|
2418
|
-
DEVICE_MEMORIES = [4, 8, 8, 8, 16, 16, 32];
|
|
2419
|
-
PLATFORM_VERSIONS = [
|
|
2420
|
-
{ platform: "Windows", platformVersion: "14.0.0", major: "10" },
|
|
2421
|
-
{ platform: "Windows", platformVersion: "15.0.0", major: "11" },
|
|
2422
|
-
{ platform: "Windows", platformVersion: "14.0.0", major: "10" },
|
|
2423
|
-
{ platform: "Windows", platformVersion: "15.0.0", major: "11" }
|
|
2424
|
-
];
|
|
2425
|
-
NOT_A_BRAND_VARIANTS = [
|
|
2426
|
-
{ brand: "Not/A)Brand", version: "99" },
|
|
2427
|
-
{ brand: "Not)A_Brand", version: "99" },
|
|
2428
|
-
{ brand: "Not/A)Brand", version: "8" },
|
|
2429
|
-
{ brand: "Not?A_Brand", version: "24" },
|
|
2430
|
-
{ brand: "Not/A)Brand", version: "99" }
|
|
2431
|
-
];
|
|
2432
|
-
profileCache = /* @__PURE__ */ new Map();
|
|
2433
|
-
rotationSalts = /* @__PURE__ */ new Map();
|
|
2587
|
+
init_accounts();
|
|
2588
|
+
init_account_priority();
|
|
2589
|
+
init_logger();
|
|
2590
|
+
cooldowns = /* @__PURE__ */ new Map();
|
|
2591
|
+
headersReadyAccounts = /* @__PURE__ */ new Set();
|
|
2434
2592
|
}
|
|
2435
2593
|
});
|
|
2436
2594
|
|
|
@@ -2513,69 +2671,357 @@ async function subtlePageActivity(page) {
|
|
|
2513
2671
|
target.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
|
|
2514
2672
|
target.dispatchEvent(new MouseEvent("mouseleave", { bubbles: true }));
|
|
2515
2673
|
}
|
|
2516
|
-
} catch {
|
|
2674
|
+
} catch {
|
|
2675
|
+
}
|
|
2676
|
+
}).catch(() => {
|
|
2677
|
+
});
|
|
2678
|
+
} catch (err) {
|
|
2679
|
+
if (page.isClosed()) return;
|
|
2680
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2681
|
+
if (msg.includes("Target page, context or browser has been closed") || msg.includes("Browser has been closed") || msg.includes("Target closed") || msg.includes("Target crashed") || msg.includes("Page crashed") || msg.includes("Connection closed")) {
|
|
2682
|
+
return;
|
|
2683
|
+
}
|
|
2684
|
+
throw err;
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
var sleep;
|
|
2688
|
+
var init_human_behavior = __esm({
|
|
2689
|
+
"src/services/human-behavior.ts"() {
|
|
2690
|
+
"use strict";
|
|
2691
|
+
sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2692
|
+
}
|
|
2693
|
+
});
|
|
2694
|
+
|
|
2695
|
+
// src/services/captcha-solver.ts
|
|
2696
|
+
function formatCaptchaLogValue(value) {
|
|
2697
|
+
if (typeof value === "string") {
|
|
2698
|
+
return JSON.stringify(value.replace(/\s+/g, " ").slice(0, 160));
|
|
2699
|
+
}
|
|
2700
|
+
return String(value);
|
|
2701
|
+
}
|
|
2702
|
+
function logBaxiaCaptcha(event, fields = {}, important = false) {
|
|
2703
|
+
if (!important && !captchaDebugEnabled) return;
|
|
2704
|
+
const suffix = Object.entries(fields).map(([key, value]) => `${key}=${formatCaptchaLogValue(value)}`).join(" ");
|
|
2705
|
+
const emoji = CAPTCHA_EVENT_EMOJI[event] ?? "\u2139\uFE0F";
|
|
2706
|
+
const line = `${emoji} [Captcha] ${event}${suffix ? ` | ${suffix}` : ""}`;
|
|
2707
|
+
if (important) {
|
|
2708
|
+
console.warn(line);
|
|
2709
|
+
} else {
|
|
2710
|
+
console.log(line);
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
function extractBaxiaChallengeUrl(body, baseUrl) {
|
|
2714
|
+
if (!body) return null;
|
|
2715
|
+
const normalized = body.replace(/\\u002f/gi, "/").replace(/\\\//g, "/").replace(/&/gi, "&");
|
|
2716
|
+
const candidates = normalized.match(
|
|
2717
|
+
/(?:https?:)?\/\/[^\s"'`\\<>()]*(?:_____tmd_____|x5secdata=)[^\s"'`\\<>()]*|\/[^\s"'`\\<>()]*(?:_____tmd_____|x5secdata=)[^\s"'`\\<>()]*/gi
|
|
2718
|
+
);
|
|
2719
|
+
if (!candidates) return null;
|
|
2720
|
+
let base;
|
|
2721
|
+
try {
|
|
2722
|
+
base = new URL(baseUrl);
|
|
2723
|
+
} catch {
|
|
2724
|
+
return null;
|
|
2725
|
+
}
|
|
2726
|
+
for (const candidate of candidates) {
|
|
2727
|
+
let url;
|
|
2728
|
+
try {
|
|
2729
|
+
url = new URL(candidate, base);
|
|
2730
|
+
} catch {
|
|
2731
|
+
continue;
|
|
2732
|
+
}
|
|
2733
|
+
if (url.protocol !== base.protocol || url.host !== base.host) continue;
|
|
2734
|
+
return url.toString();
|
|
2735
|
+
}
|
|
2736
|
+
return null;
|
|
2737
|
+
}
|
|
2738
|
+
async function findVisibleLocatorWithin(page, selectors, timeoutMs) {
|
|
2739
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
2740
|
+
while (true) {
|
|
2741
|
+
const found = await findVisibleLocator(page, selectors);
|
|
2742
|
+
if (found) return found;
|
|
2743
|
+
if (Date.now() >= deadline) return null;
|
|
2744
|
+
await sleep(Math.min(150, Math.max(1, deadline - Date.now())));
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
async function waitForHidden(locator, timeoutMs) {
|
|
2748
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
2749
|
+
while (true) {
|
|
2750
|
+
if (!await isVisible(locator)) return true;
|
|
2751
|
+
if (Date.now() >= deadline) return false;
|
|
2752
|
+
await sleep(Math.min(100, Math.max(1, deadline - Date.now())));
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
async function computeAliyunPuzzleOffset(page) {
|
|
2756
|
+
return page.evaluate(() => {
|
|
2757
|
+
const background = document.querySelector(
|
|
2758
|
+
"#aliyunCaptcha-img"
|
|
2759
|
+
);
|
|
2760
|
+
const piece = document.querySelector(
|
|
2761
|
+
"#aliyunCaptcha-puzzle"
|
|
2762
|
+
);
|
|
2763
|
+
if (!background || !piece) {
|
|
2764
|
+
return Promise.resolve({ ok: false, reason: "missing puzzle images" });
|
|
2765
|
+
}
|
|
2766
|
+
const compute = () => {
|
|
2767
|
+
try {
|
|
2768
|
+
const width = background.naturalWidth;
|
|
2769
|
+
const height = background.naturalHeight;
|
|
2770
|
+
const pieceWidth = piece.naturalWidth;
|
|
2771
|
+
const pieceHeight = piece.naturalHeight;
|
|
2772
|
+
if (!width || !height || !pieceWidth || !pieceHeight) {
|
|
2773
|
+
return { ok: false, reason: "image dimensions unavailable" };
|
|
2774
|
+
}
|
|
2775
|
+
const backgroundCanvas = document.createElement("canvas");
|
|
2776
|
+
backgroundCanvas.id = "captcha-solver-canvas";
|
|
2777
|
+
backgroundCanvas.width = width;
|
|
2778
|
+
backgroundCanvas.height = height;
|
|
2779
|
+
const backgroundContext = backgroundCanvas.getContext("2d");
|
|
2780
|
+
if (!backgroundContext) {
|
|
2781
|
+
return { ok: false, reason: "no background context" };
|
|
2782
|
+
}
|
|
2783
|
+
const pieceCanvas = document.createElement("canvas");
|
|
2784
|
+
pieceCanvas.id = "captcha-solver-canvas";
|
|
2785
|
+
pieceCanvas.width = pieceWidth;
|
|
2786
|
+
pieceCanvas.height = pieceHeight;
|
|
2787
|
+
const pieceContext = pieceCanvas.getContext("2d");
|
|
2788
|
+
if (!pieceContext) {
|
|
2789
|
+
return { ok: false, reason: "no piece context" };
|
|
2790
|
+
}
|
|
2791
|
+
try {
|
|
2792
|
+
backgroundContext.drawImage(background, 0, 0);
|
|
2793
|
+
} catch {
|
|
2794
|
+
return { ok: false, reason: "background canvas tainted" };
|
|
2795
|
+
}
|
|
2796
|
+
try {
|
|
2797
|
+
pieceContext.drawImage(piece, 0, 0);
|
|
2798
|
+
} catch {
|
|
2799
|
+
return { ok: false, reason: "puzzle canvas tainted" };
|
|
2800
|
+
}
|
|
2801
|
+
const backgroundData = backgroundContext.getImageData(
|
|
2802
|
+
0,
|
|
2803
|
+
0,
|
|
2804
|
+
width,
|
|
2805
|
+
height
|
|
2806
|
+
).data;
|
|
2807
|
+
const pieceData = pieceContext.getImageData(
|
|
2808
|
+
0,
|
|
2809
|
+
0,
|
|
2810
|
+
pieceWidth,
|
|
2811
|
+
pieceHeight
|
|
2812
|
+
).data;
|
|
2813
|
+
let pieceMinX = pieceWidth;
|
|
2814
|
+
let pieceMaxX = -1;
|
|
2815
|
+
let pieceMinY = pieceHeight;
|
|
2816
|
+
let pieceMaxY = -1;
|
|
2817
|
+
for (let y = 0; y < pieceHeight; y++) {
|
|
2818
|
+
for (let x = 0; x < pieceWidth; x++) {
|
|
2819
|
+
if (pieceData[(y * pieceWidth + x) * 4 + 3] > 100) {
|
|
2820
|
+
if (x < pieceMinX) pieceMinX = x;
|
|
2821
|
+
if (x > pieceMaxX) pieceMaxX = x;
|
|
2822
|
+
if (y < pieceMinY) pieceMinY = y;
|
|
2823
|
+
if (y > pieceMaxY) pieceMaxY = y;
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
const puzzleWidth = pieceMaxX - pieceMinX + 1;
|
|
2828
|
+
if (puzzleWidth <= 0) {
|
|
2829
|
+
return { ok: false, reason: "empty puzzle piece" };
|
|
2830
|
+
}
|
|
2831
|
+
const yStart = Math.max(1, Math.min(height - 2, pieceMinY + 5));
|
|
2832
|
+
const yEnd = Math.max(
|
|
2833
|
+
yStart,
|
|
2834
|
+
Math.min(height - 2, pieceMaxY - 5)
|
|
2835
|
+
);
|
|
2836
|
+
const columnGradients = new Float32Array(width);
|
|
2837
|
+
for (let x = 1; x < width - 1; x++) {
|
|
2838
|
+
let gradient = 0;
|
|
2839
|
+
for (let y = yStart; y <= yEnd; y++) {
|
|
2840
|
+
const left = (y * width + x - 1) * 4;
|
|
2841
|
+
const right = (y * width + x + 1) * 4;
|
|
2842
|
+
gradient += Math.abs(backgroundData[right] - backgroundData[left]) + Math.abs(backgroundData[right + 1] - backgroundData[left + 1]) + Math.abs(backgroundData[right + 2] - backgroundData[left + 2]);
|
|
2843
|
+
}
|
|
2844
|
+
columnGradients[x] = gradient;
|
|
2845
|
+
}
|
|
2846
|
+
let bestX = 0;
|
|
2847
|
+
let bestScore = 0;
|
|
2848
|
+
const minCandidateX = 30;
|
|
2849
|
+
const maxCandidateX = width - puzzleWidth - 20;
|
|
2850
|
+
for (let candidateX = minCandidateX; candidateX <= maxCandidateX; candidateX++) {
|
|
2851
|
+
let leftMax = 0;
|
|
2852
|
+
for (let dx = -2; dx <= 2; dx++) {
|
|
2853
|
+
const value = columnGradients[candidateX + pieceMinX + dx] || 0;
|
|
2854
|
+
if (value > leftMax) leftMax = value;
|
|
2855
|
+
}
|
|
2856
|
+
let rightMax = 0;
|
|
2857
|
+
for (let dx = -3; dx <= 1; dx++) {
|
|
2858
|
+
const value = columnGradients[candidateX + pieceMaxX + dx] || 0;
|
|
2859
|
+
if (value > rightMax) rightMax = value;
|
|
2860
|
+
}
|
|
2861
|
+
const score = Math.sqrt(leftMax * rightMax);
|
|
2862
|
+
if (score > bestScore) {
|
|
2863
|
+
bestScore = score;
|
|
2864
|
+
bestX = candidateX;
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
if (bestScore <= 0) {
|
|
2868
|
+
return { ok: false, reason: "no matching hole edge" };
|
|
2869
|
+
}
|
|
2870
|
+
return {
|
|
2871
|
+
ok: true,
|
|
2872
|
+
offsetX: bestX - pieceMinX,
|
|
2873
|
+
naturalWidth: width
|
|
2874
|
+
};
|
|
2875
|
+
} catch (error) {
|
|
2876
|
+
return {
|
|
2877
|
+
ok: false,
|
|
2878
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
2879
|
+
};
|
|
2880
|
+
}
|
|
2881
|
+
};
|
|
2882
|
+
return new Promise((resolve) => {
|
|
2883
|
+
if (background.complete && piece.complete) {
|
|
2884
|
+
resolve(compute());
|
|
2885
|
+
return;
|
|
2886
|
+
}
|
|
2887
|
+
let settled = false;
|
|
2888
|
+
const finish = () => {
|
|
2889
|
+
if (settled) return;
|
|
2890
|
+
settled = true;
|
|
2891
|
+
resolve(compute());
|
|
2892
|
+
};
|
|
2893
|
+
const fail = () => {
|
|
2894
|
+
if (settled) return;
|
|
2895
|
+
settled = true;
|
|
2896
|
+
resolve({ ok: false, reason: "puzzle image load error" });
|
|
2897
|
+
};
|
|
2898
|
+
background.addEventListener("load", finish, { once: true });
|
|
2899
|
+
piece.addEventListener("load", finish, { once: true });
|
|
2900
|
+
background.addEventListener("error", fail, { once: true });
|
|
2901
|
+
piece.addEventListener("error", fail, { once: true });
|
|
2902
|
+
setTimeout(() => {
|
|
2903
|
+
if (settled) return;
|
|
2904
|
+
settled = true;
|
|
2905
|
+
resolve({ ok: false, reason: "puzzle image load timeout" });
|
|
2906
|
+
}, 2e3);
|
|
2907
|
+
});
|
|
2908
|
+
});
|
|
2909
|
+
}
|
|
2910
|
+
async function solveAliyunWafCaptcha(page, options = {}) {
|
|
2911
|
+
const waitForMs = Math.max(0, options.waitForMs ?? 0);
|
|
2912
|
+
const maxAttempts = Math.max(
|
|
2913
|
+
1,
|
|
2914
|
+
Math.min(5, options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS)
|
|
2915
|
+
);
|
|
2916
|
+
const retryDelayMs = Math.max(
|
|
2917
|
+
0,
|
|
2918
|
+
options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS
|
|
2919
|
+
);
|
|
2920
|
+
const settleMs = Math.max(0, options.settleMs ?? DEFAULT_SETTLE_MS);
|
|
2921
|
+
const sliderTimeoutMs = Math.max(
|
|
2922
|
+
500,
|
|
2923
|
+
options.sliderTimeoutMs ?? DEFAULT_SLIDER_TIMEOUT_MS
|
|
2924
|
+
);
|
|
2925
|
+
const detected = await findVisibleLocatorWithin(
|
|
2926
|
+
page,
|
|
2927
|
+
ALIYUN_WAF_BLOCK_SELECTORS,
|
|
2928
|
+
waitForMs
|
|
2929
|
+
);
|
|
2930
|
+
if (!detected) return false;
|
|
2931
|
+
return withCaptchaMouseLock(async () => {
|
|
2932
|
+
const block = detected.locator;
|
|
2933
|
+
if (!await isVisible(block)) return false;
|
|
2934
|
+
logBaxiaCaptcha("aliyun_detected", { selector: detected.selector });
|
|
2935
|
+
let lastReason = "unknown";
|
|
2936
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
2937
|
+
try {
|
|
2938
|
+
const offset = await computeAliyunPuzzleOffset(page);
|
|
2939
|
+
if (!offset.ok || typeof offset.offsetX !== "number" || typeof offset.naturalWidth !== "number" || offset.naturalWidth <= 0) {
|
|
2940
|
+
lastReason = offset.reason || "offset_unavailable";
|
|
2941
|
+
logBaxiaCaptcha("aliyun_offset_failed", {
|
|
2942
|
+
attempt,
|
|
2943
|
+
reason: lastReason
|
|
2944
|
+
});
|
|
2945
|
+
} else {
|
|
2946
|
+
const slider = page.locator(ALIYUN_PUZZLE_SLIDER_SELECTOR).first();
|
|
2947
|
+
const track = page.locator(ALIYUN_PUZZLE_TRACK_SELECTOR).first();
|
|
2948
|
+
await slider.waitFor({ state: "visible", timeout: sliderTimeoutMs });
|
|
2949
|
+
const [sliderBox, trackBox] = await Promise.all([
|
|
2950
|
+
slider.boundingBox(),
|
|
2951
|
+
track.boundingBox()
|
|
2952
|
+
]);
|
|
2953
|
+
if (!sliderBox || !trackBox || trackBox.width <= 0) {
|
|
2954
|
+
lastReason = "bounds_unavailable";
|
|
2955
|
+
logBaxiaCaptcha("aliyun_offset_failed", {
|
|
2956
|
+
attempt,
|
|
2957
|
+
reason: lastReason
|
|
2958
|
+
});
|
|
2959
|
+
} else {
|
|
2960
|
+
const scale = trackBox.width / offset.naturalWidth;
|
|
2961
|
+
const dragDistance = Math.round(offset.offsetX * scale);
|
|
2962
|
+
logBaxiaCaptcha("aliyun_geometry", {
|
|
2963
|
+
attempt,
|
|
2964
|
+
offset: offset.offsetX,
|
|
2965
|
+
scale: Number(scale.toFixed(2)),
|
|
2966
|
+
distance: dragDistance
|
|
2967
|
+
});
|
|
2968
|
+
if (dragDistance <= 0) {
|
|
2969
|
+
lastReason = "non_positive_distance";
|
|
2970
|
+
} else {
|
|
2971
|
+
const startX = sliderBox.x + sliderBox.width / 2;
|
|
2972
|
+
const startY = sliderBox.y + sliderBox.height / 2;
|
|
2973
|
+
await humanDrag(
|
|
2974
|
+
page,
|
|
2975
|
+
startX,
|
|
2976
|
+
startY,
|
|
2977
|
+
startX + dragDistance,
|
|
2978
|
+
startY
|
|
2979
|
+
);
|
|
2980
|
+
if (await waitForHidden(block, settleMs)) {
|
|
2981
|
+
logBaxiaCaptcha(
|
|
2982
|
+
"aliyun_solve_succeeded",
|
|
2983
|
+
{ attempt, distance: dragDistance },
|
|
2984
|
+
true
|
|
2985
|
+
);
|
|
2986
|
+
return true;
|
|
2987
|
+
}
|
|
2988
|
+
lastReason = "not_solved";
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
} catch (error) {
|
|
2993
|
+
lastReason = error instanceof Error ? error.name : "UnknownError";
|
|
2994
|
+
logBaxiaCaptcha("aliyun_offset_failed", {
|
|
2995
|
+
attempt,
|
|
2996
|
+
error: lastReason,
|
|
2997
|
+
detail: sanitizeCaptchaErrorDetail(error)
|
|
2998
|
+
});
|
|
2999
|
+
}
|
|
3000
|
+
if (attempt < maxAttempts && retryDelayMs > 0) {
|
|
3001
|
+
await sleep(retryDelayMs);
|
|
2517
3002
|
}
|
|
2518
|
-
}).catch(() => {
|
|
2519
|
-
});
|
|
2520
|
-
} catch (err) {
|
|
2521
|
-
if (page.isClosed()) return;
|
|
2522
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2523
|
-
if (msg.includes("Target page, context or browser has been closed") || msg.includes("Browser has been closed") || msg.includes("Target closed") || msg.includes("Target crashed") || msg.includes("Page crashed") || msg.includes("Connection closed")) {
|
|
2524
|
-
return;
|
|
2525
3003
|
}
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
}
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2534
|
-
}
|
|
2535
|
-
});
|
|
2536
|
-
|
|
2537
|
-
// src/services/captcha-solver.ts
|
|
2538
|
-
function formatCaptchaLogValue(value) {
|
|
2539
|
-
if (typeof value === "string") {
|
|
2540
|
-
return JSON.stringify(value.replace(/\s+/g, " ").slice(0, 160));
|
|
2541
|
-
}
|
|
2542
|
-
return String(value);
|
|
3004
|
+
logBaxiaCaptcha(
|
|
3005
|
+
"aliyun_solve_failed",
|
|
3006
|
+
{ attempts: maxAttempts, reason: lastReason },
|
|
3007
|
+
true
|
|
3008
|
+
);
|
|
3009
|
+
return false;
|
|
3010
|
+
});
|
|
2543
3011
|
}
|
|
2544
|
-
function
|
|
2545
|
-
if (
|
|
2546
|
-
const
|
|
2547
|
-
const
|
|
2548
|
-
const
|
|
2549
|
-
if (
|
|
2550
|
-
|
|
2551
|
-
} else {
|
|
2552
|
-
console.log(line);
|
|
3012
|
+
async function solveVisibleCaptcha(page, options = {}) {
|
|
3013
|
+
if (typeof page.isClosed === "function" && page.isClosed()) return false;
|
|
3014
|
+
const totalWaitMs = Math.max(0, options.waitForMs ?? 0);
|
|
3015
|
+
const aliyunWaitMs = Math.min(totalWaitMs, ALIYUN_PROBE_MAX_WAIT_MS);
|
|
3016
|
+
const startedAt = Date.now();
|
|
3017
|
+
if (await solveAliyunWafCaptcha(page, { ...options, waitForMs: aliyunWaitMs })) {
|
|
3018
|
+
return true;
|
|
2553
3019
|
}
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
const normalized = body.replace(/\\u002f/gi, "/").replace(/\\\//g, "/").replace(/&/gi, "&");
|
|
2558
|
-
const candidates = normalized.match(
|
|
2559
|
-
/(?:https?:)?\/\/[^\s"'`\\<>()]*(?:_____tmd_____|x5secdata=)[^\s"'`\\<>()]*|\/[^\s"'`\\<>()]*(?:_____tmd_____|x5secdata=)[^\s"'`\\<>()]*/gi
|
|
3020
|
+
const remainingWaitMs = Math.max(
|
|
3021
|
+
0,
|
|
3022
|
+
totalWaitMs - (Date.now() - startedAt)
|
|
2560
3023
|
);
|
|
2561
|
-
|
|
2562
|
-
let base;
|
|
2563
|
-
try {
|
|
2564
|
-
base = new URL(baseUrl);
|
|
2565
|
-
} catch {
|
|
2566
|
-
return null;
|
|
2567
|
-
}
|
|
2568
|
-
for (const candidate of candidates) {
|
|
2569
|
-
let url;
|
|
2570
|
-
try {
|
|
2571
|
-
url = new URL(candidate, base);
|
|
2572
|
-
} catch {
|
|
2573
|
-
continue;
|
|
2574
|
-
}
|
|
2575
|
-
if (url.protocol !== base.protocol || url.host !== base.host) continue;
|
|
2576
|
-
return url.toString();
|
|
2577
|
-
}
|
|
2578
|
-
return null;
|
|
3024
|
+
return solveBaxiaCaptcha(page, { ...options, waitForMs: remainingWaitMs });
|
|
2579
3025
|
}
|
|
2580
3026
|
async function isVisible(locator) {
|
|
2581
3027
|
return locator.isVisible().catch(() => false);
|
|
@@ -2846,7 +3292,7 @@ function startBaxiaCaptchaWatcher(page, timeoutMs, options = {}) {
|
|
|
2846
3292
|
promise
|
|
2847
3293
|
};
|
|
2848
3294
|
}
|
|
2849
|
-
var BAXIA_DIALOG_SELECTOR, BAXIA_CONTENT_SELECTOR, CAPTCHA_EVENT_EMOJI, captchaDebugEnabled, BAXIA_IFRAME_SELECTORS, BAXIA_DOCUMENT_SELECTORS, BAXIA_IFRAME_SELECTOR, BAXIA_SLIDER_SELECTOR, BAXIA_TRACK_SELECTOR, BAXIA_SUCCESS_SELECTOR, BAXIA_RELOAD_SELECTOR, DEFAULT_MAX_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_SETTLE_MS, DEFAULT_SLIDER_TIMEOUT_MS, captchaMouseLock;
|
|
3295
|
+
var BAXIA_DIALOG_SELECTOR, BAXIA_CONTENT_SELECTOR, CAPTCHA_EVENT_EMOJI, captchaDebugEnabled, BAXIA_IFRAME_SELECTORS, BAXIA_DOCUMENT_SELECTORS, BAXIA_IFRAME_SELECTOR, BAXIA_SLIDER_SELECTOR, BAXIA_TRACK_SELECTOR, BAXIA_SUCCESS_SELECTOR, BAXIA_RELOAD_SELECTOR, DEFAULT_MAX_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_SETTLE_MS, DEFAULT_SLIDER_TIMEOUT_MS, ALIYUN_WAF_CAPTCHA_SELECTOR, ALIYUN_WAF_CAPTCHA_WIDGET, ALIYUN_WAF_BLOCK_SELECTORS, ALIYUN_PUZZLE_SLIDER_SELECTOR, ALIYUN_PUZZLE_TRACK_SELECTOR, ALIYUN_PROBE_MAX_WAIT_MS, captchaMouseLock;
|
|
2850
3296
|
var init_captcha_solver = __esm({
|
|
2851
3297
|
"src/services/captcha-solver.ts"() {
|
|
2852
3298
|
"use strict";
|
|
@@ -2872,14 +3318,20 @@ var init_captcha_solver = __esm({
|
|
|
2872
3318
|
solve_failed: "\u274C",
|
|
2873
3319
|
recovery_succeeded: "\u2705",
|
|
2874
3320
|
recovery_not_solved: "\u26A0\uFE0F",
|
|
2875
|
-
recovery_failed: "\u274C"
|
|
3321
|
+
recovery_failed: "\u274C",
|
|
3322
|
+
aliyun_detected: "\u{1F9E9}",
|
|
3323
|
+
aliyun_offset_failed: "\u{1F4D0}",
|
|
3324
|
+
aliyun_geometry: "\u{1F4D0}",
|
|
3325
|
+
aliyun_solve_succeeded: "\u2705",
|
|
3326
|
+
aliyun_solve_failed: "\u274C"
|
|
2876
3327
|
};
|
|
2877
3328
|
captchaDebugEnabled = process.env.CAPTCHA_DEBUG === "true";
|
|
2878
3329
|
BAXIA_IFRAME_SELECTORS = [
|
|
2879
3330
|
`${BAXIA_DIALOG_SELECTOR} ${BAXIA_CONTENT_SELECTOR} iframe`,
|
|
2880
3331
|
`${BAXIA_CONTENT_SELECTOR} iframe`,
|
|
2881
3332
|
"iframe#baxia-dialog-content",
|
|
2882
|
-
'iframe[src*="_____tmd_____/punish"]'
|
|
3333
|
+
'iframe[src*="_____tmd_____/punish"]',
|
|
3334
|
+
'iframe[src*="nocaptcha"]'
|
|
2883
3335
|
];
|
|
2884
3336
|
BAXIA_DOCUMENT_SELECTORS = [
|
|
2885
3337
|
"#nocaptcha",
|
|
@@ -2887,41 +3339,71 @@ var init_captcha_solver = __esm({
|
|
|
2887
3339
|
"#baxia-punish"
|
|
2888
3340
|
];
|
|
2889
3341
|
BAXIA_IFRAME_SELECTOR = BAXIA_IFRAME_SELECTORS.join(", ");
|
|
2890
|
-
BAXIA_SLIDER_SELECTOR =
|
|
2891
|
-
BAXIA_TRACK_SELECTOR =
|
|
3342
|
+
BAXIA_SLIDER_SELECTOR = '#nc_1_n1z, .nc_1_n1z, .btn_slide, .nc_iconfont.btn_slide, span[id*="_n1z"], .nc_wrapper .btn_slide, ._nc .btn_slide, .nc-container .btn_slide';
|
|
3343
|
+
BAXIA_TRACK_SELECTOR = '#nc_1_n1t, .nc_scale, span[id*="_n1t"], .nc_wrapper .nc_scale, ._nc .nc_scale, .nc-container .nc_scale';
|
|
2892
3344
|
BAXIA_SUCCESS_SELECTOR = '.btn_ok, .nc_ok, .nc_success, .nc_result, .nc_wrapper.nc-success, .nc_wrapper.success, [data-nc-lang="SUCCESS"], [data-nc-lang="success"], #nc-loading-circle';
|
|
2893
3345
|
BAXIA_RELOAD_SELECTOR = '#nc_1_refresh1, .errloading a, .nc-container .errloading a, .btn_refresh, .clickCaptcha_text .btn_refresh, [data-nc-lang="REFRESH"], a[id*="refresh"]';
|
|
2894
3346
|
DEFAULT_MAX_ATTEMPTS = 3;
|
|
2895
3347
|
DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
2896
3348
|
DEFAULT_SETTLE_MS = 2e3;
|
|
2897
3349
|
DEFAULT_SLIDER_TIMEOUT_MS = 8e3;
|
|
3350
|
+
ALIYUN_WAF_CAPTCHA_SELECTOR = "#waf_nc_block";
|
|
3351
|
+
ALIYUN_WAF_CAPTCHA_WIDGET = "#aliyunCaptcha-window-embed";
|
|
3352
|
+
ALIYUN_WAF_BLOCK_SELECTORS = [
|
|
3353
|
+
ALIYUN_WAF_CAPTCHA_SELECTOR,
|
|
3354
|
+
ALIYUN_WAF_CAPTCHA_WIDGET
|
|
3355
|
+
];
|
|
3356
|
+
ALIYUN_PUZZLE_SLIDER_SELECTOR = "#aliyunCaptcha-sliding-slider";
|
|
3357
|
+
ALIYUN_PUZZLE_TRACK_SELECTOR = "#aliyunCaptcha-sliding-body";
|
|
3358
|
+
ALIYUN_PROBE_MAX_WAIT_MS = 2e3;
|
|
2898
3359
|
captchaMouseLock = Promise.resolve();
|
|
2899
3360
|
}
|
|
2900
3361
|
});
|
|
2901
3362
|
|
|
2902
|
-
// src/services/qwen-url.ts
|
|
2903
|
-
function qwenUrl(path6 = "") {
|
|
2904
|
-
const normalizedPath = path6.replace(/^\/+/, "");
|
|
2905
|
-
return normalizedPath ? `${QWEN_BASE_URL}/${normalizedPath}` : QWEN_BASE_URL;
|
|
2906
|
-
}
|
|
2907
|
-
function qwenOrigin() {
|
|
2908
|
-
return QWEN_ORIGIN;
|
|
2909
|
-
}
|
|
2910
|
-
var QWEN_BASE_URL, QWEN_ORIGIN;
|
|
2911
|
-
var init_qwen_url = __esm({
|
|
2912
|
-
"src/services/qwen-url.ts"() {
|
|
2913
|
-
"use strict";
|
|
2914
|
-
init_config();
|
|
2915
|
-
QWEN_BASE_URL = config.qwen.baseUrl.trim().replace(/\/+$/, "");
|
|
2916
|
-
QWEN_ORIGIN = new URL(QWEN_BASE_URL).origin;
|
|
2917
|
-
}
|
|
2918
|
-
});
|
|
2919
|
-
|
|
2920
3363
|
// src/core/waf-isolation.ts
|
|
2921
3364
|
function setWafContextResetListener(fn) {
|
|
2922
3365
|
contextResetListener = fn;
|
|
2923
3366
|
}
|
|
2924
|
-
|
|
3367
|
+
function getState(accountId) {
|
|
3368
|
+
let state = states.get(accountId);
|
|
3369
|
+
if (!state) {
|
|
3370
|
+
state = { consecutiveHardBlocks: 0, lastBlockAt: 0 };
|
|
3371
|
+
states.set(accountId, state);
|
|
3372
|
+
}
|
|
3373
|
+
return state;
|
|
3374
|
+
}
|
|
3375
|
+
function recordWafHardBlock(accountId) {
|
|
3376
|
+
const state = getState(accountId);
|
|
3377
|
+
state.consecutiveHardBlocks += 1;
|
|
3378
|
+
state.lastBlockAt = Date.now();
|
|
3379
|
+
const base = config.captcha.accountCooldownMs;
|
|
3380
|
+
const cap = config.captcha.hardBlockMaxCooldownMs;
|
|
3381
|
+
const exponent = Math.min(
|
|
3382
|
+
state.consecutiveHardBlocks - 1,
|
|
3383
|
+
MAX_CONSECUTIVE_FOR_ESCALATION
|
|
3384
|
+
);
|
|
3385
|
+
const cooldownMs = Math.min(cap, base * Math.pow(ESCALATION_FACTOR, exponent));
|
|
3386
|
+
if (cooldownMs > 0) {
|
|
3387
|
+
markAccountRateLimited(accountId, cooldownMs, "WafChallenge");
|
|
3388
|
+
}
|
|
3389
|
+
rotateFingerprintSeed(accountId);
|
|
3390
|
+
logger.warn(
|
|
3391
|
+
`[WafIsolation] Hard WAF block on ${accountId}: fingerprint rotated (streak ${state.consecutiveHardBlocks}), quarantined ${Math.round(cooldownMs / 1e3)}s`
|
|
3392
|
+
);
|
|
3393
|
+
if (contextResetListener) {
|
|
3394
|
+
void Promise.resolve(contextResetListener(accountId)).catch((error) => {
|
|
3395
|
+
logger.warn(
|
|
3396
|
+
`[WafIsolation] Context reset listener failed for ${accountId}: ${error instanceof Error ? error.message : String(error)}`
|
|
3397
|
+
);
|
|
3398
|
+
});
|
|
3399
|
+
}
|
|
3400
|
+
return {
|
|
3401
|
+
cooldownMs,
|
|
3402
|
+
fingerprintRotated: true,
|
|
3403
|
+
escalated: state.consecutiveHardBlocks > 1
|
|
3404
|
+
};
|
|
3405
|
+
}
|
|
3406
|
+
var ESCALATION_FACTOR, MAX_CONSECUTIVE_FOR_ESCALATION, states, contextResetListener;
|
|
2925
3407
|
var init_waf_isolation = __esm({
|
|
2926
3408
|
"src/core/waf-isolation.ts"() {
|
|
2927
3409
|
"use strict";
|
|
@@ -2929,132 +3411,13 @@ var init_waf_isolation = __esm({
|
|
|
2929
3411
|
init_logger();
|
|
2930
3412
|
init_account_manager();
|
|
2931
3413
|
init_fingerprint();
|
|
3414
|
+
ESCALATION_FACTOR = 2;
|
|
3415
|
+
MAX_CONSECUTIVE_FOR_ESCALATION = 4;
|
|
3416
|
+
states = /* @__PURE__ */ new Map();
|
|
2932
3417
|
contextResetListener = null;
|
|
2933
3418
|
}
|
|
2934
3419
|
});
|
|
2935
3420
|
|
|
2936
|
-
// src/utils/timezone.ts
|
|
2937
|
-
function formatAsciiTimezone(date = /* @__PURE__ */ new Date()) {
|
|
2938
|
-
const dayName = DAYS[date.getDay()];
|
|
2939
|
-
const monthName = MONTHS[date.getMonth()];
|
|
2940
|
-
const day = String(date.getDate()).padStart(2, "0");
|
|
2941
|
-
const year = date.getFullYear();
|
|
2942
|
-
const hours = String(date.getHours()).padStart(2, "0");
|
|
2943
|
-
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
2944
|
-
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
2945
|
-
const offsetMinutes = -date.getTimezoneOffset();
|
|
2946
|
-
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
2947
|
-
const absOffset = Math.abs(offsetMinutes);
|
|
2948
|
-
const offsetHours = String(Math.floor(absOffset / 60)).padStart(2, "0");
|
|
2949
|
-
const offsetMins = String(absOffset % 60).padStart(2, "0");
|
|
2950
|
-
const tzOffset = `GMT${sign}${offsetHours}${offsetMins}`;
|
|
2951
|
-
return `${dayName} ${monthName} ${day} ${year} ${hours}:${minutes}:${seconds} ${tzOffset}`;
|
|
2952
|
-
}
|
|
2953
|
-
function sanitizeHeaderForFetch(val) {
|
|
2954
|
-
if (typeof val !== "string") return "";
|
|
2955
|
-
return val.replace(/[^\x00-\xFF]/g, "");
|
|
2956
|
-
}
|
|
2957
|
-
var DAYS, MONTHS;
|
|
2958
|
-
var init_timezone = __esm({
|
|
2959
|
-
"src/utils/timezone.ts"() {
|
|
2960
|
-
"use strict";
|
|
2961
|
-
DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
2962
|
-
MONTHS = [
|
|
2963
|
-
"Jan",
|
|
2964
|
-
"Feb",
|
|
2965
|
-
"Mar",
|
|
2966
|
-
"Apr",
|
|
2967
|
-
"May",
|
|
2968
|
-
"Jun",
|
|
2969
|
-
"Jul",
|
|
2970
|
-
"Aug",
|
|
2971
|
-
"Sep",
|
|
2972
|
-
"Oct",
|
|
2973
|
-
"Nov",
|
|
2974
|
-
"Dec"
|
|
2975
|
-
];
|
|
2976
|
-
}
|
|
2977
|
-
});
|
|
2978
|
-
|
|
2979
|
-
// src/services/qwen-headers.ts
|
|
2980
|
-
import { v4 as uuidv4 } from "uuid";
|
|
2981
|
-
function getSystemAcceptLanguage(customLocale) {
|
|
2982
|
-
const locale = customLocale || getSystemLocale();
|
|
2983
|
-
const primary = locale.split("-")[0];
|
|
2984
|
-
if (locale.toLowerCase() === "en-us" || locale.toLowerCase() === "en") {
|
|
2985
|
-
return "en-US,en;q=0.9";
|
|
2986
|
-
}
|
|
2987
|
-
if (locale.toLowerCase().startsWith("pt")) {
|
|
2988
|
-
return "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7";
|
|
2989
|
-
}
|
|
2990
|
-
return `${locale},${primary};q=0.9,en-US;q=0.8,en;q=0.7`;
|
|
2991
|
-
}
|
|
2992
|
-
function getDefaultQwenUserAgent(major = getChromeMajor()) {
|
|
2993
|
-
return `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${major}.0.0.0 Safari/537.36`;
|
|
2994
|
-
}
|
|
2995
|
-
function updateQwenWebVersion(version) {
|
|
2996
|
-
if (version && typeof version === "string" && /^\d+\.\d+\.\d+/.test(version)) {
|
|
2997
|
-
dynamicWebVersion = version.trim();
|
|
2998
|
-
}
|
|
2999
|
-
}
|
|
3000
|
-
function getQwenWebVersion() {
|
|
3001
|
-
return dynamicWebVersion || config.qwen.webVersion;
|
|
3002
|
-
}
|
|
3003
|
-
function buildQwenRequestHeaders(opts) {
|
|
3004
|
-
const headers = {
|
|
3005
|
-
...opts.extra ?? {},
|
|
3006
|
-
Accept: "application/json",
|
|
3007
|
-
"Accept-Language": opts.extra?.["Accept-Language"] || opts.acceptLanguage || getSystemAcceptLanguage(),
|
|
3008
|
-
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
3009
|
-
"Content-Type": "application/json",
|
|
3010
|
-
Cookie: opts.cookie,
|
|
3011
|
-
Origin: qwenOrigin(),
|
|
3012
|
-
Referer: opts.extra?.Referer ?? (opts.chatSessionId ? qwenUrl(`/c/${encodeURIComponent(opts.chatSessionId)}`) : qwenUrl("/")),
|
|
3013
|
-
"Sec-Fetch-Dest": "empty",
|
|
3014
|
-
"Sec-Fetch-Mode": "cors",
|
|
3015
|
-
"Sec-Fetch-Site": "same-origin",
|
|
3016
|
-
Connection: "keep-alive",
|
|
3017
|
-
"User-Agent": opts.userAgent || getDefaultQwenUserAgent(),
|
|
3018
|
-
"X-Request-Id": uuidv4(),
|
|
3019
|
-
"bx-v": opts.bxV || "2.5.37",
|
|
3020
|
-
source: "web",
|
|
3021
|
-
version: opts.version || getQwenWebVersion(),
|
|
3022
|
-
timezone: opts.extra?.timezone || opts.extra?.Timezone || formatAsciiTimezone(),
|
|
3023
|
-
Timezone: opts.extra?.Timezone || opts.extra?.timezone || formatAsciiTimezone(),
|
|
3024
|
-
// Use the real browser client-hints when captured (anti-hardcoded); fall
|
|
3025
|
-
// back to the static fingerprint otherwise.
|
|
3026
|
-
"sec-ch-ua": opts.secChUa || `"Google Chrome";v="${getChromeMajor()}", "Chromium";v="${getChromeMajor()}", "Not.A/Brand";v="99"`,
|
|
3027
|
-
"sec-ch-ua-mobile": opts.secChUaMobile || "?0",
|
|
3028
|
-
"sec-ch-ua-platform": opts.secChUaPlatform || '"Windows"'
|
|
3029
|
-
};
|
|
3030
|
-
const tokenMatch = opts.cookie?.match(/(?:^|;\s*)token=([^;]+)/);
|
|
3031
|
-
if (tokenMatch && !headers["Authorization"] && !headers["authorization"]) {
|
|
3032
|
-
const bearer = decodeURIComponent(tokenMatch[1].trim());
|
|
3033
|
-
if (bearer && bearer !== '""' && bearer !== "null") {
|
|
3034
|
-
headers["Authorization"] = `Bearer ${bearer}`;
|
|
3035
|
-
}
|
|
3036
|
-
}
|
|
3037
|
-
if (config.qwen.sendBxUa) {
|
|
3038
|
-
if (opts.bxUa) headers["bx-ua"] = opts.bxUa;
|
|
3039
|
-
if (opts.bxUmidtoken) headers["bx-umidtoken"] = opts.bxUmidtoken;
|
|
3040
|
-
}
|
|
3041
|
-
return headers;
|
|
3042
|
-
}
|
|
3043
|
-
var dynamicWebVersion, QWEN_WEB_VERSION, DEFAULT_QWEN_USER_AGENT, QWEN_TIMEZONE_HEADER;
|
|
3044
|
-
var init_qwen_headers = __esm({
|
|
3045
|
-
"src/services/qwen-headers.ts"() {
|
|
3046
|
-
"use strict";
|
|
3047
|
-
init_qwen_url();
|
|
3048
|
-
init_config();
|
|
3049
|
-
init_fingerprint();
|
|
3050
|
-
init_timezone();
|
|
3051
|
-
dynamicWebVersion = null;
|
|
3052
|
-
QWEN_WEB_VERSION = config.qwen.webVersion;
|
|
3053
|
-
DEFAULT_QWEN_USER_AGENT = getDefaultQwenUserAgent(151);
|
|
3054
|
-
QWEN_TIMEZONE_HEADER = (/* @__PURE__ */ new Date()).toString().split(" (")[0];
|
|
3055
|
-
}
|
|
3056
|
-
});
|
|
3057
|
-
|
|
3058
3421
|
// src/utils/jwt.ts
|
|
3059
3422
|
var jwt_exports = {};
|
|
3060
3423
|
__export(jwt_exports, {
|
|
@@ -3662,11 +4025,12 @@ async function getOrLaunchSharedBrowser(browserType = "chromium", headless = con
|
|
|
3662
4025
|
async function clearVisibleChallenge(page) {
|
|
3663
4026
|
if (page.isClosed()) return;
|
|
3664
4027
|
if (config.captcha.enabled) {
|
|
3665
|
-
await
|
|
4028
|
+
await solveVisibleCaptcha(page, {
|
|
3666
4029
|
waitForMs: 0,
|
|
3667
4030
|
maxAttempts: config.captcha.maxAttempts,
|
|
3668
4031
|
retryDelayMs: config.captcha.retryDelayMs,
|
|
3669
|
-
settleMs: config.captcha.settleMs
|
|
4032
|
+
settleMs: config.captcha.settleMs,
|
|
4033
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
3670
4034
|
}).catch(() => false);
|
|
3671
4035
|
}
|
|
3672
4036
|
try {
|
|
@@ -4279,6 +4643,7 @@ async function getBasicHeaders(accountId) {
|
|
|
4279
4643
|
mobile = data.mobile ? "?1" : "?0";
|
|
4280
4644
|
}
|
|
4281
4645
|
let bundleVersion = null;
|
|
4646
|
+
let baxiaVersion = null;
|
|
4282
4647
|
try {
|
|
4283
4648
|
const el = document.querySelector('link[href*="qwen-chat-fe"], script[src*="qwen-chat-fe"], img[src*="qwen-chat-fe"]');
|
|
4284
4649
|
const src = el ? el.getAttribute("href") || el.getAttribute("src") || "" : "";
|
|
@@ -4286,7 +4651,14 @@ async function getBasicHeaders(accountId) {
|
|
|
4286
4651
|
if (match) bundleVersion = match[1];
|
|
4287
4652
|
} catch {
|
|
4288
4653
|
}
|
|
4289
|
-
|
|
4654
|
+
try {
|
|
4655
|
+
const baxia = window.baxiaCommon;
|
|
4656
|
+
if (typeof baxia?.version === "string") {
|
|
4657
|
+
baxiaVersion = baxia.version;
|
|
4658
|
+
}
|
|
4659
|
+
} catch {
|
|
4660
|
+
}
|
|
4661
|
+
return { ua, secChUa, platform, mobile, bundleVersion, baxiaVersion };
|
|
4290
4662
|
}),
|
|
4291
4663
|
config.timeouts.page,
|
|
4292
4664
|
`User-agent lookup timed out for ${accountId}`
|
|
@@ -4295,6 +4667,9 @@ async function getBasicHeaders(accountId) {
|
|
|
4295
4667
|
if (nav.bundleVersion) {
|
|
4296
4668
|
updateQwenWebVersion(nav.bundleVersion);
|
|
4297
4669
|
}
|
|
4670
|
+
if (nav.baxiaVersion) {
|
|
4671
|
+
updateQwenBxVersion(nav.baxiaVersion);
|
|
4672
|
+
}
|
|
4298
4673
|
cachedUserAgents.set(accountId, userAgent);
|
|
4299
4674
|
const hints = getHeaderCache(accountId).headers;
|
|
4300
4675
|
clientHints = {
|
|
@@ -4326,7 +4701,7 @@ async function getBasicHeaders(accountId) {
|
|
|
4326
4701
|
markAccountHeadersReady(accountId);
|
|
4327
4702
|
const bxUa2 = cache.headers["bx-ua"];
|
|
4328
4703
|
const bxUmidtoken2 = cache.headers["bx-umidtoken"];
|
|
4329
|
-
const bxV2 = cache.headers["bx-v"] ||
|
|
4704
|
+
const bxV2 = cache.headers["bx-v"] || getQwenBxVersion();
|
|
4330
4705
|
const cookie2 = await getCookies(accountId);
|
|
4331
4706
|
return { cookie: cookie2, userAgent, bxV: bxV2, bxUa: bxUa2, bxUmidtoken: bxUmidtoken2, ...clientHints };
|
|
4332
4707
|
}
|
|
@@ -4337,7 +4712,7 @@ async function getBasicHeaders(accountId) {
|
|
|
4337
4712
|
cookieCaches.set(accountId, { cookie: cookie2, timestamp: Date.now() });
|
|
4338
4713
|
const bxUa2 = cache.headers["bx-ua"];
|
|
4339
4714
|
const bxUmidtoken2 = cache.headers["bx-umidtoken"];
|
|
4340
|
-
const bxV2 = cache.headers["bx-v"] ||
|
|
4715
|
+
const bxV2 = cache.headers["bx-v"] || getQwenBxVersion();
|
|
4341
4716
|
cache.lastRefresh = Date.now();
|
|
4342
4717
|
markAccountHeadersReady(accountId);
|
|
4343
4718
|
console.log(
|
|
@@ -4412,6 +4787,9 @@ async function getBasicHeaders(accountId) {
|
|
|
4412
4787
|
if (persisted.version) {
|
|
4413
4788
|
updateQwenWebVersion(persisted.version);
|
|
4414
4789
|
}
|
|
4790
|
+
if (persisted.bxV) {
|
|
4791
|
+
updateQwenBxVersion(persisted.bxV);
|
|
4792
|
+
}
|
|
4415
4793
|
cache.lastRefresh = persisted.capturedAt;
|
|
4416
4794
|
markAccountHeadersReady(accountId);
|
|
4417
4795
|
}
|
|
@@ -4439,7 +4817,7 @@ async function getBasicHeaders(accountId) {
|
|
|
4439
4817
|
markAccountHeadersReady(accountId);
|
|
4440
4818
|
const bxUa = cache.headers["bx-ua"];
|
|
4441
4819
|
const bxUmidtoken = cache.headers["bx-umidtoken"];
|
|
4442
|
-
const bxV = cache.headers["bx-v"] ||
|
|
4820
|
+
const bxV = cache.headers["bx-v"] || getQwenBxVersion();
|
|
4443
4821
|
cookieCaches.delete(accountId);
|
|
4444
4822
|
const cookie = await getCookies(accountId, true);
|
|
4445
4823
|
if (cache.headers) {
|
|
@@ -4684,6 +5062,9 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4684
5062
|
if (persisted.version) {
|
|
4685
5063
|
updateQwenWebVersion(persisted.version);
|
|
4686
5064
|
}
|
|
5065
|
+
if (persisted.bxV) {
|
|
5066
|
+
updateQwenBxVersion(persisted.bxV);
|
|
5067
|
+
}
|
|
4687
5068
|
cache.lastRefresh = persisted.capturedAt;
|
|
4688
5069
|
markAccountHeadersReady(account.id);
|
|
4689
5070
|
restoredFromDb = true;
|
|
@@ -5033,7 +5414,7 @@ async function startEmailOtpLogin(email, options = {}) {
|
|
|
5033
5414
|
{
|
|
5034
5415
|
email: normalizedEmail,
|
|
5035
5416
|
requestId,
|
|
5036
|
-
version: getQwenWebVersion()
|
|
5417
|
+
version: getQwenWebVersion(),
|
|
5037
5418
|
timezone: formatAsciiTimezone()
|
|
5038
5419
|
}
|
|
5039
5420
|
).catch((err) => ({ ok: false, error: err?.message || String(err) }));
|
|
@@ -5128,7 +5509,7 @@ async function verifyEmailOtpLogin(sessionId, code) {
|
|
|
5128
5509
|
email: session.email,
|
|
5129
5510
|
code: cleanCode,
|
|
5130
5511
|
requestId,
|
|
5131
|
-
version: getQwenWebVersion()
|
|
5512
|
+
version: getQwenWebVersion(),
|
|
5132
5513
|
timezone: formatAsciiTimezone()
|
|
5133
5514
|
}
|
|
5134
5515
|
).catch((err) => ({ ok: false, error: err?.message || String(err) }));
|
|
@@ -5175,8 +5556,8 @@ async function verifyEmailOtpLogin(sessionId, code) {
|
|
|
5175
5556
|
saveAuthSession2(session.accountId, {
|
|
5176
5557
|
cookie: `token=${accessToken}`,
|
|
5177
5558
|
userAgent: session.fingerprint.userAgent,
|
|
5178
|
-
bxV:
|
|
5179
|
-
version: getQwenWebVersion()
|
|
5559
|
+
bxV: getQwenBxVersion(),
|
|
5560
|
+
version: getQwenWebVersion(),
|
|
5180
5561
|
userId: userId || void 0,
|
|
5181
5562
|
tokenExpiresAt: exp || void 0,
|
|
5182
5563
|
refreshToken: refreshToken || void 0,
|
|
@@ -5286,7 +5667,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5286
5667
|
saveAuthSession2(accountId, {
|
|
5287
5668
|
cookie: cookieStr,
|
|
5288
5669
|
userAgent: cache.headers["user-agent"] || "",
|
|
5289
|
-
bxV: cache.headers["bx-v"] ||
|
|
5670
|
+
bxV: cache.headers["bx-v"] || getQwenBxVersion(),
|
|
5290
5671
|
bxUa: cache.headers["bx-ua"] || "",
|
|
5291
5672
|
bxUmidtoken: cache.headers["bx-umidtoken"] || "",
|
|
5292
5673
|
secChUa: cache.headers["sec-ch-ua"] || void 0,
|
|
@@ -5358,7 +5739,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5358
5739
|
saveAuthSession2(accountId, {
|
|
5359
5740
|
cookie: cookieStr,
|
|
5360
5741
|
userAgent: cache.headers["user-agent"] || "",
|
|
5361
|
-
bxV: cache.headers["bx-v"] ||
|
|
5742
|
+
bxV: cache.headers["bx-v"] || getQwenBxVersion(),
|
|
5362
5743
|
bxUa: cache.headers["bx-ua"] || "",
|
|
5363
5744
|
bxUmidtoken: cache.headers["bx-umidtoken"] || "",
|
|
5364
5745
|
secChUa: cache.headers["sec-ch-ua"] || void 0,
|
|
@@ -5429,7 +5810,7 @@ async function loginViaApi(page, email, password) {
|
|
|
5429
5810
|
}
|
|
5430
5811
|
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
5431
5812
|
const requestId = crypto3.randomUUID();
|
|
5432
|
-
const webVersion = getQwenWebVersion()
|
|
5813
|
+
const webVersion = getQwenWebVersion();
|
|
5433
5814
|
const evalRes = await page.evaluate(
|
|
5434
5815
|
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz, version }) => {
|
|
5435
5816
|
try {
|
|
@@ -5601,6 +5982,15 @@ async function loginViaUi(page, email, password) {
|
|
|
5601
5982
|
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
5602
5983
|
return { success: true };
|
|
5603
5984
|
}
|
|
5985
|
+
if (config.captcha.enabled) {
|
|
5986
|
+
await solveVisibleCaptcha(page, {
|
|
5987
|
+
waitForMs: 1500,
|
|
5988
|
+
maxAttempts: config.captcha.maxAttempts,
|
|
5989
|
+
retryDelayMs: config.captcha.retryDelayMs,
|
|
5990
|
+
settleMs: config.captcha.settleMs,
|
|
5991
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
5992
|
+
}).catch(() => false);
|
|
5993
|
+
}
|
|
5604
5994
|
const emailSelector = [
|
|
5605
5995
|
'input[type="email"]',
|
|
5606
5996
|
'input[name="email"]',
|
|
@@ -5756,10 +6146,11 @@ async function loginViaUi(page, email, password) {
|
|
|
5756
6146
|
while (Date.now() < postSubmitDeadline) {
|
|
5757
6147
|
if (page.isClosed()) break;
|
|
5758
6148
|
if (config.captcha.enabled) {
|
|
5759
|
-
await
|
|
6149
|
+
await solveVisibleCaptcha(page, {
|
|
5760
6150
|
waitForMs: 1500,
|
|
5761
6151
|
maxAttempts: config.captcha.maxAttempts,
|
|
5762
|
-
retryDelayMs: config.captcha.retryDelayMs
|
|
6152
|
+
retryDelayMs: config.captcha.retryDelayMs,
|
|
6153
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
5763
6154
|
}).catch(() => {
|
|
5764
6155
|
});
|
|
5765
6156
|
}
|
|
@@ -5882,7 +6273,7 @@ async function refreshAccountToken(accountId) {
|
|
|
5882
6273
|
}
|
|
5883
6274
|
if (refreshToken) {
|
|
5884
6275
|
try {
|
|
5885
|
-
const webVersion = getQwenWebVersion()
|
|
6276
|
+
const webVersion = getQwenWebVersion();
|
|
5886
6277
|
const refreshResult = await page.evaluate(
|
|
5887
6278
|
async ({ rTok, tz, version }) => {
|
|
5888
6279
|
try {
|
|
@@ -5947,7 +6338,7 @@ async function refreshAccountToken(accountId) {
|
|
|
5947
6338
|
saveAuthSession2(accountId, {
|
|
5948
6339
|
cookie: cookieStr,
|
|
5949
6340
|
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
5950
|
-
bxV: cache.headers["bx-v"] || session?.bxV ||
|
|
6341
|
+
bxV: cache.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
|
|
5951
6342
|
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
5952
6343
|
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
5953
6344
|
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
@@ -5982,7 +6373,7 @@ async function refreshAccountToken(accountId) {
|
|
|
5982
6373
|
saveAuthSession2(accountId, {
|
|
5983
6374
|
cookie: cookieStr,
|
|
5984
6375
|
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
5985
|
-
bxV: cache.headers["bx-v"] || session?.bxV ||
|
|
6376
|
+
bxV: cache.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
|
|
5986
6377
|
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
5987
6378
|
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
5988
6379
|
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
@@ -6130,7 +6521,7 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
6130
6521
|
cookie: reqHeaders["cookie"] || "",
|
|
6131
6522
|
"bx-ua": reqHeaders["bx-ua"] || "",
|
|
6132
6523
|
"bx-umidtoken": reqHeaders["bx-umidtoken"] || "",
|
|
6133
|
-
"bx-v": reqHeaders["bx-v"] ||
|
|
6524
|
+
"bx-v": reqHeaders["bx-v"] || getQwenBxVersion(),
|
|
6134
6525
|
"user-agent": reqHeaders["user-agent"] || "",
|
|
6135
6526
|
"x-request-id": reqHeaders["x-request-id"] || "",
|
|
6136
6527
|
"version": reqHeaders["version"] || "",
|
|
@@ -6162,6 +6553,9 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
6162
6553
|
if (capturedHeaders["version"]) {
|
|
6163
6554
|
updateQwenWebVersion(capturedHeaders["version"]);
|
|
6164
6555
|
}
|
|
6556
|
+
if (capturedHeaders["bx-v"]) {
|
|
6557
|
+
updateQwenBxVersion(capturedHeaders["bx-v"]);
|
|
6558
|
+
}
|
|
6165
6559
|
markAccountHeadersReady(accountId);
|
|
6166
6560
|
cache.lastRefresh = Date.now();
|
|
6167
6561
|
cookieCaches.delete(accountId);
|
|
@@ -6619,7 +7013,7 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
6619
7013
|
saveAuthSession2(accountId, {
|
|
6620
7014
|
cookie: cookieStr,
|
|
6621
7015
|
userAgent: cache.headers["user-agent"] || "",
|
|
6622
|
-
bxV: cache.headers["bx-v"] ||
|
|
7016
|
+
bxV: cache.headers["bx-v"] || getQwenBxVersion(),
|
|
6623
7017
|
bxUa: cache.headers["bx-ua"] || "",
|
|
6624
7018
|
bxUmidtoken: cache.headers["bx-umidtoken"] || "",
|
|
6625
7019
|
secChUa: cache.headers["sec-ch-ua"] || void 0,
|
|
@@ -7383,13 +7777,13 @@ async function getBasicHeaders2(accountId) {
|
|
|
7383
7777
|
return {
|
|
7384
7778
|
cookie: "token=mock",
|
|
7385
7779
|
userAgent: "mock",
|
|
7386
|
-
bxV:
|
|
7780
|
+
bxV: getQwenBxVersion(),
|
|
7387
7781
|
bxUa: "mock-bx-ua",
|
|
7388
7782
|
bxUmidtoken: "mock-bx-umidtoken",
|
|
7389
7783
|
secChUa: "",
|
|
7390
7784
|
secChUaMobile: "?0",
|
|
7391
7785
|
secChUaPlatform: "",
|
|
7392
|
-
version:
|
|
7786
|
+
version: getQwenWebVersion()
|
|
7393
7787
|
};
|
|
7394
7788
|
}
|
|
7395
7789
|
const resolvedAccountId = accountId ?? loadAccounts()[0]?.id;
|
|
@@ -7450,6 +7844,7 @@ var init_auth_playwright = __esm({
|
|
|
7450
7844
|
init_errors();
|
|
7451
7845
|
init_accounts();
|
|
7452
7846
|
init_config();
|
|
7847
|
+
init_qwen_headers();
|
|
7453
7848
|
init_playwright();
|
|
7454
7849
|
init_jwt();
|
|
7455
7850
|
}
|
|
@@ -7878,9 +8273,10 @@ async function solveChallengeOnPage(page, challengeUrl, waitForMs = config.captc
|
|
|
7878
8273
|
const solverOptions = {
|
|
7879
8274
|
maxAttempts: config.captcha.maxAttempts,
|
|
7880
8275
|
retryDelayMs: config.captcha.retryDelayMs,
|
|
7881
|
-
settleMs: config.captcha.settleMs
|
|
8276
|
+
settleMs: config.captcha.settleMs,
|
|
8277
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
7882
8278
|
};
|
|
7883
|
-
if (await
|
|
8279
|
+
if (await solveVisibleCaptcha(page, { ...solverOptions, waitForMs: 0 })) {
|
|
7884
8280
|
return true;
|
|
7885
8281
|
}
|
|
7886
8282
|
logBaxiaCaptcha(
|
|
@@ -7890,7 +8286,7 @@ async function solveChallengeOnPage(page, challengeUrl, waitForMs = config.captc
|
|
|
7890
8286
|
);
|
|
7891
8287
|
await gotoBestEffort(page, challengeUrl ?? qwenUrl("/"));
|
|
7892
8288
|
try {
|
|
7893
|
-
return await
|
|
8289
|
+
return await solveVisibleCaptcha(page, { ...solverOptions, waitForMs });
|
|
7894
8290
|
} finally {
|
|
7895
8291
|
if (page.url().includes(CHALLENGE_PATH_MARKER)) {
|
|
7896
8292
|
await gotoBestEffort(page, qwenUrl("/"));
|
|
@@ -7928,9 +8324,10 @@ async function recoverBaxiaCaptcha(accountId, label, options = {}) {
|
|
|
7928
8324
|
const solverOptions = {
|
|
7929
8325
|
maxAttempts: config.captcha.maxAttempts,
|
|
7930
8326
|
retryDelayMs: config.captcha.retryDelayMs,
|
|
7931
|
-
settleMs: config.captcha.settleMs
|
|
8327
|
+
settleMs: config.captcha.settleMs,
|
|
8328
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
7932
8329
|
};
|
|
7933
|
-
if (await
|
|
8330
|
+
if (await solveVisibleCaptcha(page, { ...solverOptions, waitForMs: 0 })) {
|
|
7934
8331
|
return true;
|
|
7935
8332
|
}
|
|
7936
8333
|
const ctx = typeof page.context === "function" ? page.context() : null;
|
|
@@ -8447,7 +8844,7 @@ var init_media_generation = __esm({
|
|
|
8447
8844
|
|
|
8448
8845
|
// src/services/qwen-chat-pool.ts
|
|
8449
8846
|
import crypto4 from "crypto";
|
|
8450
|
-
async function createQwenChatSession(headers, model, accountId, chatMode = "thread") {
|
|
8847
|
+
async function createQwenChatSession(headers, model, accountId, chatMode = "thread", captchaRecoveryAttempts = 1) {
|
|
8451
8848
|
if (isAuthMockEnabled()) {
|
|
8452
8849
|
return process.env.TEST_SESSION_ID || "mock-session";
|
|
8453
8850
|
}
|
|
@@ -8475,16 +8872,29 @@ async function createQwenChatSession(headers, model, accountId, chatMode = "thre
|
|
|
8475
8872
|
if (!chatId || typeof chatId !== "string") {
|
|
8476
8873
|
const rawLower = raw.toLowerCase();
|
|
8477
8874
|
if (looksLikeAntiBotChallengeText(raw)) {
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8875
|
+
if (captchaRecoveryAttempts > 0) {
|
|
8876
|
+
try {
|
|
8877
|
+
const { recoverBaxiaCaptcha: recoverBaxiaCaptcha2 } = await Promise.resolve().then(() => (init_captcha_coordinator(), captcha_coordinator_exports));
|
|
8878
|
+
const solved = await recoverBaxiaCaptcha2(accountId, "createQwenChatSession", {
|
|
8879
|
+
challengeBody: raw
|
|
8880
|
+
});
|
|
8881
|
+
if (solved) {
|
|
8882
|
+
return createQwenChatSession(
|
|
8883
|
+
headers,
|
|
8884
|
+
model,
|
|
8885
|
+
accountId,
|
|
8886
|
+
chatMode,
|
|
8887
|
+
captchaRecoveryAttempts - 1
|
|
8888
|
+
);
|
|
8889
|
+
}
|
|
8890
|
+
} catch {
|
|
8485
8891
|
}
|
|
8486
|
-
} catch {
|
|
8487
8892
|
}
|
|
8893
|
+
throw new QwenUpstreamError(
|
|
8894
|
+
`Qwen create chat blocked by WAF challenge: ${raw.substring(0, 300)}`,
|
|
8895
|
+
"FAIL_SYS_USER_VALIDATE",
|
|
8896
|
+
403
|
|
8897
|
+
);
|
|
8488
8898
|
}
|
|
8489
8899
|
const isUnauthorized = json?.data?.code?.toLowerCase() === "unauthorized" || json?.code?.toLowerCase() === "unauthorized" || rawLower.includes("unauthorized") || rawLower.includes("permission to access") || rawLower.includes("token has expired") || rawLower.includes("401");
|
|
8490
8900
|
if (isUnauthorized) {
|
|
@@ -8661,6 +9071,20 @@ async function refillQwenChatPool(headers, model, accountId) {
|
|
|
8661
9071
|
console.warn(
|
|
8662
9072
|
`[WarmPool] Account ${accountId || "global"} rate-limited during chat creation. Marked for cooldown.`
|
|
8663
9073
|
);
|
|
9074
|
+
} else if (accountId && (err.upstreamCode === "FAIL_SYS_USER_VALIDATE" || err.upstreamCode === "RGV587_ERROR" || /_____tmd_____|rgv587_error|fail_sys_user_validate/i.test(
|
|
9075
|
+
err.message
|
|
9076
|
+
))) {
|
|
9077
|
+
const existing = getAccountCooldownInfo(accountId);
|
|
9078
|
+
if (existing?.reason === "WafChallenge") {
|
|
9079
|
+
console.warn(
|
|
9080
|
+
`[WarmPool] Account ${accountId} still on WAF quarantine (${Math.ceil(existing.remainingMs / 1e3)}s left); skipping re-escalation.`
|
|
9081
|
+
);
|
|
9082
|
+
} else {
|
|
9083
|
+
const block = recordWafHardBlock(accountId);
|
|
9084
|
+
console.warn(
|
|
9085
|
+
`[WarmPool] Unsolved WAF challenge on ${accountId} during chat creation; quarantined ${Math.ceil(block.cooldownMs / 1e3)}s and rotated the fingerprint.`
|
|
9086
|
+
);
|
|
9087
|
+
}
|
|
8664
9088
|
}
|
|
8665
9089
|
}
|
|
8666
9090
|
if (isToolcallDebugEnabled()) {
|
|
@@ -8696,6 +9120,7 @@ var init_qwen_chat_pool = __esm({
|
|
|
8696
9120
|
init_config();
|
|
8697
9121
|
init_logger();
|
|
8698
9122
|
init_account_manager();
|
|
9123
|
+
init_waf_isolation();
|
|
8699
9124
|
init_model_alias();
|
|
8700
9125
|
init_qwen_url();
|
|
8701
9126
|
init_qwen_errors();
|
|
@@ -9265,7 +9690,7 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
|
|
|
9265
9690
|
browserHeaders["Content-Type"] = "application/json";
|
|
9266
9691
|
}
|
|
9267
9692
|
const evaluateRequest = (page) => page.evaluate(
|
|
9268
|
-
async ({ url: url2, method: method2, headers: headers2, body: body2, referrer, timeoutMs, tz }) => {
|
|
9693
|
+
async ({ url: url2, method: method2, headers: headers2, body: body2, referrer, timeoutMs, tz, version }) => {
|
|
9269
9694
|
const controller = new AbortController();
|
|
9270
9695
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
9271
9696
|
try {
|
|
@@ -9287,7 +9712,7 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
|
|
|
9287
9712
|
headers: {
|
|
9288
9713
|
accept: "application/json, text/plain, */*",
|
|
9289
9714
|
source: "web",
|
|
9290
|
-
version
|
|
9715
|
+
version,
|
|
9291
9716
|
"x-request-origin": "https://chat.qwen.ai",
|
|
9292
9717
|
timezone: tz,
|
|
9293
9718
|
authorization: `Bearer ${rTok}`
|
|
@@ -9335,7 +9760,8 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
|
|
|
9335
9760
|
body,
|
|
9336
9761
|
referrer: options.referrer,
|
|
9337
9762
|
timeoutMs: options.timeoutMs ?? Math.min(config.timeouts.page, 2e4),
|
|
9338
|
-
tz: formatAsciiTimezone()
|
|
9763
|
+
tz: formatAsciiTimezone(),
|
|
9764
|
+
version: getQwenWebVersion()
|
|
9339
9765
|
}
|
|
9340
9766
|
);
|
|
9341
9767
|
const recoverOnTimeout = !options.noMutexRecovery;
|
|
@@ -10292,7 +10718,7 @@ async function deleteSingleQwenChat(accountId, chatId) {
|
|
|
10292
10718
|
}
|
|
10293
10719
|
const requestHeaders = {
|
|
10294
10720
|
source: "web",
|
|
10295
|
-
version: getQwenWebVersion()
|
|
10721
|
+
version: getQwenWebVersion(),
|
|
10296
10722
|
timezone: formatAsciiTimezone(),
|
|
10297
10723
|
"x-request-id": crypto5.randomUUID(),
|
|
10298
10724
|
Referer: qwenUrl(`/c/${encodeURIComponent(chatId)}`)
|
|
@@ -10336,7 +10762,7 @@ async function fetchRemoteQwenChats(accountId) {
|
|
|
10336
10762
|
return [];
|
|
10337
10763
|
}
|
|
10338
10764
|
const requestHeaders = {
|
|
10339
|
-
version: getQwenWebVersion()
|
|
10765
|
+
version: getQwenWebVersion(),
|
|
10340
10766
|
timezone: formatAsciiTimezone(),
|
|
10341
10767
|
"x-request-id": crypto5.randomUUID(),
|
|
10342
10768
|
Referer: qwenUrl("/settings/chats")
|