qwenproxy-cli 1.6.10 → 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 +390 -30
- package/dist/delete-chats.js +946 -445
- package/dist/index.js +612 -100
- package/dist/login.js +417 -51
- package/dist/reset-cooldowns.js +769 -407
- package/dist/sync-clients.js +4 -1
- package/package.json +2 -2
- package/src/api/server.ts +8 -4
- package/src/core/config.ts +4 -1
- package/src/core/model-alias.ts +1 -0
- package/src/core/version.ts +1 -1
- package/src/core/watchdog.ts +4 -3
- package/src/routes/chat/account.ts +12 -0
- package/src/routes/chat/streaming.ts +18 -2
- package/src/services/auth-playwright.ts +3 -2
- package/src/services/captcha-coordinator.ts +41 -11
- package/src/services/captcha-solver.ts +400 -2
- package/src/services/chat-cleanup.ts +11 -2
- package/src/services/playwright.ts +135 -50
- package/src/services/qwen-chat-pool.ts +52 -9
- package/src/services/qwen-headers.ts +18 -1
- package/src/services/qwen.ts +35 -7
- 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) {
|
|
@@ -2185,232 +2549,46 @@ function clearAccountCooldown(accountId) {
|
|
|
2185
2549
|
}
|
|
2186
2550
|
}
|
|
2187
2551
|
}
|
|
2188
|
-
function
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
init_logger();
|
|
2206
|
-
cooldowns = /* @__PURE__ */ new Map();
|
|
2207
|
-
headersReadyAccounts = /* @__PURE__ */ new Set();
|
|
2208
|
-
}
|
|
2209
|
-
});
|
|
2210
|
-
|
|
2211
|
-
// src/services/fingerprint.ts
|
|
2212
|
-
function mulberry32(seed) {
|
|
2213
|
-
return () => {
|
|
2214
|
-
seed |= 0;
|
|
2215
|
-
seed = seed + 1831565813 | 0;
|
|
2216
|
-
let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
|
|
2217
|
-
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
2218
|
-
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
2219
|
-
};
|
|
2220
|
-
}
|
|
2221
|
-
function seedFromString(value) {
|
|
2222
|
-
let hash = 0;
|
|
2223
|
-
for (let i = 0; i < value.length; i++) {
|
|
2224
|
-
hash = (hash << 5) - hash + value.charCodeAt(i) | 0;
|
|
2225
|
-
}
|
|
2226
|
-
return hash >>> 0;
|
|
2227
|
-
}
|
|
2228
|
-
function pick(rng, values) {
|
|
2229
|
-
return values[Math.floor(rng() * values.length)];
|
|
2230
|
-
}
|
|
2231
|
-
function randInt(rng, min, max) {
|
|
2232
|
-
return Math.floor(rng() * (max - min + 1)) + min;
|
|
2233
|
-
}
|
|
2234
|
-
function updateChromeMajor(major) {
|
|
2235
|
-
if (typeof major === "number" && major >= 100) {
|
|
2236
|
-
dynamicChromeMajor = major;
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
function getChromeMajor() {
|
|
2240
|
-
return dynamicChromeMajor;
|
|
2241
|
-
}
|
|
2242
|
-
function getSystemLocale() {
|
|
2243
|
-
return process.env.QWEN_LOCALE || (typeof Intl !== "undefined" && Intl.DateTimeFormat ? Intl.DateTimeFormat().resolvedOptions().locale : "") || "pt-BR";
|
|
2244
|
-
}
|
|
2245
|
-
function getLanguageProfiles(locale = getSystemLocale()) {
|
|
2246
|
-
const primary = locale.split("-")[0];
|
|
2247
|
-
if (primary === "en") {
|
|
2248
|
-
return [
|
|
2249
|
-
["en-US", "en"],
|
|
2250
|
-
["en-US", "en", "es"],
|
|
2251
|
-
["en", "en-US"],
|
|
2252
|
-
["en-US", "en;q=0.9"]
|
|
2253
|
-
];
|
|
2552
|
+
function getAccountCooldownInfo(accountId) {
|
|
2553
|
+
const entry = cooldowns.get(accountId);
|
|
2554
|
+
if (!entry) return null;
|
|
2555
|
+
const remaining = entry.until - Date.now();
|
|
2556
|
+
if (remaining <= 0) {
|
|
2557
|
+
cooldowns.delete(accountId);
|
|
2558
|
+
if (accountId !== "global") {
|
|
2559
|
+
try {
|
|
2560
|
+
updateAccountCooldown(accountId, 0, null);
|
|
2561
|
+
} catch (err) {
|
|
2562
|
+
console.error(
|
|
2563
|
+
`\u274C [AccountManager] Failed to clear expired cooldown in DB:`,
|
|
2564
|
+
err.message
|
|
2565
|
+
);
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
return null;
|
|
2254
2569
|
}
|
|
2255
|
-
return
|
|
2256
|
-
[locale, primary, "en-US", "en"],
|
|
2257
|
-
[locale, primary, "en-US", "en", "es"],
|
|
2258
|
-
[locale, "en-US", "en", primary],
|
|
2259
|
-
[locale, primary, "en"],
|
|
2260
|
-
[locale, `${primary};q=0.9`, "en-US;q=0.8", "en;q=0.7"]
|
|
2261
|
-
];
|
|
2570
|
+
return { onCooldown: true, remainingMs: remaining, reason: entry.reason };
|
|
2262
2571
|
}
|
|
2263
|
-
function
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
const salt = rotationSalts.get(accountId) ?? 0;
|
|
2267
|
-
const seed = seedFromString(salt === 0 ? accountId : `${accountId}#r${salt}`);
|
|
2268
|
-
const rng = mulberry32(seed);
|
|
2269
|
-
const viewport = pick(rng, VIEWPORTS);
|
|
2270
|
-
const webgl = pick(rng, WEBGL_PROFILES);
|
|
2271
|
-
const languages = [...pick(rng, getLanguageProfiles())];
|
|
2272
|
-
const hardwareConcurrency = pick(rng, HARDWARE_CONCURRENCIES);
|
|
2273
|
-
const deviceMemory = pick(rng, DEVICE_MEMORIES);
|
|
2274
|
-
const platformInfo = pick(rng, PLATFORM_VERSIONS);
|
|
2275
|
-
const notABrand = pick(rng, NOT_A_BRAND_VARIANTS);
|
|
2276
|
-
const major = dynamicChromeMajor;
|
|
2277
|
-
const build = randInt(rng, 7300, 7600);
|
|
2278
|
-
const patch = randInt(rng, 0, 160);
|
|
2279
|
-
const chromeVersion = `${major}.0.${build}.${patch}`;
|
|
2280
|
-
const brands = [
|
|
2281
|
-
{ brand: notABrand.brand, version: notABrand.version },
|
|
2282
|
-
{ brand: "Google Chrome", version: String(major) },
|
|
2283
|
-
{ brand: "Chromium", version: String(major) }
|
|
2284
|
-
];
|
|
2285
|
-
const fullVersionList = [
|
|
2286
|
-
{ brand: notABrand.brand, version: chromeVersion },
|
|
2287
|
-
{ brand: "Google Chrome", version: chromeVersion },
|
|
2288
|
-
{ brand: "Chromium", version: chromeVersion }
|
|
2289
|
-
];
|
|
2290
|
-
const secChUa = brands.map((brand) => `"${brand.brand}";v="${brand.version}"`).join(", ");
|
|
2291
|
-
const userAgent = `Mozilla/5.0 (Windows NT ${platformInfo.major}.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`;
|
|
2292
|
-
const profile = {
|
|
2293
|
-
accountId,
|
|
2294
|
-
seed,
|
|
2295
|
-
userAgent,
|
|
2296
|
-
appVersion: userAgent.replace("Mozilla/", ""),
|
|
2297
|
-
chromeMajor: CHROME_MAJOR,
|
|
2298
|
-
chromeVersion,
|
|
2299
|
-
brands,
|
|
2300
|
-
fullVersionList,
|
|
2301
|
-
secChUa,
|
|
2302
|
-
platform: "Win32",
|
|
2303
|
-
platformVersion: platformInfo.platformVersion,
|
|
2304
|
-
architecture: "x86",
|
|
2305
|
-
bitness: "64",
|
|
2306
|
-
languages,
|
|
2307
|
-
locale: languages[0].split(";")[0],
|
|
2308
|
-
timezoneId: "America/Sao_Paulo",
|
|
2309
|
-
viewport,
|
|
2310
|
-
hardwareConcurrency,
|
|
2311
|
-
deviceMemory,
|
|
2312
|
-
webglVendor: webgl.vendor,
|
|
2313
|
-
webglRenderer: webgl.renderer,
|
|
2314
|
-
colorDepth: 24,
|
|
2315
|
-
pixelDepth: 24,
|
|
2316
|
-
canvasNoiseSeed: randInt(rng, 1, 2147483647),
|
|
2317
|
-
audioNoiseSeed: randInt(rng, 1, 2147483647),
|
|
2318
|
-
webglNoiseSeed: randInt(rng, 1, 2147483647),
|
|
2319
|
-
outerWidthOffset: randInt(rng, 0, 20),
|
|
2320
|
-
outerHeightOffset: randInt(rng, 75, 95)
|
|
2321
|
-
};
|
|
2322
|
-
profileCache.set(accountId, profile);
|
|
2323
|
-
return profile;
|
|
2572
|
+
function markAccountHeadersReady(accountId) {
|
|
2573
|
+
if (!accountId || accountId === "global") return;
|
|
2574
|
+
headersReadyAccounts.add(accountId);
|
|
2324
2575
|
}
|
|
2325
|
-
function
|
|
2326
|
-
if (accountId)
|
|
2327
|
-
|
|
2576
|
+
function unmarkAccountHeadersReady(accountId) {
|
|
2577
|
+
if (!accountId) return;
|
|
2578
|
+
headersReadyAccounts.delete(accountId);
|
|
2328
2579
|
}
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
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"() {
|
|
2332
2586
|
"use strict";
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
{ width: 1536, height: 864 },
|
|
2339
|
-
{ width: 1600, height: 900 },
|
|
2340
|
-
{ width: 1680, height: 1050 },
|
|
2341
|
-
{ width: 1920, height: 1080 },
|
|
2342
|
-
{ width: 1920, height: 1200 },
|
|
2343
|
-
{ width: 1280, height: 720 },
|
|
2344
|
-
{ width: 1280, height: 800 },
|
|
2345
|
-
{ width: 1536, height: 864 }
|
|
2346
|
-
];
|
|
2347
|
-
WEBGL_PROFILES = [
|
|
2348
|
-
{
|
|
2349
|
-
vendor: "Google Inc. (Intel)",
|
|
2350
|
-
renderer: "ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2351
|
-
},
|
|
2352
|
-
{
|
|
2353
|
-
vendor: "Google Inc. (Intel)",
|
|
2354
|
-
renderer: "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2355
|
-
},
|
|
2356
|
-
{
|
|
2357
|
-
vendor: "Google Inc. (Intel)",
|
|
2358
|
-
renderer: "ANGLE (Intel, Intel(R) UHD Graphics 770 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2359
|
-
},
|
|
2360
|
-
{
|
|
2361
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2362
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2363
|
-
},
|
|
2364
|
-
{
|
|
2365
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2366
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2367
|
-
},
|
|
2368
|
-
{
|
|
2369
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2370
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3080 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2371
|
-
},
|
|
2372
|
-
{
|
|
2373
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2374
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4060 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2375
|
-
},
|
|
2376
|
-
{
|
|
2377
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2378
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2379
|
-
},
|
|
2380
|
-
{
|
|
2381
|
-
vendor: "Google Inc. (NVIDIA)",
|
|
2382
|
-
renderer: "ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 SUPER Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2383
|
-
},
|
|
2384
|
-
{
|
|
2385
|
-
vendor: "Google Inc. (AMD)",
|
|
2386
|
-
renderer: "ANGLE (AMD, AMD Radeon RX 6600 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2387
|
-
},
|
|
2388
|
-
{
|
|
2389
|
-
vendor: "Google Inc. (AMD)",
|
|
2390
|
-
renderer: "ANGLE (AMD, AMD Radeon RX 7600 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2391
|
-
},
|
|
2392
|
-
{
|
|
2393
|
-
vendor: "Google Inc. (AMD)",
|
|
2394
|
-
renderer: "ANGLE (AMD, AMD Radeon RX 580 Direct3D11 vs_5_0 ps_5_0, D3D11)"
|
|
2395
|
-
}
|
|
2396
|
-
];
|
|
2397
|
-
HARDWARE_CONCURRENCIES = [4, 6, 8, 8, 8, 12, 16, 16, 24, 32];
|
|
2398
|
-
DEVICE_MEMORIES = [4, 8, 8, 8, 16, 16, 32];
|
|
2399
|
-
PLATFORM_VERSIONS = [
|
|
2400
|
-
{ platform: "Windows", platformVersion: "14.0.0", major: "10" },
|
|
2401
|
-
{ platform: "Windows", platformVersion: "15.0.0", major: "11" },
|
|
2402
|
-
{ platform: "Windows", platformVersion: "14.0.0", major: "10" },
|
|
2403
|
-
{ platform: "Windows", platformVersion: "15.0.0", major: "11" }
|
|
2404
|
-
];
|
|
2405
|
-
NOT_A_BRAND_VARIANTS = [
|
|
2406
|
-
{ brand: "Not/A)Brand", version: "99" },
|
|
2407
|
-
{ brand: "Not)A_Brand", version: "99" },
|
|
2408
|
-
{ brand: "Not/A)Brand", version: "8" },
|
|
2409
|
-
{ brand: "Not?A_Brand", version: "24" },
|
|
2410
|
-
{ brand: "Not/A)Brand", version: "99" }
|
|
2411
|
-
];
|
|
2412
|
-
profileCache = /* @__PURE__ */ new Map();
|
|
2413
|
-
rotationSalts = /* @__PURE__ */ new Map();
|
|
2587
|
+
init_accounts();
|
|
2588
|
+
init_account_priority();
|
|
2589
|
+
init_logger();
|
|
2590
|
+
cooldowns = /* @__PURE__ */ new Map();
|
|
2591
|
+
headersReadyAccounts = /* @__PURE__ */ new Set();
|
|
2414
2592
|
}
|
|
2415
2593
|
});
|
|
2416
2594
|
|
|
@@ -2552,10 +2730,298 @@ function extractBaxiaChallengeUrl(body, baseUrl) {
|
|
|
2552
2730
|
} catch {
|
|
2553
2731
|
continue;
|
|
2554
2732
|
}
|
|
2555
|
-
if (url.protocol !== base.protocol || url.host !== base.host) continue;
|
|
2556
|
-
return url.toString();
|
|
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);
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
logBaxiaCaptcha(
|
|
3005
|
+
"aliyun_solve_failed",
|
|
3006
|
+
{ attempts: maxAttempts, reason: lastReason },
|
|
3007
|
+
true
|
|
3008
|
+
);
|
|
3009
|
+
return false;
|
|
3010
|
+
});
|
|
3011
|
+
}
|
|
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;
|
|
2557
3019
|
}
|
|
2558
|
-
|
|
3020
|
+
const remainingWaitMs = Math.max(
|
|
3021
|
+
0,
|
|
3022
|
+
totalWaitMs - (Date.now() - startedAt)
|
|
3023
|
+
);
|
|
3024
|
+
return solveBaxiaCaptcha(page, { ...options, waitForMs: remainingWaitMs });
|
|
2559
3025
|
}
|
|
2560
3026
|
async function isVisible(locator) {
|
|
2561
3027
|
return locator.isVisible().catch(() => false);
|
|
@@ -2826,7 +3292,7 @@ function startBaxiaCaptchaWatcher(page, timeoutMs, options = {}) {
|
|
|
2826
3292
|
promise
|
|
2827
3293
|
};
|
|
2828
3294
|
}
|
|
2829
|
-
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;
|
|
2830
3296
|
var init_captcha_solver = __esm({
|
|
2831
3297
|
"src/services/captcha-solver.ts"() {
|
|
2832
3298
|
"use strict";
|
|
@@ -2852,14 +3318,20 @@ var init_captcha_solver = __esm({
|
|
|
2852
3318
|
solve_failed: "\u274C",
|
|
2853
3319
|
recovery_succeeded: "\u2705",
|
|
2854
3320
|
recovery_not_solved: "\u26A0\uFE0F",
|
|
2855
|
-
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"
|
|
2856
3327
|
};
|
|
2857
3328
|
captchaDebugEnabled = process.env.CAPTCHA_DEBUG === "true";
|
|
2858
3329
|
BAXIA_IFRAME_SELECTORS = [
|
|
2859
3330
|
`${BAXIA_DIALOG_SELECTOR} ${BAXIA_CONTENT_SELECTOR} iframe`,
|
|
2860
3331
|
`${BAXIA_CONTENT_SELECTOR} iframe`,
|
|
2861
3332
|
"iframe#baxia-dialog-content",
|
|
2862
|
-
'iframe[src*="_____tmd_____/punish"]'
|
|
3333
|
+
'iframe[src*="_____tmd_____/punish"]',
|
|
3334
|
+
'iframe[src*="nocaptcha"]'
|
|
2863
3335
|
];
|
|
2864
3336
|
BAXIA_DOCUMENT_SELECTORS = [
|
|
2865
3337
|
"#nocaptcha",
|
|
@@ -2867,41 +3339,71 @@ var init_captcha_solver = __esm({
|
|
|
2867
3339
|
"#baxia-punish"
|
|
2868
3340
|
];
|
|
2869
3341
|
BAXIA_IFRAME_SELECTOR = BAXIA_IFRAME_SELECTORS.join(", ");
|
|
2870
|
-
BAXIA_SLIDER_SELECTOR =
|
|
2871
|
-
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';
|
|
2872
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';
|
|
2873
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"]';
|
|
2874
3346
|
DEFAULT_MAX_ATTEMPTS = 3;
|
|
2875
3347
|
DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
2876
3348
|
DEFAULT_SETTLE_MS = 2e3;
|
|
2877
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;
|
|
2878
3359
|
captchaMouseLock = Promise.resolve();
|
|
2879
3360
|
}
|
|
2880
3361
|
});
|
|
2881
3362
|
|
|
2882
|
-
// src/services/qwen-url.ts
|
|
2883
|
-
function qwenUrl(path6 = "") {
|
|
2884
|
-
const normalizedPath = path6.replace(/^\/+/, "");
|
|
2885
|
-
return normalizedPath ? `${QWEN_BASE_URL}/${normalizedPath}` : QWEN_BASE_URL;
|
|
2886
|
-
}
|
|
2887
|
-
function qwenOrigin() {
|
|
2888
|
-
return QWEN_ORIGIN;
|
|
2889
|
-
}
|
|
2890
|
-
var QWEN_BASE_URL, QWEN_ORIGIN;
|
|
2891
|
-
var init_qwen_url = __esm({
|
|
2892
|
-
"src/services/qwen-url.ts"() {
|
|
2893
|
-
"use strict";
|
|
2894
|
-
init_config();
|
|
2895
|
-
QWEN_BASE_URL = config.qwen.baseUrl.trim().replace(/\/+$/, "");
|
|
2896
|
-
QWEN_ORIGIN = new URL(QWEN_BASE_URL).origin;
|
|
2897
|
-
}
|
|
2898
|
-
});
|
|
2899
|
-
|
|
2900
3363
|
// src/core/waf-isolation.ts
|
|
2901
3364
|
function setWafContextResetListener(fn) {
|
|
2902
3365
|
contextResetListener = fn;
|
|
2903
3366
|
}
|
|
2904
|
-
|
|
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;
|
|
2905
3407
|
var init_waf_isolation = __esm({
|
|
2906
3408
|
"src/core/waf-isolation.ts"() {
|
|
2907
3409
|
"use strict";
|
|
@@ -2909,132 +3411,13 @@ var init_waf_isolation = __esm({
|
|
|
2909
3411
|
init_logger();
|
|
2910
3412
|
init_account_manager();
|
|
2911
3413
|
init_fingerprint();
|
|
3414
|
+
ESCALATION_FACTOR = 2;
|
|
3415
|
+
MAX_CONSECUTIVE_FOR_ESCALATION = 4;
|
|
3416
|
+
states = /* @__PURE__ */ new Map();
|
|
2912
3417
|
contextResetListener = null;
|
|
2913
3418
|
}
|
|
2914
3419
|
});
|
|
2915
3420
|
|
|
2916
|
-
// src/utils/timezone.ts
|
|
2917
|
-
function formatAsciiTimezone(date = /* @__PURE__ */ new Date()) {
|
|
2918
|
-
const dayName = DAYS[date.getDay()];
|
|
2919
|
-
const monthName = MONTHS[date.getMonth()];
|
|
2920
|
-
const day = String(date.getDate()).padStart(2, "0");
|
|
2921
|
-
const year = date.getFullYear();
|
|
2922
|
-
const hours = String(date.getHours()).padStart(2, "0");
|
|
2923
|
-
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
2924
|
-
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
2925
|
-
const offsetMinutes = -date.getTimezoneOffset();
|
|
2926
|
-
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
2927
|
-
const absOffset = Math.abs(offsetMinutes);
|
|
2928
|
-
const offsetHours = String(Math.floor(absOffset / 60)).padStart(2, "0");
|
|
2929
|
-
const offsetMins = String(absOffset % 60).padStart(2, "0");
|
|
2930
|
-
const tzOffset = `GMT${sign}${offsetHours}${offsetMins}`;
|
|
2931
|
-
return `${dayName} ${monthName} ${day} ${year} ${hours}:${minutes}:${seconds} ${tzOffset}`;
|
|
2932
|
-
}
|
|
2933
|
-
function sanitizeHeaderForFetch(val) {
|
|
2934
|
-
if (typeof val !== "string") return "";
|
|
2935
|
-
return val.replace(/[^\x00-\xFF]/g, "");
|
|
2936
|
-
}
|
|
2937
|
-
var DAYS, MONTHS;
|
|
2938
|
-
var init_timezone = __esm({
|
|
2939
|
-
"src/utils/timezone.ts"() {
|
|
2940
|
-
"use strict";
|
|
2941
|
-
DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
2942
|
-
MONTHS = [
|
|
2943
|
-
"Jan",
|
|
2944
|
-
"Feb",
|
|
2945
|
-
"Mar",
|
|
2946
|
-
"Apr",
|
|
2947
|
-
"May",
|
|
2948
|
-
"Jun",
|
|
2949
|
-
"Jul",
|
|
2950
|
-
"Aug",
|
|
2951
|
-
"Sep",
|
|
2952
|
-
"Oct",
|
|
2953
|
-
"Nov",
|
|
2954
|
-
"Dec"
|
|
2955
|
-
];
|
|
2956
|
-
}
|
|
2957
|
-
});
|
|
2958
|
-
|
|
2959
|
-
// src/services/qwen-headers.ts
|
|
2960
|
-
import { v4 as uuidv4 } from "uuid";
|
|
2961
|
-
function getSystemAcceptLanguage(customLocale) {
|
|
2962
|
-
const locale = customLocale || getSystemLocale();
|
|
2963
|
-
const primary = locale.split("-")[0];
|
|
2964
|
-
if (locale.toLowerCase() === "en-us" || locale.toLowerCase() === "en") {
|
|
2965
|
-
return "en-US,en;q=0.9";
|
|
2966
|
-
}
|
|
2967
|
-
if (locale.toLowerCase().startsWith("pt")) {
|
|
2968
|
-
return "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7";
|
|
2969
|
-
}
|
|
2970
|
-
return `${locale},${primary};q=0.9,en-US;q=0.8,en;q=0.7`;
|
|
2971
|
-
}
|
|
2972
|
-
function getDefaultQwenUserAgent(major = getChromeMajor()) {
|
|
2973
|
-
return `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${major}.0.0.0 Safari/537.36`;
|
|
2974
|
-
}
|
|
2975
|
-
function updateQwenWebVersion(version) {
|
|
2976
|
-
if (version && typeof version === "string" && /^\d+\.\d+\.\d+/.test(version)) {
|
|
2977
|
-
dynamicWebVersion = version.trim();
|
|
2978
|
-
}
|
|
2979
|
-
}
|
|
2980
|
-
function getQwenWebVersion() {
|
|
2981
|
-
return dynamicWebVersion || config.qwen.webVersion;
|
|
2982
|
-
}
|
|
2983
|
-
function buildQwenRequestHeaders(opts) {
|
|
2984
|
-
const headers = {
|
|
2985
|
-
...opts.extra ?? {},
|
|
2986
|
-
Accept: "application/json",
|
|
2987
|
-
"Accept-Language": opts.extra?.["Accept-Language"] || opts.acceptLanguage || getSystemAcceptLanguage(),
|
|
2988
|
-
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
2989
|
-
"Content-Type": "application/json",
|
|
2990
|
-
Cookie: opts.cookie,
|
|
2991
|
-
Origin: qwenOrigin(),
|
|
2992
|
-
Referer: opts.extra?.Referer ?? (opts.chatSessionId ? qwenUrl(`/c/${encodeURIComponent(opts.chatSessionId)}`) : qwenUrl("/")),
|
|
2993
|
-
"Sec-Fetch-Dest": "empty",
|
|
2994
|
-
"Sec-Fetch-Mode": "cors",
|
|
2995
|
-
"Sec-Fetch-Site": "same-origin",
|
|
2996
|
-
Connection: "keep-alive",
|
|
2997
|
-
"User-Agent": opts.userAgent || getDefaultQwenUserAgent(),
|
|
2998
|
-
"X-Request-Id": uuidv4(),
|
|
2999
|
-
"bx-v": opts.bxV || "2.5.37",
|
|
3000
|
-
source: "web",
|
|
3001
|
-
version: opts.version || getQwenWebVersion(),
|
|
3002
|
-
timezone: opts.extra?.timezone || opts.extra?.Timezone || formatAsciiTimezone(),
|
|
3003
|
-
Timezone: opts.extra?.Timezone || opts.extra?.timezone || formatAsciiTimezone(),
|
|
3004
|
-
// Use the real browser client-hints when captured (anti-hardcoded); fall
|
|
3005
|
-
// back to the static fingerprint otherwise.
|
|
3006
|
-
"sec-ch-ua": opts.secChUa || `"Google Chrome";v="${getChromeMajor()}", "Chromium";v="${getChromeMajor()}", "Not.A/Brand";v="99"`,
|
|
3007
|
-
"sec-ch-ua-mobile": opts.secChUaMobile || "?0",
|
|
3008
|
-
"sec-ch-ua-platform": opts.secChUaPlatform || '"Windows"'
|
|
3009
|
-
};
|
|
3010
|
-
const tokenMatch = opts.cookie?.match(/(?:^|;\s*)token=([^;]+)/);
|
|
3011
|
-
if (tokenMatch && !headers["Authorization"] && !headers["authorization"]) {
|
|
3012
|
-
const bearer = decodeURIComponent(tokenMatch[1].trim());
|
|
3013
|
-
if (bearer && bearer !== '""' && bearer !== "null") {
|
|
3014
|
-
headers["Authorization"] = `Bearer ${bearer}`;
|
|
3015
|
-
}
|
|
3016
|
-
}
|
|
3017
|
-
if (config.qwen.sendBxUa) {
|
|
3018
|
-
if (opts.bxUa) headers["bx-ua"] = opts.bxUa;
|
|
3019
|
-
if (opts.bxUmidtoken) headers["bx-umidtoken"] = opts.bxUmidtoken;
|
|
3020
|
-
}
|
|
3021
|
-
return headers;
|
|
3022
|
-
}
|
|
3023
|
-
var dynamicWebVersion, QWEN_WEB_VERSION, DEFAULT_QWEN_USER_AGENT, QWEN_TIMEZONE_HEADER;
|
|
3024
|
-
var init_qwen_headers = __esm({
|
|
3025
|
-
"src/services/qwen-headers.ts"() {
|
|
3026
|
-
"use strict";
|
|
3027
|
-
init_qwen_url();
|
|
3028
|
-
init_config();
|
|
3029
|
-
init_fingerprint();
|
|
3030
|
-
init_timezone();
|
|
3031
|
-
dynamicWebVersion = null;
|
|
3032
|
-
QWEN_WEB_VERSION = config.qwen.webVersion;
|
|
3033
|
-
DEFAULT_QWEN_USER_AGENT = getDefaultQwenUserAgent(151);
|
|
3034
|
-
QWEN_TIMEZONE_HEADER = (/* @__PURE__ */ new Date()).toString().split(" (")[0];
|
|
3035
|
-
}
|
|
3036
|
-
});
|
|
3037
|
-
|
|
3038
3421
|
// src/utils/jwt.ts
|
|
3039
3422
|
var jwt_exports = {};
|
|
3040
3423
|
__export(jwt_exports, {
|
|
@@ -3642,11 +4025,12 @@ async function getOrLaunchSharedBrowser(browserType = "chromium", headless = con
|
|
|
3642
4025
|
async function clearVisibleChallenge(page) {
|
|
3643
4026
|
if (page.isClosed()) return;
|
|
3644
4027
|
if (config.captcha.enabled) {
|
|
3645
|
-
await
|
|
4028
|
+
await solveVisibleCaptcha(page, {
|
|
3646
4029
|
waitForMs: 0,
|
|
3647
4030
|
maxAttempts: config.captcha.maxAttempts,
|
|
3648
4031
|
retryDelayMs: config.captcha.retryDelayMs,
|
|
3649
|
-
settleMs: config.captcha.settleMs
|
|
4032
|
+
settleMs: config.captcha.settleMs,
|
|
4033
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
3650
4034
|
}).catch(() => false);
|
|
3651
4035
|
}
|
|
3652
4036
|
try {
|
|
@@ -4259,6 +4643,7 @@ async function getBasicHeaders(accountId) {
|
|
|
4259
4643
|
mobile = data.mobile ? "?1" : "?0";
|
|
4260
4644
|
}
|
|
4261
4645
|
let bundleVersion = null;
|
|
4646
|
+
let baxiaVersion = null;
|
|
4262
4647
|
try {
|
|
4263
4648
|
const el = document.querySelector('link[href*="qwen-chat-fe"], script[src*="qwen-chat-fe"], img[src*="qwen-chat-fe"]');
|
|
4264
4649
|
const src = el ? el.getAttribute("href") || el.getAttribute("src") || "" : "";
|
|
@@ -4266,7 +4651,14 @@ async function getBasicHeaders(accountId) {
|
|
|
4266
4651
|
if (match) bundleVersion = match[1];
|
|
4267
4652
|
} catch {
|
|
4268
4653
|
}
|
|
4269
|
-
|
|
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 };
|
|
4270
4662
|
}),
|
|
4271
4663
|
config.timeouts.page,
|
|
4272
4664
|
`User-agent lookup timed out for ${accountId}`
|
|
@@ -4275,6 +4667,9 @@ async function getBasicHeaders(accountId) {
|
|
|
4275
4667
|
if (nav.bundleVersion) {
|
|
4276
4668
|
updateQwenWebVersion(nav.bundleVersion);
|
|
4277
4669
|
}
|
|
4670
|
+
if (nav.baxiaVersion) {
|
|
4671
|
+
updateQwenBxVersion(nav.baxiaVersion);
|
|
4672
|
+
}
|
|
4278
4673
|
cachedUserAgents.set(accountId, userAgent);
|
|
4279
4674
|
const hints = getHeaderCache(accountId).headers;
|
|
4280
4675
|
clientHints = {
|
|
@@ -4306,7 +4701,7 @@ async function getBasicHeaders(accountId) {
|
|
|
4306
4701
|
markAccountHeadersReady(accountId);
|
|
4307
4702
|
const bxUa2 = cache.headers["bx-ua"];
|
|
4308
4703
|
const bxUmidtoken2 = cache.headers["bx-umidtoken"];
|
|
4309
|
-
const bxV2 = cache.headers["bx-v"] ||
|
|
4704
|
+
const bxV2 = cache.headers["bx-v"] || getQwenBxVersion();
|
|
4310
4705
|
const cookie2 = await getCookies(accountId);
|
|
4311
4706
|
return { cookie: cookie2, userAgent, bxV: bxV2, bxUa: bxUa2, bxUmidtoken: bxUmidtoken2, ...clientHints };
|
|
4312
4707
|
}
|
|
@@ -4317,7 +4712,7 @@ async function getBasicHeaders(accountId) {
|
|
|
4317
4712
|
cookieCaches.set(accountId, { cookie: cookie2, timestamp: Date.now() });
|
|
4318
4713
|
const bxUa2 = cache.headers["bx-ua"];
|
|
4319
4714
|
const bxUmidtoken2 = cache.headers["bx-umidtoken"];
|
|
4320
|
-
const bxV2 = cache.headers["bx-v"] ||
|
|
4715
|
+
const bxV2 = cache.headers["bx-v"] || getQwenBxVersion();
|
|
4321
4716
|
cache.lastRefresh = Date.now();
|
|
4322
4717
|
markAccountHeadersReady(accountId);
|
|
4323
4718
|
console.log(
|
|
@@ -4337,14 +4732,15 @@ async function getBasicHeaders(accountId) {
|
|
|
4337
4732
|
`\u26A0\uFE0F [Playwright] Header refresh failed for ${accountId}; retaining the previous valid cache: ${getErrorMessage(error)}`
|
|
4338
4733
|
);
|
|
4339
4734
|
}
|
|
4340
|
-
} else if (hadUsableHeaders && headersAge > HEADER_CACHE_TTL * HEADER_REFRESH_THRESHOLD && !cache.refreshInProgress
|
|
4341
|
-
|
|
4735
|
+
} else if (hadUsableHeaders && headersAge > HEADER_CACHE_TTL * HEADER_REFRESH_THRESHOLD && !cache.refreshInProgress && // Header capture types into the chat input and sends a probe message on
|
|
4736
|
+
// the account's page. Doing that while the account is serving a stream
|
|
4737
|
+
// would mutate the live conversation (and can navigate the SPA), so the
|
|
4738
|
+
// proactive refresh waits until the account has no active lease.
|
|
4739
|
+
!hasActiveAccountLease(accountId)) {
|
|
4342
4740
|
refreshHeadersInternal(accountId).catch((error) => {
|
|
4343
4741
|
console.warn(
|
|
4344
4742
|
`\u26A0\uFE0F [Playwright] Background header refresh failed for ${accountId}: ${getErrorMessage(error)}`
|
|
4345
4743
|
);
|
|
4346
|
-
}).finally(() => {
|
|
4347
|
-
cache.refreshInProgress = false;
|
|
4348
4744
|
});
|
|
4349
4745
|
}
|
|
4350
4746
|
if (!hasRequiredQwenHeaders(cache.headers)) {
|
|
@@ -4391,6 +4787,9 @@ async function getBasicHeaders(accountId) {
|
|
|
4391
4787
|
if (persisted.version) {
|
|
4392
4788
|
updateQwenWebVersion(persisted.version);
|
|
4393
4789
|
}
|
|
4790
|
+
if (persisted.bxV) {
|
|
4791
|
+
updateQwenBxVersion(persisted.bxV);
|
|
4792
|
+
}
|
|
4394
4793
|
cache.lastRefresh = persisted.capturedAt;
|
|
4395
4794
|
markAccountHeadersReady(accountId);
|
|
4396
4795
|
}
|
|
@@ -4418,7 +4817,7 @@ async function getBasicHeaders(accountId) {
|
|
|
4418
4817
|
markAccountHeadersReady(accountId);
|
|
4419
4818
|
const bxUa = cache.headers["bx-ua"];
|
|
4420
4819
|
const bxUmidtoken = cache.headers["bx-umidtoken"];
|
|
4421
|
-
const bxV = cache.headers["bx-v"] ||
|
|
4820
|
+
const bxV = cache.headers["bx-v"] || getQwenBxVersion();
|
|
4422
4821
|
cookieCaches.delete(accountId);
|
|
4423
4822
|
const cookie = await getCookies(accountId, true);
|
|
4424
4823
|
if (cache.headers) {
|
|
@@ -4482,8 +4881,12 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4482
4881
|
if (accountPages.has(account.id)) {
|
|
4483
4882
|
return;
|
|
4484
4883
|
}
|
|
4485
|
-
|
|
4486
|
-
|
|
4884
|
+
if (config.playwright.maxActiveContexts > 0) {
|
|
4885
|
+
await evictIdlePlaywrightContextsToLimit(
|
|
4886
|
+
Math.max(1, config.playwright.maxActiveContexts - 1)
|
|
4887
|
+
).catch(() => {
|
|
4888
|
+
});
|
|
4889
|
+
}
|
|
4487
4890
|
const profilePath = getAccountProfilePath(account.id);
|
|
4488
4891
|
const fingerprint = getFingerprintProfile(account.id);
|
|
4489
4892
|
const { engine, channel } = resolveBrowserEngine(browserType);
|
|
@@ -4659,6 +5062,9 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4659
5062
|
if (persisted.version) {
|
|
4660
5063
|
updateQwenWebVersion(persisted.version);
|
|
4661
5064
|
}
|
|
5065
|
+
if (persisted.bxV) {
|
|
5066
|
+
updateQwenBxVersion(persisted.bxV);
|
|
5067
|
+
}
|
|
4662
5068
|
cache.lastRefresh = persisted.capturedAt;
|
|
4663
5069
|
markAccountHeadersReady(account.id);
|
|
4664
5070
|
restoredFromDb = true;
|
|
@@ -4752,7 +5158,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4752
5158
|
if (!acctPage.isClosed()) {
|
|
4753
5159
|
try {
|
|
4754
5160
|
const currentUrl = new URL(acctPage.url());
|
|
4755
|
-
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname
|
|
5161
|
+
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname.includes("/auth") || currentUrl.pathname.includes("/login") || currentUrl.pathname.includes("_____tmd_____")) {
|
|
4756
5162
|
await acctPage.goto(qwenUrl("/"), {
|
|
4757
5163
|
waitUntil: "domcontentloaded",
|
|
4758
5164
|
timeout: config.timeouts.navigation
|
|
@@ -4770,6 +5176,8 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4770
5176
|
} finally {
|
|
4771
5177
|
release();
|
|
4772
5178
|
}
|
|
5179
|
+
await evictIdlePlaywrightContextsToLimit().catch(() => {
|
|
5180
|
+
});
|
|
4773
5181
|
})();
|
|
4774
5182
|
try {
|
|
4775
5183
|
await initPromise;
|
|
@@ -5006,7 +5414,7 @@ async function startEmailOtpLogin(email, options = {}) {
|
|
|
5006
5414
|
{
|
|
5007
5415
|
email: normalizedEmail,
|
|
5008
5416
|
requestId,
|
|
5009
|
-
version: getQwenWebVersion()
|
|
5417
|
+
version: getQwenWebVersion(),
|
|
5010
5418
|
timezone: formatAsciiTimezone()
|
|
5011
5419
|
}
|
|
5012
5420
|
).catch((err) => ({ ok: false, error: err?.message || String(err) }));
|
|
@@ -5101,7 +5509,7 @@ async function verifyEmailOtpLogin(sessionId, code) {
|
|
|
5101
5509
|
email: session.email,
|
|
5102
5510
|
code: cleanCode,
|
|
5103
5511
|
requestId,
|
|
5104
|
-
version: getQwenWebVersion()
|
|
5512
|
+
version: getQwenWebVersion(),
|
|
5105
5513
|
timezone: formatAsciiTimezone()
|
|
5106
5514
|
}
|
|
5107
5515
|
).catch((err) => ({ ok: false, error: err?.message || String(err) }));
|
|
@@ -5148,8 +5556,8 @@ async function verifyEmailOtpLogin(sessionId, code) {
|
|
|
5148
5556
|
saveAuthSession2(session.accountId, {
|
|
5149
5557
|
cookie: `token=${accessToken}`,
|
|
5150
5558
|
userAgent: session.fingerprint.userAgent,
|
|
5151
|
-
bxV:
|
|
5152
|
-
version: getQwenWebVersion()
|
|
5559
|
+
bxV: getQwenBxVersion(),
|
|
5560
|
+
version: getQwenWebVersion(),
|
|
5153
5561
|
userId: userId || void 0,
|
|
5154
5562
|
tokenExpiresAt: exp || void 0,
|
|
5155
5563
|
refreshToken: refreshToken || void 0,
|
|
@@ -5259,7 +5667,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5259
5667
|
saveAuthSession2(accountId, {
|
|
5260
5668
|
cookie: cookieStr,
|
|
5261
5669
|
userAgent: cache.headers["user-agent"] || "",
|
|
5262
|
-
bxV: cache.headers["bx-v"] ||
|
|
5670
|
+
bxV: cache.headers["bx-v"] || getQwenBxVersion(),
|
|
5263
5671
|
bxUa: cache.headers["bx-ua"] || "",
|
|
5264
5672
|
bxUmidtoken: cache.headers["bx-umidtoken"] || "",
|
|
5265
5673
|
secChUa: cache.headers["sec-ch-ua"] || void 0,
|
|
@@ -5331,7 +5739,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5331
5739
|
saveAuthSession2(accountId, {
|
|
5332
5740
|
cookie: cookieStr,
|
|
5333
5741
|
userAgent: cache.headers["user-agent"] || "",
|
|
5334
|
-
bxV: cache.headers["bx-v"] ||
|
|
5742
|
+
bxV: cache.headers["bx-v"] || getQwenBxVersion(),
|
|
5335
5743
|
bxUa: cache.headers["bx-ua"] || "",
|
|
5336
5744
|
bxUmidtoken: cache.headers["bx-umidtoken"] || "",
|
|
5337
5745
|
secChUa: cache.headers["sec-ch-ua"] || void 0,
|
|
@@ -5402,7 +5810,7 @@ async function loginViaApi(page, email, password) {
|
|
|
5402
5810
|
}
|
|
5403
5811
|
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
5404
5812
|
const requestId = crypto3.randomUUID();
|
|
5405
|
-
const webVersion = getQwenWebVersion()
|
|
5813
|
+
const webVersion = getQwenWebVersion();
|
|
5406
5814
|
const evalRes = await page.evaluate(
|
|
5407
5815
|
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz, version }) => {
|
|
5408
5816
|
try {
|
|
@@ -5574,6 +5982,15 @@ async function loginViaUi(page, email, password) {
|
|
|
5574
5982
|
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
5575
5983
|
return { success: true };
|
|
5576
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
|
+
}
|
|
5577
5994
|
const emailSelector = [
|
|
5578
5995
|
'input[type="email"]',
|
|
5579
5996
|
'input[name="email"]',
|
|
@@ -5729,10 +6146,11 @@ async function loginViaUi(page, email, password) {
|
|
|
5729
6146
|
while (Date.now() < postSubmitDeadline) {
|
|
5730
6147
|
if (page.isClosed()) break;
|
|
5731
6148
|
if (config.captcha.enabled) {
|
|
5732
|
-
await
|
|
6149
|
+
await solveVisibleCaptcha(page, {
|
|
5733
6150
|
waitForMs: 1500,
|
|
5734
6151
|
maxAttempts: config.captcha.maxAttempts,
|
|
5735
|
-
retryDelayMs: config.captcha.retryDelayMs
|
|
6152
|
+
retryDelayMs: config.captcha.retryDelayMs,
|
|
6153
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
5736
6154
|
}).catch(() => {
|
|
5737
6155
|
});
|
|
5738
6156
|
}
|
|
@@ -5855,7 +6273,7 @@ async function refreshAccountToken(accountId) {
|
|
|
5855
6273
|
}
|
|
5856
6274
|
if (refreshToken) {
|
|
5857
6275
|
try {
|
|
5858
|
-
const webVersion = getQwenWebVersion()
|
|
6276
|
+
const webVersion = getQwenWebVersion();
|
|
5859
6277
|
const refreshResult = await page.evaluate(
|
|
5860
6278
|
async ({ rTok, tz, version }) => {
|
|
5861
6279
|
try {
|
|
@@ -5920,7 +6338,7 @@ async function refreshAccountToken(accountId) {
|
|
|
5920
6338
|
saveAuthSession2(accountId, {
|
|
5921
6339
|
cookie: cookieStr,
|
|
5922
6340
|
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
5923
|
-
bxV: cache.headers["bx-v"] || session?.bxV ||
|
|
6341
|
+
bxV: cache.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
|
|
5924
6342
|
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
5925
6343
|
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
5926
6344
|
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
@@ -5955,7 +6373,7 @@ async function refreshAccountToken(accountId) {
|
|
|
5955
6373
|
saveAuthSession2(accountId, {
|
|
5956
6374
|
cookie: cookieStr,
|
|
5957
6375
|
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
5958
|
-
bxV: cache.headers["bx-v"] || session?.bxV ||
|
|
6376
|
+
bxV: cache.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
|
|
5959
6377
|
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
5960
6378
|
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
5961
6379
|
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
@@ -6103,7 +6521,7 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
6103
6521
|
cookie: reqHeaders["cookie"] || "",
|
|
6104
6522
|
"bx-ua": reqHeaders["bx-ua"] || "",
|
|
6105
6523
|
"bx-umidtoken": reqHeaders["bx-umidtoken"] || "",
|
|
6106
|
-
"bx-v": reqHeaders["bx-v"] ||
|
|
6524
|
+
"bx-v": reqHeaders["bx-v"] || getQwenBxVersion(),
|
|
6107
6525
|
"user-agent": reqHeaders["user-agent"] || "",
|
|
6108
6526
|
"x-request-id": reqHeaders["x-request-id"] || "",
|
|
6109
6527
|
"version": reqHeaders["version"] || "",
|
|
@@ -6135,6 +6553,9 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
6135
6553
|
if (capturedHeaders["version"]) {
|
|
6136
6554
|
updateQwenWebVersion(capturedHeaders["version"]);
|
|
6137
6555
|
}
|
|
6556
|
+
if (capturedHeaders["bx-v"]) {
|
|
6557
|
+
updateQwenBxVersion(capturedHeaders["bx-v"]);
|
|
6558
|
+
}
|
|
6138
6559
|
markAccountHeadersReady(accountId);
|
|
6139
6560
|
cache.lastRefresh = Date.now();
|
|
6140
6561
|
cookieCaches.delete(accountId);
|
|
@@ -6538,19 +6959,26 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
6538
6959
|
await executeReauth();
|
|
6539
6960
|
} else {
|
|
6540
6961
|
try {
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6962
|
+
const currentUrl = typeof page.url === "function" ? page.url() : "";
|
|
6963
|
+
const needsNavigation = !currentUrl.startsWith(qwenOrigin()) || currentUrl.includes("/auth") || currentUrl.includes("/login") || currentUrl.includes("_____tmd_____");
|
|
6964
|
+
if (needsNavigation) {
|
|
6965
|
+
await page.goto(qwenUrl("/"), {
|
|
6966
|
+
waitUntil: "domcontentloaded",
|
|
6967
|
+
timeout: Math.min(
|
|
6968
|
+
config.timeouts.navigation,
|
|
6969
|
+
boundedTimeoutMs,
|
|
6970
|
+
SESSION_PROBE_NAVIGATION_TIMEOUT_MS
|
|
6971
|
+
)
|
|
6972
|
+
});
|
|
6973
|
+
await sleep2(2e3);
|
|
6974
|
+
}
|
|
6975
|
+
const url = typeof page.url === "function" ? page.url() : "";
|
|
6551
6976
|
const isAuthUrl = url.includes("auth") || url.includes("login");
|
|
6552
6977
|
if (isAuthUrl) {
|
|
6553
|
-
await
|
|
6978
|
+
const refreshed = await refreshAccountToken(accountId);
|
|
6979
|
+
if (!refreshed.success) {
|
|
6980
|
+
await executeReauth();
|
|
6981
|
+
}
|
|
6554
6982
|
}
|
|
6555
6983
|
} catch (navErr) {
|
|
6556
6984
|
console.warn(
|
|
@@ -6585,7 +7013,7 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
6585
7013
|
saveAuthSession2(accountId, {
|
|
6586
7014
|
cookie: cookieStr,
|
|
6587
7015
|
userAgent: cache.headers["user-agent"] || "",
|
|
6588
|
-
bxV: cache.headers["bx-v"] ||
|
|
7016
|
+
bxV: cache.headers["bx-v"] || getQwenBxVersion(),
|
|
6589
7017
|
bxUa: cache.headers["bx-ua"] || "",
|
|
6590
7018
|
bxUmidtoken: cache.headers["bx-umidtoken"] || "",
|
|
6591
7019
|
secChUa: cache.headers["sec-ch-ua"] || void 0,
|
|
@@ -6607,7 +7035,7 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
6607
7035
|
if (capturedPage && !capturedPage.isClosed()) {
|
|
6608
7036
|
try {
|
|
6609
7037
|
const currentUrl = new URL(capturedPage.url());
|
|
6610
|
-
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname
|
|
7038
|
+
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname.includes("/auth") || currentUrl.pathname.includes("/login") || currentUrl.pathname.includes("_____tmd_____")) {
|
|
6611
7039
|
await capturedPage.goto(qwenUrl("/"), {
|
|
6612
7040
|
waitUntil: "domcontentloaded",
|
|
6613
7041
|
timeout: Math.min(config.timeouts.navigation, boundedTimeoutMs)
|
|
@@ -6923,7 +7351,11 @@ function priorityOrderForEviction(accountIds) {
|
|
|
6923
7351
|
const ranked = getAccountsByPriority(accountIds.map((id) => ({ id })));
|
|
6924
7352
|
const rank = /* @__PURE__ */ new Map();
|
|
6925
7353
|
for (const [index, account] of ranked.entries()) {
|
|
6926
|
-
|
|
7354
|
+
if (getAccountCooldownInfo(account.id)) {
|
|
7355
|
+
rank.set(account.id, Number.MAX_SAFE_INTEGER);
|
|
7356
|
+
} else {
|
|
7357
|
+
rank.set(account.id, index);
|
|
7358
|
+
}
|
|
6927
7359
|
}
|
|
6928
7360
|
return orderContextsForEviction(
|
|
6929
7361
|
accountIds,
|
|
@@ -6960,14 +7392,15 @@ async function closeIdlePlaywrightAccounts(idleMs) {
|
|
|
6960
7392
|
}
|
|
6961
7393
|
return closed;
|
|
6962
7394
|
}
|
|
6963
|
-
async function evictIdlePlaywrightContextsToLimit() {
|
|
6964
|
-
const
|
|
6965
|
-
if (
|
|
7395
|
+
async function evictIdlePlaywrightContextsToLimit(targetLimit) {
|
|
7396
|
+
const configuredMax = config.playwright.maxActiveContexts;
|
|
7397
|
+
if (configuredMax <= 0) return 0;
|
|
7398
|
+
const max = targetLimit !== void 0 ? Math.max(0, targetLimit) : configuredMax;
|
|
6966
7399
|
if (accountPages.size <= max) return 0;
|
|
6967
7400
|
const candidates = priorityOrderForEviction(
|
|
6968
7401
|
Array.from(accountPages.keys()).filter((accountId) => {
|
|
6969
7402
|
if (isAccountServingStream(accountId)) return false;
|
|
6970
|
-
if (
|
|
7403
|
+
if (hasActiveAccountLease(accountId)) return false;
|
|
6971
7404
|
const mutex = accountMutexes.get(accountId);
|
|
6972
7405
|
return mutex?.isIdle();
|
|
6973
7406
|
})
|
|
@@ -6980,6 +7413,7 @@ async function evictIdlePlaywrightContextsToLimit() {
|
|
|
6980
7413
|
for (const candidate of candidates) {
|
|
6981
7414
|
if (accountPages.size <= max) break;
|
|
6982
7415
|
if (isAccountServingStream(candidate.accountId)) continue;
|
|
7416
|
+
if (hasActiveAccountLease(candidate.accountId)) continue;
|
|
6983
7417
|
const mutex = accountMutexes.get(candidate.accountId);
|
|
6984
7418
|
if (!mutex?.isIdle()) continue;
|
|
6985
7419
|
await closePlaywrightForAccount(candidate.accountId).catch((error) => {
|
|
@@ -7343,13 +7777,13 @@ async function getBasicHeaders2(accountId) {
|
|
|
7343
7777
|
return {
|
|
7344
7778
|
cookie: "token=mock",
|
|
7345
7779
|
userAgent: "mock",
|
|
7346
|
-
bxV:
|
|
7780
|
+
bxV: getQwenBxVersion(),
|
|
7347
7781
|
bxUa: "mock-bx-ua",
|
|
7348
7782
|
bxUmidtoken: "mock-bx-umidtoken",
|
|
7349
7783
|
secChUa: "",
|
|
7350
7784
|
secChUaMobile: "?0",
|
|
7351
7785
|
secChUaPlatform: "",
|
|
7352
|
-
version:
|
|
7786
|
+
version: getQwenWebVersion()
|
|
7353
7787
|
};
|
|
7354
7788
|
}
|
|
7355
7789
|
const resolvedAccountId = accountId ?? loadAccounts()[0]?.id;
|
|
@@ -7410,6 +7844,7 @@ var init_auth_playwright = __esm({
|
|
|
7410
7844
|
init_errors();
|
|
7411
7845
|
init_accounts();
|
|
7412
7846
|
init_config();
|
|
7847
|
+
init_qwen_headers();
|
|
7413
7848
|
init_playwright();
|
|
7414
7849
|
init_jwt();
|
|
7415
7850
|
}
|
|
@@ -7818,6 +8253,7 @@ var init_model_registry = __esm({
|
|
|
7818
8253
|
var captcha_coordinator_exports = {};
|
|
7819
8254
|
__export(captcha_coordinator_exports, {
|
|
7820
8255
|
isCaptchaRecoveryActive: () => isCaptchaRecoveryActive,
|
|
8256
|
+
isCaptchaRecoveryInBackoff: () => isCaptchaRecoveryInBackoff,
|
|
7821
8257
|
recoverBaxiaCaptcha: () => recoverBaxiaCaptcha,
|
|
7822
8258
|
solveChallengeOnPage: () => solveChallengeOnPage
|
|
7823
8259
|
});
|
|
@@ -7837,9 +8273,10 @@ async function solveChallengeOnPage(page, challengeUrl, waitForMs = config.captc
|
|
|
7837
8273
|
const solverOptions = {
|
|
7838
8274
|
maxAttempts: config.captcha.maxAttempts,
|
|
7839
8275
|
retryDelayMs: config.captcha.retryDelayMs,
|
|
7840
|
-
settleMs: config.captcha.settleMs
|
|
8276
|
+
settleMs: config.captcha.settleMs,
|
|
8277
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
7841
8278
|
};
|
|
7842
|
-
if (await
|
|
8279
|
+
if (await solveVisibleCaptcha(page, { ...solverOptions, waitForMs: 0 })) {
|
|
7843
8280
|
return true;
|
|
7844
8281
|
}
|
|
7845
8282
|
logBaxiaCaptcha(
|
|
@@ -7849,13 +8286,18 @@ async function solveChallengeOnPage(page, challengeUrl, waitForMs = config.captc
|
|
|
7849
8286
|
);
|
|
7850
8287
|
await gotoBestEffort(page, challengeUrl ?? qwenUrl("/"));
|
|
7851
8288
|
try {
|
|
7852
|
-
return await
|
|
8289
|
+
return await solveVisibleCaptcha(page, { ...solverOptions, waitForMs });
|
|
7853
8290
|
} finally {
|
|
7854
8291
|
if (page.url().includes(CHALLENGE_PATH_MARKER)) {
|
|
7855
8292
|
await gotoBestEffort(page, qwenUrl("/"));
|
|
7856
8293
|
}
|
|
7857
8294
|
}
|
|
7858
8295
|
}
|
|
8296
|
+
function isCaptchaRecoveryInBackoff(accountId) {
|
|
8297
|
+
if (!accountId) return false;
|
|
8298
|
+
const lastFailure = lastFailedRecoveryAt.get(accountId) ?? 0;
|
|
8299
|
+
return Date.now() - lastFailure < FAILED_RECOVERY_BACKOFF_MS;
|
|
8300
|
+
}
|
|
7859
8301
|
async function recoverBaxiaCaptcha(accountId, label, options = {}) {
|
|
7860
8302
|
if (!config.captcha.enabled || !accountId) return false;
|
|
7861
8303
|
const solver = "baxia";
|
|
@@ -7873,17 +8315,35 @@ async function recoverBaxiaCaptcha(accountId, label, options = {}) {
|
|
|
7873
8315
|
const challengeUrl = options.challengeBody ? extractBaxiaChallengeUrl(options.challengeBody, config.qwen.baseUrl) : null;
|
|
7874
8316
|
activeCaptchaRecoveries.add(accountId);
|
|
7875
8317
|
try {
|
|
7876
|
-
const {
|
|
7877
|
-
|
|
7878
|
-
accountId,
|
|
7879
|
-
"Account stream interrupted by captcha challenge recovery"
|
|
7880
|
-
);
|
|
7881
|
-
} catch {
|
|
7882
|
-
}
|
|
7883
|
-
try {
|
|
8318
|
+
const { hasActiveBrowserStreamsForAccount: hasActiveBrowserStreamsForAccount2 } = await Promise.resolve().then(() => (init_qwen(), qwen_exports));
|
|
8319
|
+
const hasConcurrentStream = hasActiveBrowserStreamsForAccount2(accountId);
|
|
7884
8320
|
const solved = await withAccountPage(
|
|
7885
8321
|
accountId,
|
|
7886
|
-
(page) =>
|
|
8322
|
+
async (page) => {
|
|
8323
|
+
if (hasConcurrentStream) {
|
|
8324
|
+
const solverOptions = {
|
|
8325
|
+
maxAttempts: config.captcha.maxAttempts,
|
|
8326
|
+
retryDelayMs: config.captcha.retryDelayMs,
|
|
8327
|
+
settleMs: config.captcha.settleMs,
|
|
8328
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
8329
|
+
};
|
|
8330
|
+
if (await solveVisibleCaptcha(page, { ...solverOptions, waitForMs: 0 })) {
|
|
8331
|
+
return true;
|
|
8332
|
+
}
|
|
8333
|
+
const ctx = typeof page.context === "function" ? page.context() : null;
|
|
8334
|
+
if (ctx && typeof ctx.newPage === "function") {
|
|
8335
|
+
const tempPage = await ctx.newPage();
|
|
8336
|
+
try {
|
|
8337
|
+
return await solveChallengeOnPage(tempPage, challengeUrl);
|
|
8338
|
+
} finally {
|
|
8339
|
+
await tempPage.close({ runBeforeUnload: false }).catch(() => {
|
|
8340
|
+
});
|
|
8341
|
+
}
|
|
8342
|
+
}
|
|
8343
|
+
return false;
|
|
8344
|
+
}
|
|
8345
|
+
return await solveChallengeOnPage(page, challengeUrl);
|
|
8346
|
+
},
|
|
7887
8347
|
solverOperationTimeoutMs,
|
|
7888
8348
|
solverOperationTimeoutMs,
|
|
7889
8349
|
false
|
|
@@ -8384,7 +8844,7 @@ var init_media_generation = __esm({
|
|
|
8384
8844
|
|
|
8385
8845
|
// src/services/qwen-chat-pool.ts
|
|
8386
8846
|
import crypto4 from "crypto";
|
|
8387
|
-
async function createQwenChatSession(headers, model, accountId, chatMode = "thread") {
|
|
8847
|
+
async function createQwenChatSession(headers, model, accountId, chatMode = "thread", captchaRecoveryAttempts = 1) {
|
|
8388
8848
|
if (isAuthMockEnabled()) {
|
|
8389
8849
|
return process.env.TEST_SESSION_ID || "mock-session";
|
|
8390
8850
|
}
|
|
@@ -8412,16 +8872,29 @@ async function createQwenChatSession(headers, model, accountId, chatMode = "thre
|
|
|
8412
8872
|
if (!chatId || typeof chatId !== "string") {
|
|
8413
8873
|
const rawLower = raw.toLowerCase();
|
|
8414
8874
|
if (looksLikeAntiBotChallengeText(raw)) {
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
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 {
|
|
8422
8891
|
}
|
|
8423
|
-
} catch {
|
|
8424
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
|
+
);
|
|
8425
8898
|
}
|
|
8426
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");
|
|
8427
8900
|
if (isUnauthorized) {
|
|
@@ -8598,6 +9071,20 @@ async function refillQwenChatPool(headers, model, accountId) {
|
|
|
8598
9071
|
console.warn(
|
|
8599
9072
|
`[WarmPool] Account ${accountId || "global"} rate-limited during chat creation. Marked for cooldown.`
|
|
8600
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
|
+
}
|
|
8601
9088
|
}
|
|
8602
9089
|
}
|
|
8603
9090
|
if (isToolcallDebugEnabled()) {
|
|
@@ -8633,6 +9120,7 @@ var init_qwen_chat_pool = __esm({
|
|
|
8633
9120
|
init_config();
|
|
8634
9121
|
init_logger();
|
|
8635
9122
|
init_account_manager();
|
|
9123
|
+
init_waf_isolation();
|
|
8636
9124
|
init_model_alias();
|
|
8637
9125
|
init_qwen_url();
|
|
8638
9126
|
init_qwen_errors();
|
|
@@ -8682,6 +9170,7 @@ __export(qwen_exports, {
|
|
|
8682
9170
|
getLogicalThreadState: () => getLogicalThreadState,
|
|
8683
9171
|
getQwenErrorCode: () => getQwenErrorCode,
|
|
8684
9172
|
getSessionParent: () => getSessionParent,
|
|
9173
|
+
hasActiveBrowserStreamsForAccount: () => hasActiveBrowserStreamsForAccount,
|
|
8685
9174
|
invalidateLogicalThreadParent: () => invalidateLogicalThreadParent,
|
|
8686
9175
|
isChatSessionActive: () => isChatSessionActive,
|
|
8687
9176
|
isRetryableFetchErrorMessage: () => isRetryableFetchErrorMessage,
|
|
@@ -8703,6 +9192,14 @@ __export(qwen_exports, {
|
|
|
8703
9192
|
});
|
|
8704
9193
|
import crypto5 from "crypto";
|
|
8705
9194
|
import { v4 as uuidv43 } from "uuid";
|
|
9195
|
+
function hasActiveBrowserStreamsForAccount(accountId) {
|
|
9196
|
+
for (const state of browserStreamStates.values()) {
|
|
9197
|
+
if (state.accountId === accountId && !state.done) {
|
|
9198
|
+
return true;
|
|
9199
|
+
}
|
|
9200
|
+
}
|
|
9201
|
+
return false;
|
|
9202
|
+
}
|
|
8706
9203
|
function abortActiveBrowserStreamsForAccount(accountId, reason = "Account browser stream interrupted (page context unloaded)") {
|
|
8707
9204
|
let count = 0;
|
|
8708
9205
|
for (const [requestId, state] of browserStreamStates) {
|
|
@@ -9193,7 +9690,7 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
|
|
|
9193
9690
|
browserHeaders["Content-Type"] = "application/json";
|
|
9194
9691
|
}
|
|
9195
9692
|
const evaluateRequest = (page) => page.evaluate(
|
|
9196
|
-
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 }) => {
|
|
9197
9694
|
const controller = new AbortController();
|
|
9198
9695
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
9199
9696
|
try {
|
|
@@ -9215,7 +9712,7 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
|
|
|
9215
9712
|
headers: {
|
|
9216
9713
|
accept: "application/json, text/plain, */*",
|
|
9217
9714
|
source: "web",
|
|
9218
|
-
version
|
|
9715
|
+
version,
|
|
9219
9716
|
"x-request-origin": "https://chat.qwen.ai",
|
|
9220
9717
|
timezone: tz,
|
|
9221
9718
|
authorization: `Bearer ${rTok}`
|
|
@@ -9263,7 +9760,8 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
|
|
|
9263
9760
|
body,
|
|
9264
9761
|
referrer: options.referrer,
|
|
9265
9762
|
timeoutMs: options.timeoutMs ?? Math.min(config.timeouts.page, 2e4),
|
|
9266
|
-
tz: formatAsciiTimezone()
|
|
9763
|
+
tz: formatAsciiTimezone(),
|
|
9764
|
+
version: getQwenWebVersion()
|
|
9267
9765
|
}
|
|
9268
9766
|
);
|
|
9269
9767
|
const recoverOnTimeout = !options.noMutexRecovery;
|
|
@@ -9480,7 +9978,7 @@ async function createQwenBrowserResponse(accountId, url, method, headers, body,
|
|
|
9480
9978
|
const onFrameNavigated = (frame) => {
|
|
9481
9979
|
if (!settled && typeof page.mainFrame === "function" && frame === page.mainFrame()) {
|
|
9482
9980
|
const url2 = typeof frame.url === "function" ? frame.url() : String(frame.url || "");
|
|
9483
|
-
if (url2.startsWith(qwenOrigin()) && !url2.includes("/auth") && !url2.includes("_____tmd_____") && !url2.includes("/punish")) {
|
|
9981
|
+
if (url2.startsWith(qwenOrigin()) && !url2.includes("/auth") && !url2.includes("/login") && !url2.includes("_____tmd_____") && !url2.includes("/punish")) {
|
|
9484
9982
|
return;
|
|
9485
9983
|
}
|
|
9486
9984
|
handleBrowserStreamEvent(requestId, {
|
|
@@ -9501,10 +9999,12 @@ async function createQwenBrowserResponse(accountId, url, method, headers, body,
|
|
|
9501
9999
|
};
|
|
9502
10000
|
page.on("framenavigated", onFrameNavigated);
|
|
9503
10001
|
page.on("close", onPageClosed);
|
|
10002
|
+
page.on("crash", onPageClosed);
|
|
9504
10003
|
pageCleanup = () => {
|
|
9505
10004
|
try {
|
|
9506
10005
|
page.off?.("framenavigated", onFrameNavigated);
|
|
9507
10006
|
page.off?.("close", onPageClosed);
|
|
10007
|
+
page.off?.("crash", onPageClosed);
|
|
9508
10008
|
} catch {
|
|
9509
10009
|
}
|
|
9510
10010
|
};
|
|
@@ -10218,7 +10718,7 @@ async function deleteSingleQwenChat(accountId, chatId) {
|
|
|
10218
10718
|
}
|
|
10219
10719
|
const requestHeaders = {
|
|
10220
10720
|
source: "web",
|
|
10221
|
-
version: getQwenWebVersion()
|
|
10721
|
+
version: getQwenWebVersion(),
|
|
10222
10722
|
timezone: formatAsciiTimezone(),
|
|
10223
10723
|
"x-request-id": crypto5.randomUUID(),
|
|
10224
10724
|
Referer: qwenUrl(`/c/${encodeURIComponent(chatId)}`)
|
|
@@ -10262,7 +10762,7 @@ async function fetchRemoteQwenChats(accountId) {
|
|
|
10262
10762
|
return [];
|
|
10263
10763
|
}
|
|
10264
10764
|
const requestHeaders = {
|
|
10265
|
-
version: getQwenWebVersion()
|
|
10765
|
+
version: getQwenWebVersion(),
|
|
10266
10766
|
timezone: formatAsciiTimezone(),
|
|
10267
10767
|
"x-request-id": crypto5.randomUUID(),
|
|
10268
10768
|
Referer: qwenUrl("/settings/chats")
|
|
@@ -11292,6 +11792,7 @@ async function deleteChatsForConfiguredAccounts(keepBrowserOpen = false) {
|
|
|
11292
11792
|
const account = accounts[i];
|
|
11293
11793
|
const currentIdx = i + 1;
|
|
11294
11794
|
const totalCount = accounts.length;
|
|
11795
|
+
const wasInitialized = isPlaywrightInitialized(account.id);
|
|
11295
11796
|
try {
|
|
11296
11797
|
const ok = await deleteChatsForAccount(account, currentIdx, totalCount);
|
|
11297
11798
|
if (ok) succeeded++;
|
|
@@ -11301,7 +11802,7 @@ async function deleteChatsForConfiguredAccounts(keepBrowserOpen = false) {
|
|
|
11301
11802
|
error instanceof Error ? error.message : String(error)
|
|
11302
11803
|
);
|
|
11303
11804
|
} finally {
|
|
11304
|
-
if (!keepBrowserOpen) {
|
|
11805
|
+
if ((!keepBrowserOpen || !wasInitialized) && !isAuthMockEnabled()) {
|
|
11305
11806
|
const { closePlaywrightForAccount: closePlaywrightForAccount2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
11306
11807
|
await closePlaywrightForAccount2(account.id).catch(() => {
|
|
11307
11808
|
});
|