qwenproxy-cli 1.6.9 → 1.6.10
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 +159 -43
- package/dist/delete-chats.js +159 -43
- package/dist/index.js +160 -44
- package/dist/login.js +159 -43
- package/dist/reset-cooldowns.js +159 -43
- package/package.json +1 -1
- package/src/core/version.ts +1 -1
- package/src/services/playwright.ts +171 -46
package/dist/delete-chats.js
CHANGED
|
@@ -3519,7 +3519,19 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
3519
3519
|
if (localStorage.getItem("qwen_token_logged_out_marker")) {
|
|
3520
3520
|
return false;
|
|
3521
3521
|
}
|
|
3522
|
-
const
|
|
3522
|
+
const lsToken = (localStorage.getItem("token") || "").trim();
|
|
3523
|
+
if (lsToken && !/(?:^|;\s*)token=/.test(document.cookie || "")) {
|
|
3524
|
+
try {
|
|
3525
|
+
document.cookie = `token=${encodeURIComponent(lsToken)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
3526
|
+
} catch {
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
const authHeaders = lsToken ? { Authorization: `Bearer ${lsToken}` } : {};
|
|
3530
|
+
const res = await fetch("/api/v1/auths/", {
|
|
3531
|
+
method: "GET",
|
|
3532
|
+
headers: authHeaders,
|
|
3533
|
+
credentials: "include"
|
|
3534
|
+
});
|
|
3523
3535
|
if (res.status !== 200) return false;
|
|
3524
3536
|
const json = await res.json().catch(() => null);
|
|
3525
3537
|
if (!json) return false;
|
|
@@ -3537,6 +3549,7 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
3537
3549
|
try {
|
|
3538
3550
|
const settingsRes = await fetch("/api/v2/users/user/settings", {
|
|
3539
3551
|
method: "GET",
|
|
3552
|
+
headers: authHeaders,
|
|
3540
3553
|
credentials: "include",
|
|
3541
3554
|
signal: AbortSignal.timeout(3e3)
|
|
3542
3555
|
});
|
|
@@ -4695,8 +4708,15 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4695
4708
|
const hasAuthCookie = cookies.some(
|
|
4696
4709
|
(c) => c.name.toLowerCase().includes("token") || c.name.toLowerCase().includes("session")
|
|
4697
4710
|
);
|
|
4711
|
+
let initialLoginAttempted = false;
|
|
4698
4712
|
if (!hasAuthCookie && account.email && account.password) {
|
|
4699
|
-
|
|
4713
|
+
initialLoginAttempted = true;
|
|
4714
|
+
const loggedIn = await loginToQwen(account.id, account.email, account.password);
|
|
4715
|
+
if (!loggedIn) {
|
|
4716
|
+
throw new Error(
|
|
4717
|
+
`Authentication failed for account ${maskEmail(account.email)}`
|
|
4718
|
+
);
|
|
4719
|
+
}
|
|
4700
4720
|
}
|
|
4701
4721
|
try {
|
|
4702
4722
|
await acctPage.goto(qwenUrl("/"), {
|
|
@@ -4706,13 +4726,21 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4706
4726
|
await sleep2(1500);
|
|
4707
4727
|
const currentUrl = acctPage.url();
|
|
4708
4728
|
const isAuthUrl = currentUrl.includes("/auth") || currentUrl.includes("/login");
|
|
4709
|
-
if (isAuthUrl && account.email && account.password) {
|
|
4729
|
+
if (isAuthUrl && !initialLoginAttempted && account.email && account.password) {
|
|
4710
4730
|
console.log(
|
|
4711
4731
|
`[Playwright] Initial login needed for ${maskEmail(account.email)}, authenticating...`
|
|
4712
4732
|
);
|
|
4713
|
-
await loginToQwen(account.id, account.email, account.password);
|
|
4733
|
+
const loggedIn = await loginToQwen(account.id, account.email, account.password);
|
|
4734
|
+
if (!loggedIn) {
|
|
4735
|
+
throw new Error(
|
|
4736
|
+
`Authentication failed for account ${maskEmail(account.email)}`
|
|
4737
|
+
);
|
|
4738
|
+
}
|
|
4714
4739
|
}
|
|
4715
4740
|
} catch (err) {
|
|
4741
|
+
if (err?.message?.includes("Authentication failed for account")) {
|
|
4742
|
+
throw err;
|
|
4743
|
+
}
|
|
4716
4744
|
console.warn(
|
|
4717
4745
|
`\u26A0\uFE0F [Playwright] Initial navigation check for ${maskEmail(account.email)}: ${err.message}`
|
|
4718
4746
|
);
|
|
@@ -5261,10 +5289,30 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5261
5289
|
const uiResult = await loginViaUi(page, email, password);
|
|
5262
5290
|
if (uiResult.success) {
|
|
5263
5291
|
cookieCaches.delete(accountId);
|
|
5264
|
-
await saveStorageState(page.context(), accountId);
|
|
5265
5292
|
try {
|
|
5266
|
-
|
|
5267
|
-
|
|
5293
|
+
let liveCookies = await page.context().cookies();
|
|
5294
|
+
let tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
5295
|
+
if (!tokenCookie) {
|
|
5296
|
+
const lsTok = uiResult.token || await page.evaluate(() => (localStorage.getItem("token") || "").trim()).catch(() => "");
|
|
5297
|
+
if (lsTok) {
|
|
5298
|
+
await page.context().addCookies([
|
|
5299
|
+
{
|
|
5300
|
+
name: "token",
|
|
5301
|
+
value: lsTok,
|
|
5302
|
+
domain: ".qwen.ai",
|
|
5303
|
+
path: "/",
|
|
5304
|
+
expires: Math.floor(Date.now() / 1e3) + 31536e3,
|
|
5305
|
+
httpOnly: false,
|
|
5306
|
+
secure: true,
|
|
5307
|
+
sameSite: "Lax"
|
|
5308
|
+
}
|
|
5309
|
+
]).catch(() => {
|
|
5310
|
+
});
|
|
5311
|
+
liveCookies = await page.context().cookies();
|
|
5312
|
+
tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
5313
|
+
}
|
|
5314
|
+
}
|
|
5315
|
+
await saveStorageState(page.context(), accountId);
|
|
5268
5316
|
if (tokenCookie) {
|
|
5269
5317
|
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
5270
5318
|
const cache = getHeaderCache(accountId);
|
|
@@ -5273,7 +5321,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5273
5321
|
markAccountHeadersReady(accountId);
|
|
5274
5322
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
5275
5323
|
const exp = parseJwtExpiry(tokenCookie.value);
|
|
5276
|
-
let rTok = uiResult.refreshToken;
|
|
5324
|
+
let rTok = uiResult.refreshToken || liveCookies.find((c) => c.name === "refresh_token")?.value;
|
|
5277
5325
|
if (!rTok) {
|
|
5278
5326
|
try {
|
|
5279
5327
|
rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
|
|
@@ -5354,8 +5402,9 @@ async function loginViaApi(page, email, password) {
|
|
|
5354
5402
|
}
|
|
5355
5403
|
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
5356
5404
|
const requestId = crypto3.randomUUID();
|
|
5405
|
+
const webVersion = getQwenWebVersion() || "0.3.26";
|
|
5357
5406
|
const evalRes = await page.evaluate(
|
|
5358
|
-
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz }) => {
|
|
5407
|
+
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz, version }) => {
|
|
5359
5408
|
try {
|
|
5360
5409
|
const response = await fetch(signinUrl2, {
|
|
5361
5410
|
method: "POST",
|
|
@@ -5365,7 +5414,7 @@ async function loginViaApi(page, email, password) {
|
|
|
5365
5414
|
accept: "application/json, text/plain, */*",
|
|
5366
5415
|
"content-type": "application/json",
|
|
5367
5416
|
source: "web",
|
|
5368
|
-
version
|
|
5417
|
+
version,
|
|
5369
5418
|
"x-request-origin": "https://chat.qwen.ai",
|
|
5370
5419
|
timezone: tz,
|
|
5371
5420
|
"x-request-id": requestId2
|
|
@@ -5378,7 +5427,14 @@ async function loginViaApi(page, email, password) {
|
|
|
5378
5427
|
return { ok: false, error: e.message };
|
|
5379
5428
|
}
|
|
5380
5429
|
},
|
|
5381
|
-
{
|
|
5430
|
+
{
|
|
5431
|
+
email,
|
|
5432
|
+
password: hashedPassword,
|
|
5433
|
+
signinUrl,
|
|
5434
|
+
requestId,
|
|
5435
|
+
tz: formatAsciiTimezone(),
|
|
5436
|
+
version: webVersion
|
|
5437
|
+
}
|
|
5382
5438
|
).catch(() => null);
|
|
5383
5439
|
let data = evalRes?.data;
|
|
5384
5440
|
let signinSuccess = Boolean(
|
|
@@ -5387,7 +5443,7 @@ async function loginViaApi(page, email, password) {
|
|
|
5387
5443
|
if (!signinSuccess && !data?.data?.code) {
|
|
5388
5444
|
const fallbackUrl = qwenUrl("/api/v2/auths/signin");
|
|
5389
5445
|
const fallbackRes = await page.evaluate(
|
|
5390
|
-
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz }) => {
|
|
5446
|
+
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz, version }) => {
|
|
5391
5447
|
try {
|
|
5392
5448
|
const response = await fetch(fallbackUrl2, {
|
|
5393
5449
|
method: "POST",
|
|
@@ -5397,7 +5453,7 @@ async function loginViaApi(page, email, password) {
|
|
|
5397
5453
|
accept: "application/json, text/plain, */*",
|
|
5398
5454
|
"content-type": "application/json",
|
|
5399
5455
|
source: "web",
|
|
5400
|
-
version
|
|
5456
|
+
version,
|
|
5401
5457
|
timezone: tz,
|
|
5402
5458
|
"x-request-id": requestId2
|
|
5403
5459
|
},
|
|
@@ -5409,7 +5465,14 @@ async function loginViaApi(page, email, password) {
|
|
|
5409
5465
|
return { ok: false, error: e.message };
|
|
5410
5466
|
}
|
|
5411
5467
|
},
|
|
5412
|
-
{
|
|
5468
|
+
{
|
|
5469
|
+
email,
|
|
5470
|
+
password: hashedPassword,
|
|
5471
|
+
fallbackUrl,
|
|
5472
|
+
requestId,
|
|
5473
|
+
tz: formatAsciiTimezone(),
|
|
5474
|
+
version: webVersion
|
|
5475
|
+
}
|
|
5413
5476
|
).catch(() => null);
|
|
5414
5477
|
if (fallbackRes?.data) {
|
|
5415
5478
|
data = fallbackRes.data;
|
|
@@ -5634,28 +5697,34 @@ async function loginViaUi(page, email, password) {
|
|
|
5634
5697
|
await sleep2(500);
|
|
5635
5698
|
const submitSelector = 'button.qwenchat-auth-pc-submit-button, button[type="submit"], button:has-text("Log in"), button:has-text("Sign in"), button:has-text("Fazer login"), button:has-text("Entrar"), button:has-text("Iniciar sesi\xF3n"), button:has-text("\u767B\u5F55")';
|
|
5636
5699
|
const submitButton = page.locator(submitSelector).first();
|
|
5637
|
-
|
|
5638
|
-
try {
|
|
5639
|
-
const btn = document.querySelector(sel);
|
|
5640
|
-
if (btn) {
|
|
5641
|
-
btn.removeAttribute("disabled");
|
|
5642
|
-
btn.classList.remove("ant-btn-disabled");
|
|
5643
|
-
btn.click();
|
|
5644
|
-
}
|
|
5645
|
-
} catch {
|
|
5646
|
-
}
|
|
5647
|
-
}, submitSelector).catch(() => {
|
|
5648
|
-
});
|
|
5700
|
+
let submitted = false;
|
|
5649
5701
|
try {
|
|
5650
5702
|
if (await submitButton.isVisible({ timeout: 2e3 }).catch(() => false)) {
|
|
5651
|
-
await submitButton.click({
|
|
5703
|
+
await submitButton.click({ timeout: 2e3 }).catch(() => {
|
|
5652
5704
|
});
|
|
5705
|
+
submitted = true;
|
|
5653
5706
|
}
|
|
5654
5707
|
} catch {
|
|
5655
5708
|
}
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5709
|
+
if (!submitted) {
|
|
5710
|
+
await page.evaluate(() => {
|
|
5711
|
+
try {
|
|
5712
|
+
const btn = document.querySelector(
|
|
5713
|
+
'button.qwenchat-auth-pc-submit-button, button[type="submit"]'
|
|
5714
|
+
);
|
|
5715
|
+
if (btn) {
|
|
5716
|
+
btn.removeAttribute("disabled");
|
|
5717
|
+
btn.classList.remove("ant-btn-disabled");
|
|
5718
|
+
btn.click();
|
|
5719
|
+
}
|
|
5720
|
+
} catch {
|
|
5721
|
+
}
|
|
5722
|
+
}).catch(() => {
|
|
5723
|
+
});
|
|
5724
|
+
const passInput = page.locator(passwordSelector).first();
|
|
5725
|
+
await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
|
|
5726
|
+
});
|
|
5727
|
+
}
|
|
5659
5728
|
const postSubmitDeadline = Date.now() + 15e3;
|
|
5660
5729
|
while (Date.now() < postSubmitDeadline) {
|
|
5661
5730
|
if (page.isClosed()) break;
|
|
@@ -5673,9 +5742,12 @@ async function loginViaUi(page, email, password) {
|
|
|
5673
5742
|
".ant-form-item-explain-error",
|
|
5674
5743
|
".ant-message-error",
|
|
5675
5744
|
".ant-message-notice",
|
|
5745
|
+
".ant-message-custom-content",
|
|
5746
|
+
".ant-notification-notice",
|
|
5676
5747
|
'[role="alert"]',
|
|
5677
5748
|
".qwenchat-auth-error",
|
|
5678
|
-
".auth-error-message"
|
|
5749
|
+
".auth-error-message",
|
|
5750
|
+
".qwenchat-toast"
|
|
5679
5751
|
].join(", ");
|
|
5680
5752
|
const errorEl = page.locator(errorSelector).first();
|
|
5681
5753
|
if (await errorEl.isVisible().catch(() => false)) {
|
|
@@ -5689,7 +5761,15 @@ async function loginViaUi(page, email, password) {
|
|
|
5689
5761
|
};
|
|
5690
5762
|
}
|
|
5691
5763
|
}
|
|
5692
|
-
const codeSelector =
|
|
5764
|
+
const codeSelector = [
|
|
5765
|
+
'input[placeholder*="code" i]',
|
|
5766
|
+
'input[placeholder*="c\xF3digo" i]',
|
|
5767
|
+
'input[name*="code" i]',
|
|
5768
|
+
".qwenchat-verification-code-input",
|
|
5769
|
+
".qwenchat-verification-code-input-cell",
|
|
5770
|
+
'[aria-label*="Verification code" i]',
|
|
5771
|
+
'[aria-label*="c\xF3digo de verifica\xE7\xE3o" i]'
|
|
5772
|
+
].join(", ");
|
|
5693
5773
|
const codeInput = page.locator(codeSelector).first();
|
|
5694
5774
|
if (await codeInput.isVisible().catch(() => false)) {
|
|
5695
5775
|
return {
|
|
@@ -5699,17 +5779,45 @@ async function loginViaUi(page, email, password) {
|
|
|
5699
5779
|
}
|
|
5700
5780
|
try {
|
|
5701
5781
|
const liveCookies = await page.context().cookies();
|
|
5702
|
-
|
|
5703
|
-
|
|
5782
|
+
const rTokCookie = liveCookies.find((c) => c.name === "refresh_token")?.value;
|
|
5783
|
+
const tokCookie = liveCookies.find((c) => c.name === "token")?.value;
|
|
5784
|
+
if (tokCookie) {
|
|
5785
|
+
return { success: true, token: tokCookie, refreshToken: rTokCookie };
|
|
5786
|
+
}
|
|
5787
|
+
const currentUrl = page.url();
|
|
5788
|
+
if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
|
|
5789
|
+
const lsTok = await page.evaluate(() => {
|
|
5790
|
+
const t = (localStorage.getItem("token") || "").trim();
|
|
5791
|
+
if (t) {
|
|
5792
|
+
try {
|
|
5793
|
+
document.cookie = `token=${encodeURIComponent(t)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
5794
|
+
} catch {
|
|
5795
|
+
}
|
|
5796
|
+
}
|
|
5797
|
+
return t;
|
|
5798
|
+
}).catch(() => "");
|
|
5799
|
+
if (lsTok) {
|
|
5800
|
+
await page.context().addCookies([
|
|
5801
|
+
{
|
|
5802
|
+
name: "token",
|
|
5803
|
+
value: lsTok,
|
|
5804
|
+
domain: ".qwen.ai",
|
|
5805
|
+
path: "/",
|
|
5806
|
+
expires: Math.floor(Date.now() / 1e3) + 31536e3,
|
|
5807
|
+
httpOnly: false,
|
|
5808
|
+
secure: true,
|
|
5809
|
+
sameSite: "Lax"
|
|
5810
|
+
}
|
|
5811
|
+
]).catch(() => {
|
|
5812
|
+
});
|
|
5813
|
+
return { success: true, token: lsTok, refreshToken: rTokCookie };
|
|
5814
|
+
}
|
|
5815
|
+
if (await isPageLoggedIn(page, 3e3)) {
|
|
5816
|
+
return { success: true, refreshToken: rTokCookie };
|
|
5817
|
+
}
|
|
5704
5818
|
}
|
|
5705
5819
|
} catch {
|
|
5706
5820
|
}
|
|
5707
|
-
const currentUrl = page.url();
|
|
5708
|
-
if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
|
|
5709
|
-
if (await isPageLoggedIn(page, 3e3)) {
|
|
5710
|
-
return { success: true };
|
|
5711
|
-
}
|
|
5712
|
-
}
|
|
5713
5821
|
await sleep2(1e3);
|
|
5714
5822
|
}
|
|
5715
5823
|
if (await isPageLoggedIn(page, 3e3)) {
|
|
@@ -5738,10 +5846,18 @@ async function refreshAccountToken(accountId) {
|
|
|
5738
5846
|
} catch {
|
|
5739
5847
|
}
|
|
5740
5848
|
}
|
|
5849
|
+
if (!refreshToken) {
|
|
5850
|
+
try {
|
|
5851
|
+
const liveCookies = await page.context().cookies();
|
|
5852
|
+
refreshToken = liveCookies.find((c) => c.name === "refresh_token")?.value;
|
|
5853
|
+
} catch {
|
|
5854
|
+
}
|
|
5855
|
+
}
|
|
5741
5856
|
if (refreshToken) {
|
|
5742
5857
|
try {
|
|
5858
|
+
const webVersion = getQwenWebVersion() || "0.3.26";
|
|
5743
5859
|
const refreshResult = await page.evaluate(
|
|
5744
|
-
async ({ rTok, tz }) => {
|
|
5860
|
+
async ({ rTok, tz, version }) => {
|
|
5745
5861
|
try {
|
|
5746
5862
|
const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
5747
5863
|
method: "GET",
|
|
@@ -5749,7 +5865,7 @@ async function refreshAccountToken(accountId) {
|
|
|
5749
5865
|
headers: {
|
|
5750
5866
|
accept: "application/json, text/plain, */*",
|
|
5751
5867
|
source: "web",
|
|
5752
|
-
version
|
|
5868
|
+
version,
|
|
5753
5869
|
"x-request-origin": "https://chat.qwen.ai",
|
|
5754
5870
|
timezone: tz,
|
|
5755
5871
|
authorization: `Bearer ${rTok}`
|
|
@@ -5761,7 +5877,7 @@ async function refreshAccountToken(accountId) {
|
|
|
5761
5877
|
return { ok: false, error: e.message };
|
|
5762
5878
|
}
|
|
5763
5879
|
},
|
|
5764
|
-
{ rTok: refreshToken, tz: formatAsciiTimezone() }
|
|
5880
|
+
{ rTok: refreshToken, tz: formatAsciiTimezone(), version: webVersion }
|
|
5765
5881
|
);
|
|
5766
5882
|
const json = refreshResult?.data;
|
|
5767
5883
|
if (json && json.success === true && json.data) {
|