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/clean-cache.js
CHANGED
|
@@ -2990,7 +2990,19 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
2990
2990
|
if (localStorage.getItem("qwen_token_logged_out_marker")) {
|
|
2991
2991
|
return false;
|
|
2992
2992
|
}
|
|
2993
|
-
const
|
|
2993
|
+
const lsToken = (localStorage.getItem("token") || "").trim();
|
|
2994
|
+
if (lsToken && !/(?:^|;\s*)token=/.test(document.cookie || "")) {
|
|
2995
|
+
try {
|
|
2996
|
+
document.cookie = `token=${encodeURIComponent(lsToken)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
2997
|
+
} catch {
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
const authHeaders = lsToken ? { Authorization: `Bearer ${lsToken}` } : {};
|
|
3001
|
+
const res = await fetch("/api/v1/auths/", {
|
|
3002
|
+
method: "GET",
|
|
3003
|
+
headers: authHeaders,
|
|
3004
|
+
credentials: "include"
|
|
3005
|
+
});
|
|
2994
3006
|
if (res.status !== 200) return false;
|
|
2995
3007
|
const json = await res.json().catch(() => null);
|
|
2996
3008
|
if (!json) return false;
|
|
@@ -3008,6 +3020,7 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
3008
3020
|
try {
|
|
3009
3021
|
const settingsRes = await fetch("/api/v2/users/user/settings", {
|
|
3010
3022
|
method: "GET",
|
|
3023
|
+
headers: authHeaders,
|
|
3011
3024
|
credentials: "include",
|
|
3012
3025
|
signal: AbortSignal.timeout(3e3)
|
|
3013
3026
|
});
|
|
@@ -3836,8 +3849,15 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
3836
3849
|
const hasAuthCookie = cookies.some(
|
|
3837
3850
|
(c) => c.name.toLowerCase().includes("token") || c.name.toLowerCase().includes("session")
|
|
3838
3851
|
);
|
|
3852
|
+
let initialLoginAttempted = false;
|
|
3839
3853
|
if (!hasAuthCookie && account.email && account.password) {
|
|
3840
|
-
|
|
3854
|
+
initialLoginAttempted = true;
|
|
3855
|
+
const loggedIn = await loginToQwen(account.id, account.email, account.password);
|
|
3856
|
+
if (!loggedIn) {
|
|
3857
|
+
throw new Error(
|
|
3858
|
+
`Authentication failed for account ${maskEmail(account.email)}`
|
|
3859
|
+
);
|
|
3860
|
+
}
|
|
3841
3861
|
}
|
|
3842
3862
|
try {
|
|
3843
3863
|
await acctPage.goto(qwenUrl("/"), {
|
|
@@ -3847,13 +3867,21 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
3847
3867
|
await sleep2(1500);
|
|
3848
3868
|
const currentUrl = acctPage.url();
|
|
3849
3869
|
const isAuthUrl = currentUrl.includes("/auth") || currentUrl.includes("/login");
|
|
3850
|
-
if (isAuthUrl && account.email && account.password) {
|
|
3870
|
+
if (isAuthUrl && !initialLoginAttempted && account.email && account.password) {
|
|
3851
3871
|
console.log(
|
|
3852
3872
|
`[Playwright] Initial login needed for ${maskEmail(account.email)}, authenticating...`
|
|
3853
3873
|
);
|
|
3854
|
-
await loginToQwen(account.id, account.email, account.password);
|
|
3874
|
+
const loggedIn = await loginToQwen(account.id, account.email, account.password);
|
|
3875
|
+
if (!loggedIn) {
|
|
3876
|
+
throw new Error(
|
|
3877
|
+
`Authentication failed for account ${maskEmail(account.email)}`
|
|
3878
|
+
);
|
|
3879
|
+
}
|
|
3855
3880
|
}
|
|
3856
3881
|
} catch (err) {
|
|
3882
|
+
if (err?.message?.includes("Authentication failed for account")) {
|
|
3883
|
+
throw err;
|
|
3884
|
+
}
|
|
3857
3885
|
console.warn(
|
|
3858
3886
|
`\u26A0\uFE0F [Playwright] Initial navigation check for ${maskEmail(account.email)}: ${err.message}`
|
|
3859
3887
|
);
|
|
@@ -3996,10 +4024,30 @@ async function loginToQwen(accountId, email, password) {
|
|
|
3996
4024
|
const uiResult = await loginViaUi(page, email, password);
|
|
3997
4025
|
if (uiResult.success) {
|
|
3998
4026
|
cookieCaches.delete(accountId);
|
|
3999
|
-
await saveStorageState(page.context(), accountId);
|
|
4000
4027
|
try {
|
|
4001
|
-
|
|
4002
|
-
|
|
4028
|
+
let liveCookies = await page.context().cookies();
|
|
4029
|
+
let tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
4030
|
+
if (!tokenCookie) {
|
|
4031
|
+
const lsTok = uiResult.token || await page.evaluate(() => (localStorage.getItem("token") || "").trim()).catch(() => "");
|
|
4032
|
+
if (lsTok) {
|
|
4033
|
+
await page.context().addCookies([
|
|
4034
|
+
{
|
|
4035
|
+
name: "token",
|
|
4036
|
+
value: lsTok,
|
|
4037
|
+
domain: ".qwen.ai",
|
|
4038
|
+
path: "/",
|
|
4039
|
+
expires: Math.floor(Date.now() / 1e3) + 31536e3,
|
|
4040
|
+
httpOnly: false,
|
|
4041
|
+
secure: true,
|
|
4042
|
+
sameSite: "Lax"
|
|
4043
|
+
}
|
|
4044
|
+
]).catch(() => {
|
|
4045
|
+
});
|
|
4046
|
+
liveCookies = await page.context().cookies();
|
|
4047
|
+
tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
await saveStorageState(page.context(), accountId);
|
|
4003
4051
|
if (tokenCookie) {
|
|
4004
4052
|
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
4005
4053
|
const cache = getHeaderCache(accountId);
|
|
@@ -4008,7 +4056,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4008
4056
|
markAccountHeadersReady(accountId);
|
|
4009
4057
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
4010
4058
|
const exp = parseJwtExpiry(tokenCookie.value);
|
|
4011
|
-
let rTok = uiResult.refreshToken;
|
|
4059
|
+
let rTok = uiResult.refreshToken || liveCookies.find((c) => c.name === "refresh_token")?.value;
|
|
4012
4060
|
if (!rTok) {
|
|
4013
4061
|
try {
|
|
4014
4062
|
rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
|
|
@@ -4089,8 +4137,9 @@ async function loginViaApi(page, email, password) {
|
|
|
4089
4137
|
}
|
|
4090
4138
|
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
4091
4139
|
const requestId = crypto3.randomUUID();
|
|
4140
|
+
const webVersion = getQwenWebVersion() || "0.3.26";
|
|
4092
4141
|
const evalRes = await page.evaluate(
|
|
4093
|
-
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz }) => {
|
|
4142
|
+
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz, version }) => {
|
|
4094
4143
|
try {
|
|
4095
4144
|
const response = await fetch(signinUrl2, {
|
|
4096
4145
|
method: "POST",
|
|
@@ -4100,7 +4149,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4100
4149
|
accept: "application/json, text/plain, */*",
|
|
4101
4150
|
"content-type": "application/json",
|
|
4102
4151
|
source: "web",
|
|
4103
|
-
version
|
|
4152
|
+
version,
|
|
4104
4153
|
"x-request-origin": "https://chat.qwen.ai",
|
|
4105
4154
|
timezone: tz,
|
|
4106
4155
|
"x-request-id": requestId2
|
|
@@ -4113,7 +4162,14 @@ async function loginViaApi(page, email, password) {
|
|
|
4113
4162
|
return { ok: false, error: e.message };
|
|
4114
4163
|
}
|
|
4115
4164
|
},
|
|
4116
|
-
{
|
|
4165
|
+
{
|
|
4166
|
+
email,
|
|
4167
|
+
password: hashedPassword,
|
|
4168
|
+
signinUrl,
|
|
4169
|
+
requestId,
|
|
4170
|
+
tz: formatAsciiTimezone(),
|
|
4171
|
+
version: webVersion
|
|
4172
|
+
}
|
|
4117
4173
|
).catch(() => null);
|
|
4118
4174
|
let data = evalRes?.data;
|
|
4119
4175
|
let signinSuccess = Boolean(
|
|
@@ -4122,7 +4178,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4122
4178
|
if (!signinSuccess && !data?.data?.code) {
|
|
4123
4179
|
const fallbackUrl = qwenUrl("/api/v2/auths/signin");
|
|
4124
4180
|
const fallbackRes = await page.evaluate(
|
|
4125
|
-
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz }) => {
|
|
4181
|
+
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz, version }) => {
|
|
4126
4182
|
try {
|
|
4127
4183
|
const response = await fetch(fallbackUrl2, {
|
|
4128
4184
|
method: "POST",
|
|
@@ -4132,7 +4188,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4132
4188
|
accept: "application/json, text/plain, */*",
|
|
4133
4189
|
"content-type": "application/json",
|
|
4134
4190
|
source: "web",
|
|
4135
|
-
version
|
|
4191
|
+
version,
|
|
4136
4192
|
timezone: tz,
|
|
4137
4193
|
"x-request-id": requestId2
|
|
4138
4194
|
},
|
|
@@ -4144,7 +4200,14 @@ async function loginViaApi(page, email, password) {
|
|
|
4144
4200
|
return { ok: false, error: e.message };
|
|
4145
4201
|
}
|
|
4146
4202
|
},
|
|
4147
|
-
{
|
|
4203
|
+
{
|
|
4204
|
+
email,
|
|
4205
|
+
password: hashedPassword,
|
|
4206
|
+
fallbackUrl,
|
|
4207
|
+
requestId,
|
|
4208
|
+
tz: formatAsciiTimezone(),
|
|
4209
|
+
version: webVersion
|
|
4210
|
+
}
|
|
4148
4211
|
).catch(() => null);
|
|
4149
4212
|
if (fallbackRes?.data) {
|
|
4150
4213
|
data = fallbackRes.data;
|
|
@@ -4369,28 +4432,34 @@ async function loginViaUi(page, email, password) {
|
|
|
4369
4432
|
await sleep2(500);
|
|
4370
4433
|
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")';
|
|
4371
4434
|
const submitButton = page.locator(submitSelector).first();
|
|
4372
|
-
|
|
4373
|
-
try {
|
|
4374
|
-
const btn = document.querySelector(sel);
|
|
4375
|
-
if (btn) {
|
|
4376
|
-
btn.removeAttribute("disabled");
|
|
4377
|
-
btn.classList.remove("ant-btn-disabled");
|
|
4378
|
-
btn.click();
|
|
4379
|
-
}
|
|
4380
|
-
} catch {
|
|
4381
|
-
}
|
|
4382
|
-
}, submitSelector).catch(() => {
|
|
4383
|
-
});
|
|
4435
|
+
let submitted = false;
|
|
4384
4436
|
try {
|
|
4385
4437
|
if (await submitButton.isVisible({ timeout: 2e3 }).catch(() => false)) {
|
|
4386
|
-
await submitButton.click({
|
|
4438
|
+
await submitButton.click({ timeout: 2e3 }).catch(() => {
|
|
4387
4439
|
});
|
|
4440
|
+
submitted = true;
|
|
4388
4441
|
}
|
|
4389
4442
|
} catch {
|
|
4390
4443
|
}
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4444
|
+
if (!submitted) {
|
|
4445
|
+
await page.evaluate(() => {
|
|
4446
|
+
try {
|
|
4447
|
+
const btn = document.querySelector(
|
|
4448
|
+
'button.qwenchat-auth-pc-submit-button, button[type="submit"]'
|
|
4449
|
+
);
|
|
4450
|
+
if (btn) {
|
|
4451
|
+
btn.removeAttribute("disabled");
|
|
4452
|
+
btn.classList.remove("ant-btn-disabled");
|
|
4453
|
+
btn.click();
|
|
4454
|
+
}
|
|
4455
|
+
} catch {
|
|
4456
|
+
}
|
|
4457
|
+
}).catch(() => {
|
|
4458
|
+
});
|
|
4459
|
+
const passInput = page.locator(passwordSelector).first();
|
|
4460
|
+
await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
|
|
4461
|
+
});
|
|
4462
|
+
}
|
|
4394
4463
|
const postSubmitDeadline = Date.now() + 15e3;
|
|
4395
4464
|
while (Date.now() < postSubmitDeadline) {
|
|
4396
4465
|
if (page.isClosed()) break;
|
|
@@ -4408,9 +4477,12 @@ async function loginViaUi(page, email, password) {
|
|
|
4408
4477
|
".ant-form-item-explain-error",
|
|
4409
4478
|
".ant-message-error",
|
|
4410
4479
|
".ant-message-notice",
|
|
4480
|
+
".ant-message-custom-content",
|
|
4481
|
+
".ant-notification-notice",
|
|
4411
4482
|
'[role="alert"]',
|
|
4412
4483
|
".qwenchat-auth-error",
|
|
4413
|
-
".auth-error-message"
|
|
4484
|
+
".auth-error-message",
|
|
4485
|
+
".qwenchat-toast"
|
|
4414
4486
|
].join(", ");
|
|
4415
4487
|
const errorEl = page.locator(errorSelector).first();
|
|
4416
4488
|
if (await errorEl.isVisible().catch(() => false)) {
|
|
@@ -4424,7 +4496,15 @@ async function loginViaUi(page, email, password) {
|
|
|
4424
4496
|
};
|
|
4425
4497
|
}
|
|
4426
4498
|
}
|
|
4427
|
-
const codeSelector =
|
|
4499
|
+
const codeSelector = [
|
|
4500
|
+
'input[placeholder*="code" i]',
|
|
4501
|
+
'input[placeholder*="c\xF3digo" i]',
|
|
4502
|
+
'input[name*="code" i]',
|
|
4503
|
+
".qwenchat-verification-code-input",
|
|
4504
|
+
".qwenchat-verification-code-input-cell",
|
|
4505
|
+
'[aria-label*="Verification code" i]',
|
|
4506
|
+
'[aria-label*="c\xF3digo de verifica\xE7\xE3o" i]'
|
|
4507
|
+
].join(", ");
|
|
4428
4508
|
const codeInput = page.locator(codeSelector).first();
|
|
4429
4509
|
if (await codeInput.isVisible().catch(() => false)) {
|
|
4430
4510
|
return {
|
|
@@ -4434,16 +4514,44 @@ async function loginViaUi(page, email, password) {
|
|
|
4434
4514
|
}
|
|
4435
4515
|
try {
|
|
4436
4516
|
const liveCookies = await page.context().cookies();
|
|
4437
|
-
|
|
4438
|
-
|
|
4517
|
+
const rTokCookie = liveCookies.find((c) => c.name === "refresh_token")?.value;
|
|
4518
|
+
const tokCookie = liveCookies.find((c) => c.name === "token")?.value;
|
|
4519
|
+
if (tokCookie) {
|
|
4520
|
+
return { success: true, token: tokCookie, refreshToken: rTokCookie };
|
|
4439
4521
|
}
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4522
|
+
const currentUrl = page.url();
|
|
4523
|
+
if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
|
|
4524
|
+
const lsTok = await page.evaluate(() => {
|
|
4525
|
+
const t = (localStorage.getItem("token") || "").trim();
|
|
4526
|
+
if (t) {
|
|
4527
|
+
try {
|
|
4528
|
+
document.cookie = `token=${encodeURIComponent(t)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
4529
|
+
} catch {
|
|
4530
|
+
}
|
|
4531
|
+
}
|
|
4532
|
+
return t;
|
|
4533
|
+
}).catch(() => "");
|
|
4534
|
+
if (lsTok) {
|
|
4535
|
+
await page.context().addCookies([
|
|
4536
|
+
{
|
|
4537
|
+
name: "token",
|
|
4538
|
+
value: lsTok,
|
|
4539
|
+
domain: ".qwen.ai",
|
|
4540
|
+
path: "/",
|
|
4541
|
+
expires: Math.floor(Date.now() / 1e3) + 31536e3,
|
|
4542
|
+
httpOnly: false,
|
|
4543
|
+
secure: true,
|
|
4544
|
+
sameSite: "Lax"
|
|
4545
|
+
}
|
|
4546
|
+
]).catch(() => {
|
|
4547
|
+
});
|
|
4548
|
+
return { success: true, token: lsTok, refreshToken: rTokCookie };
|
|
4549
|
+
}
|
|
4550
|
+
if (await isPageLoggedIn(page, 3e3)) {
|
|
4551
|
+
return { success: true, refreshToken: rTokCookie };
|
|
4552
|
+
}
|
|
4446
4553
|
}
|
|
4554
|
+
} catch {
|
|
4447
4555
|
}
|
|
4448
4556
|
await sleep2(1e3);
|
|
4449
4557
|
}
|
|
@@ -4473,10 +4581,18 @@ async function refreshAccountToken(accountId) {
|
|
|
4473
4581
|
} catch {
|
|
4474
4582
|
}
|
|
4475
4583
|
}
|
|
4584
|
+
if (!refreshToken) {
|
|
4585
|
+
try {
|
|
4586
|
+
const liveCookies = await page.context().cookies();
|
|
4587
|
+
refreshToken = liveCookies.find((c) => c.name === "refresh_token")?.value;
|
|
4588
|
+
} catch {
|
|
4589
|
+
}
|
|
4590
|
+
}
|
|
4476
4591
|
if (refreshToken) {
|
|
4477
4592
|
try {
|
|
4593
|
+
const webVersion = getQwenWebVersion() || "0.3.26";
|
|
4478
4594
|
const refreshResult = await page.evaluate(
|
|
4479
|
-
async ({ rTok, tz }) => {
|
|
4595
|
+
async ({ rTok, tz, version }) => {
|
|
4480
4596
|
try {
|
|
4481
4597
|
const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
4482
4598
|
method: "GET",
|
|
@@ -4484,7 +4600,7 @@ async function refreshAccountToken(accountId) {
|
|
|
4484
4600
|
headers: {
|
|
4485
4601
|
accept: "application/json, text/plain, */*",
|
|
4486
4602
|
source: "web",
|
|
4487
|
-
version
|
|
4603
|
+
version,
|
|
4488
4604
|
"x-request-origin": "https://chat.qwen.ai",
|
|
4489
4605
|
timezone: tz,
|
|
4490
4606
|
authorization: `Bearer ${rTok}`
|
|
@@ -4496,7 +4612,7 @@ async function refreshAccountToken(accountId) {
|
|
|
4496
4612
|
return { ok: false, error: e.message };
|
|
4497
4613
|
}
|
|
4498
4614
|
},
|
|
4499
|
-
{ rTok: refreshToken, tz: formatAsciiTimezone() }
|
|
4615
|
+
{ rTok: refreshToken, tz: formatAsciiTimezone(), version: webVersion }
|
|
4500
4616
|
);
|
|
4501
4617
|
const json = refreshResult?.data;
|
|
4502
4618
|
if (json && json.success === true && json.data) {
|