qwenproxy-cli 1.4.3 → 1.4.8
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 +205 -75
- package/dist/delete-chats.js +397 -93
- package/dist/index.js +399 -95
- package/dist/login.js +345 -83
- package/dist/reset-cooldowns.js +205 -75
- package/package.json +1 -1
- package/src/core/database.ts +10 -5
- package/src/core/version.ts +1 -1
- package/src/routes/chat/retry-policy.ts +4 -3
- package/src/services/playwright.ts +408 -83
- package/src/services/qwen-chat-pool.ts +9 -0
- package/src/services/qwen.ts +43 -10
package/dist/login.js
CHANGED
|
@@ -359,6 +359,7 @@ function runMigrations(db2) {
|
|
|
359
359
|
"sec_ch_ua_mobile TEXT",
|
|
360
360
|
"sec_ch_ua_platform TEXT",
|
|
361
361
|
"version TEXT",
|
|
362
|
+
"refresh_token TEXT",
|
|
362
363
|
"captured_at INTEGER DEFAULT 0"
|
|
363
364
|
];
|
|
364
365
|
for (const col of authSessionCols) {
|
|
@@ -437,11 +438,11 @@ function saveAuthSession(accountId, session) {
|
|
|
437
438
|
INSERT OR REPLACE INTO qwen_auth_sessions (
|
|
438
439
|
account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
|
|
439
440
|
sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
|
|
440
|
-
user_id, token_expires_at, captured_at, updated_at
|
|
441
|
+
user_id, token_expires_at, refresh_token, captured_at, updated_at
|
|
441
442
|
) VALUES (
|
|
442
443
|
?, ?, ?, ?, ?, ?,
|
|
443
444
|
?, ?, ?, ?,
|
|
444
|
-
?, ?, ?, datetime('now')
|
|
445
|
+
?, ?, ?, ?, datetime('now')
|
|
445
446
|
)
|
|
446
447
|
`);
|
|
447
448
|
stmt.run(
|
|
@@ -457,6 +458,7 @@ function saveAuthSession(accountId, session) {
|
|
|
457
458
|
session.version || null,
|
|
458
459
|
session.userId || null,
|
|
459
460
|
session.tokenExpiresAt || null,
|
|
461
|
+
session.refreshToken || null,
|
|
460
462
|
session.capturedAt ?? Date.now()
|
|
461
463
|
);
|
|
462
464
|
}
|
|
@@ -465,7 +467,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
465
467
|
const row = database.prepare(
|
|
466
468
|
`SELECT account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
|
|
467
469
|
sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
|
|
468
|
-
user_id, token_expires_at, captured_at
|
|
470
|
+
user_id, token_expires_at, refresh_token, captured_at
|
|
469
471
|
FROM qwen_auth_sessions WHERE account_id = ?`
|
|
470
472
|
).get(accountId);
|
|
471
473
|
if (!row) return null;
|
|
@@ -473,7 +475,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
473
475
|
if (capturedAt <= 0 || Date.now() - capturedAt > maxAgeMs) {
|
|
474
476
|
return null;
|
|
475
477
|
}
|
|
476
|
-
if (row.token_expires_at) {
|
|
478
|
+
if (!row.refresh_token && row.token_expires_at) {
|
|
477
479
|
const tokenExpMs = Number(row.token_expires_at) * 1e3;
|
|
478
480
|
if (tokenExpMs <= Date.now() + 5 * 60 * 1e3) {
|
|
479
481
|
return null;
|
|
@@ -495,6 +497,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
495
497
|
version: row.version || void 0,
|
|
496
498
|
userId: row.user_id || void 0,
|
|
497
499
|
tokenExpiresAt: row.token_expires_at ? Number(row.token_expires_at) : void 0,
|
|
500
|
+
refreshToken: row.refresh_token || void 0,
|
|
498
501
|
capturedAt
|
|
499
502
|
};
|
|
500
503
|
}
|
|
@@ -3137,6 +3140,7 @@ __export(playwright_exports, {
|
|
|
3137
3140
|
parseCookiesForBrowser: () => parseCookiesForBrowser,
|
|
3138
3141
|
pruneAllPlaywrightProfiles: () => pruneAllPlaywrightProfiles,
|
|
3139
3142
|
prunePlaywrightProfileCaches: () => prunePlaywrightProfileCaches,
|
|
3143
|
+
refreshAccountToken: () => refreshAccountToken,
|
|
3140
3144
|
refreshHeaders: () => refreshHeaders,
|
|
3141
3145
|
refreshHeadersWithProfileReset: () => refreshHeadersWithProfileReset,
|
|
3142
3146
|
registerPlaywrightAccountForTests: () => registerPlaywrightAccountForTests,
|
|
@@ -3864,8 +3868,29 @@ function getStealthScript(profile) {
|
|
|
3864
3868
|
const _toBlob = HTMLCanvasElement.prototype.toBlob;
|
|
3865
3869
|
const _getImageData = CanvasRenderingContext2D.prototype.getImageData;
|
|
3866
3870
|
|
|
3871
|
+
function isCaptchaCanvas(canvas) {
|
|
3872
|
+
try {
|
|
3873
|
+
if (!canvas) return false;
|
|
3874
|
+
const id = (canvas.id || "").toLowerCase();
|
|
3875
|
+
const cls = (canvas.className || "").toLowerCase();
|
|
3876
|
+
return (
|
|
3877
|
+
id.includes("baxia") ||
|
|
3878
|
+
id.includes("nc_") ||
|
|
3879
|
+
id.includes("captcha") ||
|
|
3880
|
+
id.includes("punish") ||
|
|
3881
|
+
cls.includes("baxia") ||
|
|
3882
|
+
cls.includes("nc_") ||
|
|
3883
|
+
cls.includes("captcha") ||
|
|
3884
|
+
Boolean(canvas.closest?.("#baxia-dialog, #baxia-punish, [class*='baxia'], [class*='nc_'], .auth-layout"))
|
|
3885
|
+
);
|
|
3886
|
+
} catch(e) {
|
|
3887
|
+
return false;
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3867
3891
|
function addNoise(canvas) {
|
|
3868
3892
|
try {
|
|
3893
|
+
if (isCaptchaCanvas(canvas)) return;
|
|
3869
3894
|
const ctx = canvas.getContext('2d');
|
|
3870
3895
|
if (!ctx) return;
|
|
3871
3896
|
const style = ctx.fillStyle;
|
|
@@ -3889,6 +3914,9 @@ function getStealthScript(profile) {
|
|
|
3889
3914
|
|
|
3890
3915
|
CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
|
|
3891
3916
|
const imageData = _getImageData.apply(this, arguments);
|
|
3917
|
+
if (isCaptchaCanvas(this.canvas)) {
|
|
3918
|
+
return imageData;
|
|
3919
|
+
}
|
|
3892
3920
|
const data = imageData.data;
|
|
3893
3921
|
const maxPixels = Math.min(data.length / 4, 2500);
|
|
3894
3922
|
for (let i = 0; i < maxPixels * 4; i += 4) {
|
|
@@ -4748,6 +4776,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4748
4776
|
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || void 0,
|
|
4749
4777
|
version: cache.headers["version"] || void 0,
|
|
4750
4778
|
tokenExpiresAt: exp || void 0,
|
|
4779
|
+
refreshToken: apiResult.refreshToken,
|
|
4751
4780
|
capturedAt: Date.now()
|
|
4752
4781
|
});
|
|
4753
4782
|
}
|
|
@@ -4781,6 +4810,13 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4781
4810
|
markAccountHeadersReady(accountId);
|
|
4782
4811
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
4783
4812
|
const exp = parseJwtExpiry(tokenCookie.value);
|
|
4813
|
+
let rTok = uiResult.refreshToken;
|
|
4814
|
+
if (!rTok) {
|
|
4815
|
+
try {
|
|
4816
|
+
rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
|
|
4817
|
+
} catch {
|
|
4818
|
+
}
|
|
4819
|
+
}
|
|
4784
4820
|
saveAuthSession2(accountId, {
|
|
4785
4821
|
cookie: cookieStr,
|
|
4786
4822
|
userAgent: cache.headers["user-agent"] || "",
|
|
@@ -4792,6 +4828,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4792
4828
|
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || void 0,
|
|
4793
4829
|
version: cache.headers["version"] || void 0,
|
|
4794
4830
|
tokenExpiresAt: exp || void 0,
|
|
4831
|
+
refreshToken: rTok,
|
|
4795
4832
|
capturedAt: Date.now()
|
|
4796
4833
|
});
|
|
4797
4834
|
}
|
|
@@ -4844,37 +4881,52 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4844
4881
|
async function loginViaApi(page, email, password) {
|
|
4845
4882
|
try {
|
|
4846
4883
|
const hashedPassword = crypto3.createHash("sha256").update(password).digest("hex");
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
email,
|
|
4855
|
-
password: hashedPassword,
|
|
4856
|
-
login_type: "email"
|
|
4857
|
-
},
|
|
4858
|
-
headers: {
|
|
4859
|
-
"content-type": "application/json",
|
|
4860
|
-
accept: "application/json, text/plain, */*",
|
|
4861
|
-
referer: qwenUrl("/auth"),
|
|
4862
|
-
origin: qwenOrigin(),
|
|
4863
|
-
source: "web"
|
|
4864
|
-
},
|
|
4865
|
-
timeout: 1e4
|
|
4866
|
-
});
|
|
4867
|
-
data = await response.json().catch(() => null);
|
|
4868
|
-
signinSuccess = Boolean(data && (data.success === true || data.token));
|
|
4869
|
-
} catch {
|
|
4870
|
-
}
|
|
4884
|
+
if (!page.url().includes("/auth")) {
|
|
4885
|
+
await page.goto(qwenUrl("/auth"), {
|
|
4886
|
+
waitUntil: "domcontentloaded",
|
|
4887
|
+
timeout: config.timeouts.navigation
|
|
4888
|
+
}).catch(() => {
|
|
4889
|
+
});
|
|
4890
|
+
await sleep2(1e3);
|
|
4871
4891
|
}
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4892
|
+
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
4893
|
+
const requestId = crypto3.randomUUID();
|
|
4894
|
+
const evalRes = await page.evaluate(
|
|
4895
|
+
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
|
|
4896
|
+
try {
|
|
4897
|
+
const response = await fetch(signinUrl2, {
|
|
4898
|
+
method: "POST",
|
|
4899
|
+
signal: AbortSignal.timeout(15e3),
|
|
4900
|
+
credentials: "include",
|
|
4901
|
+
headers: {
|
|
4902
|
+
accept: "application/json, text/plain, */*",
|
|
4903
|
+
"content-type": "application/json",
|
|
4904
|
+
source: "web",
|
|
4905
|
+
version: "0.3.11",
|
|
4906
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
4907
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
4908
|
+
"x-request-id": requestId2
|
|
4909
|
+
},
|
|
4910
|
+
body: JSON.stringify({ email: email2, password: password2 })
|
|
4911
|
+
});
|
|
4912
|
+
const json = await response.json().catch(() => null);
|
|
4913
|
+
return { ok: response.ok, status: response.status, data: json };
|
|
4914
|
+
} catch (e) {
|
|
4915
|
+
return { ok: false, error: e.message };
|
|
4916
|
+
}
|
|
4917
|
+
},
|
|
4918
|
+
{ email, password: hashedPassword, signinUrl, requestId }
|
|
4919
|
+
).catch(() => null);
|
|
4920
|
+
let data = evalRes?.data;
|
|
4921
|
+
let signinSuccess = Boolean(
|
|
4922
|
+
data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
|
|
4923
|
+
);
|
|
4924
|
+
if (!signinSuccess && !data?.data?.code) {
|
|
4925
|
+
const fallbackUrl = qwenUrl("/api/v2/auths/signin");
|
|
4926
|
+
const fallbackRes = await page.evaluate(
|
|
4927
|
+
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
|
|
4876
4928
|
try {
|
|
4877
|
-
const response = await fetch(
|
|
4929
|
+
const response = await fetch(fallbackUrl2, {
|
|
4878
4930
|
method: "POST",
|
|
4879
4931
|
signal: AbortSignal.timeout(1e4),
|
|
4880
4932
|
credentials: "include",
|
|
@@ -4882,10 +4934,11 @@ async function loginViaApi(page, email, password) {
|
|
|
4882
4934
|
accept: "application/json, text/plain, */*",
|
|
4883
4935
|
"content-type": "application/json",
|
|
4884
4936
|
source: "web",
|
|
4937
|
+
version: "0.3.11",
|
|
4885
4938
|
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
4886
4939
|
"x-request-id": requestId2
|
|
4887
4940
|
},
|
|
4888
|
-
body: JSON.stringify({ email: email2, password: password2
|
|
4941
|
+
body: JSON.stringify({ email: email2, password: password2 })
|
|
4889
4942
|
});
|
|
4890
4943
|
const json = await response.json().catch(() => null);
|
|
4891
4944
|
return { ok: response.ok, status: response.status, data: json };
|
|
@@ -4893,11 +4946,13 @@ async function loginViaApi(page, email, password) {
|
|
|
4893
4946
|
return { ok: false, error: e.message };
|
|
4894
4947
|
}
|
|
4895
4948
|
},
|
|
4896
|
-
{ email, password: hashedPassword,
|
|
4949
|
+
{ email, password: hashedPassword, fallbackUrl, requestId }
|
|
4897
4950
|
).catch(() => null);
|
|
4898
|
-
if (
|
|
4899
|
-
data =
|
|
4900
|
-
signinSuccess = Boolean(
|
|
4951
|
+
if (fallbackRes?.data) {
|
|
4952
|
+
data = fallbackRes.data;
|
|
4953
|
+
signinSuccess = Boolean(
|
|
4954
|
+
data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
|
|
4955
|
+
);
|
|
4901
4956
|
}
|
|
4902
4957
|
}
|
|
4903
4958
|
if (data?.success === false) {
|
|
@@ -4911,7 +4966,8 @@ async function loginViaApi(page, email, password) {
|
|
|
4911
4966
|
};
|
|
4912
4967
|
}
|
|
4913
4968
|
if (signinSuccess) {
|
|
4914
|
-
const token = data?.data?.token || data?.token;
|
|
4969
|
+
const token = data?.data?.access_token || data?.data?.token || data?.access_token || data?.token;
|
|
4970
|
+
const refreshToken = data?.data?.refresh_token || data?.refresh_token;
|
|
4915
4971
|
if (token) {
|
|
4916
4972
|
try {
|
|
4917
4973
|
await page.context().addCookies([
|
|
@@ -4935,18 +4991,23 @@ async function loginViaApi(page, email, password) {
|
|
|
4935
4991
|
}).catch(() => {
|
|
4936
4992
|
});
|
|
4937
4993
|
if (token) {
|
|
4938
|
-
await page.evaluate(
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4994
|
+
await page.evaluate(
|
|
4995
|
+
({ tok, rTok }) => {
|
|
4996
|
+
try {
|
|
4997
|
+
localStorage.removeItem("qwen_token_logged_out_marker");
|
|
4998
|
+
localStorage.setItem("token", tok);
|
|
4999
|
+
localStorage.setItem("access_token", tok);
|
|
5000
|
+
if (rTok) localStorage.setItem("refresh_token", rTok);
|
|
5001
|
+
document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
5002
|
+
} catch {
|
|
5003
|
+
}
|
|
5004
|
+
},
|
|
5005
|
+
{ tok: token, rTok: refreshToken }
|
|
5006
|
+
).catch(() => {
|
|
4946
5007
|
});
|
|
4947
5008
|
await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
|
|
4948
5009
|
});
|
|
4949
|
-
return { success: true };
|
|
5010
|
+
return { success: true, token, refreshToken };
|
|
4950
5011
|
}
|
|
4951
5012
|
}
|
|
4952
5013
|
return {
|
|
@@ -4970,11 +5031,23 @@ async function loginViaApi(page, email, password) {
|
|
|
4970
5031
|
}
|
|
4971
5032
|
async function loginViaUi(page, email, password) {
|
|
4972
5033
|
try {
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
5034
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3).catch(() => false)) {
|
|
5035
|
+
return { success: true };
|
|
5036
|
+
}
|
|
5037
|
+
try {
|
|
5038
|
+
await page.goto(qwenUrl("/auth"), {
|
|
5039
|
+
waitUntil: "domcontentloaded",
|
|
5040
|
+
timeout: Math.min(config.timeouts.navigation, 15e3)
|
|
5041
|
+
});
|
|
5042
|
+
await sleep2(1e3);
|
|
5043
|
+
} catch (gotoErr) {
|
|
5044
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
5045
|
+
return { success: true };
|
|
5046
|
+
}
|
|
5047
|
+
}
|
|
5048
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
5049
|
+
return { success: true };
|
|
5050
|
+
}
|
|
4978
5051
|
const emailSelector = [
|
|
4979
5052
|
'input[type="email"]',
|
|
4980
5053
|
'input[name="email"]',
|
|
@@ -4984,7 +5057,7 @@ async function loginViaUi(page, email, password) {
|
|
|
4984
5057
|
].join(", ");
|
|
4985
5058
|
try {
|
|
4986
5059
|
await page.waitForSelector(emailSelector, {
|
|
4987
|
-
timeout: Math.min(config.timeouts.page,
|
|
5060
|
+
timeout: Math.min(config.timeouts.page, 5e3)
|
|
4988
5061
|
});
|
|
4989
5062
|
} catch {
|
|
4990
5063
|
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
@@ -4997,30 +5070,55 @@ async function loginViaUi(page, email, password) {
|
|
|
4997
5070
|
return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
|
|
4998
5071
|
}
|
|
4999
5072
|
await clearVisibleChallenge(page);
|
|
5000
|
-
const
|
|
5001
|
-
return page.locator('
|
|
5002
|
-
hasText: /(?:log\s*in\s*with\s*(?:a\s*)?password|fazer\s*login\s*com\s*senha|entrar\s*com\s*(?:uma\s*)?senha|iniciar\s*sesi[oó]n\s*con\s*contrase[nñ]a|密码登录)/i
|
|
5003
|
-
}).first();
|
|
5073
|
+
const isPasswordInputPresent = async () => {
|
|
5074
|
+
return await page.locator('input[type="password"], input[name="password"]').count().catch(() => 0) > 0;
|
|
5004
5075
|
};
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
|
|
5076
|
+
const revealPasswordMode = async () => {
|
|
5077
|
+
if (page.url().includes("/forget")) {
|
|
5078
|
+
await page.goto(qwenUrl("/auth"), { waitUntil: "domcontentloaded", timeout: 1e4 }).catch(() => {
|
|
5009
5079
|
});
|
|
5010
|
-
await sleep2(
|
|
5080
|
+
await sleep2(1e3);
|
|
5011
5081
|
}
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
if (await
|
|
5019
|
-
await
|
|
5082
|
+
if (await isPasswordInputPresent()) return;
|
|
5083
|
+
const btn = page.locator("button").filter({
|
|
5084
|
+
hasText: /(?:log\s*in\s*with\s*(?:a\s*)?password|fazer\s*login\s*com\s*senha|entrar\s*com\s*(?:uma\s*)?senha|iniciar\s*sesi[oó]n\s*con\s*contrase[nñ]a|密码登录)/i
|
|
5085
|
+
}).filter({
|
|
5086
|
+
hasNotText: /(?:esqueci|forgot|olvid|reset|recover)/i
|
|
5087
|
+
}).first();
|
|
5088
|
+
if (await btn.isVisible({ timeout: 1500 }).catch(() => false)) {
|
|
5089
|
+
await btn.click({ timeout: 2e3 }).catch(() => {
|
|
5020
5090
|
});
|
|
5021
5091
|
await sleep2(500);
|
|
5022
5092
|
}
|
|
5093
|
+
if (await isPasswordInputPresent()) return;
|
|
5094
|
+
await page.evaluate(() => {
|
|
5095
|
+
try {
|
|
5096
|
+
const buttons = Array.from(document.querySelectorAll("button, [role='button'], a"));
|
|
5097
|
+
for (const b of buttons) {
|
|
5098
|
+
const txt = (b.innerText || "").trim().toLowerCase();
|
|
5099
|
+
if (/(?:log\s*in\s*with\s*(?:a\s*)?password|fazer\s*login\s*com\s*senha|entrar\s*com\s*(?:uma\s*)?senha|iniciar\s*sesi[oó]n\s*con\s*contrase[nñ]a|密码登录)/i.test(txt) && !txt.includes("esqueci") && !txt.includes("forgot") && !txt.includes("olvid") && !txt.includes("reset")) {
|
|
5100
|
+
b.click();
|
|
5101
|
+
return true;
|
|
5102
|
+
}
|
|
5103
|
+
}
|
|
5104
|
+
} catch {
|
|
5105
|
+
}
|
|
5106
|
+
return false;
|
|
5107
|
+
}).catch(() => false);
|
|
5108
|
+
await sleep2(500);
|
|
5109
|
+
};
|
|
5110
|
+
await revealPasswordMode();
|
|
5111
|
+
try {
|
|
5112
|
+
await page.fill(emailSelector, email, { timeout: 8e3 });
|
|
5113
|
+
await sleep2(300);
|
|
5023
5114
|
} catch {
|
|
5115
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
5116
|
+
return { success: true };
|
|
5117
|
+
}
|
|
5118
|
+
throw new Error(`Campo de e-mail n\xE3o encontrado na tela de autentica\xE7\xE3o`);
|
|
5119
|
+
}
|
|
5120
|
+
if (!await isPasswordInputPresent()) {
|
|
5121
|
+
await revealPasswordMode();
|
|
5024
5122
|
}
|
|
5025
5123
|
const passwordSelector = 'input[type="password"], input[name="password"]';
|
|
5026
5124
|
try {
|
|
@@ -5039,17 +5137,50 @@ async function loginViaUi(page, email, password) {
|
|
|
5039
5137
|
reason: "Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o"
|
|
5040
5138
|
};
|
|
5041
5139
|
}
|
|
5042
|
-
|
|
5043
|
-
|
|
5140
|
+
try {
|
|
5141
|
+
await page.fill(passwordSelector, password, { timeout: 8e3 });
|
|
5142
|
+
await sleep2(500);
|
|
5143
|
+
} catch {
|
|
5144
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
5145
|
+
return { success: true };
|
|
5146
|
+
}
|
|
5147
|
+
throw new Error(`Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o`);
|
|
5148
|
+
}
|
|
5149
|
+
await page.evaluate(() => {
|
|
5150
|
+
try {
|
|
5151
|
+
const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
|
|
5152
|
+
const passEl = document.querySelector('input[type="password"], input[name="password"]');
|
|
5153
|
+
if (emailEl) {
|
|
5154
|
+
emailEl.dispatchEvent(new Event("input", { bubbles: true }));
|
|
5155
|
+
emailEl.dispatchEvent(new Event("change", { bubbles: true }));
|
|
5156
|
+
emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
5157
|
+
}
|
|
5158
|
+
if (passEl) {
|
|
5159
|
+
passEl.dispatchEvent(new Event("input", { bubbles: true }));
|
|
5160
|
+
passEl.dispatchEvent(new Event("change", { bubbles: true }));
|
|
5161
|
+
passEl.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
5162
|
+
}
|
|
5163
|
+
} catch {
|
|
5164
|
+
}
|
|
5165
|
+
}).catch(() => {
|
|
5166
|
+
});
|
|
5044
5167
|
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")';
|
|
5045
5168
|
const submitButton = page.locator(submitSelector).first();
|
|
5046
5169
|
try {
|
|
5047
5170
|
await page.waitForSelector('button[type="submit"]:not([disabled])', {
|
|
5048
|
-
timeout:
|
|
5171
|
+
timeout: 4e3
|
|
5049
5172
|
});
|
|
5050
5173
|
await submitButton.click();
|
|
5051
5174
|
} catch {
|
|
5052
|
-
await
|
|
5175
|
+
const isDisabled = await submitButton.isDisabled().catch(() => true);
|
|
5176
|
+
if (!isDisabled) {
|
|
5177
|
+
await submitButton.click({ force: true }).catch(() => {
|
|
5178
|
+
});
|
|
5179
|
+
} else {
|
|
5180
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
|
|
5181
|
+
return { success: true };
|
|
5182
|
+
}
|
|
5183
|
+
}
|
|
5053
5184
|
}
|
|
5054
5185
|
const postSubmitDeadline = Date.now() + 15e3;
|
|
5055
5186
|
while (Date.now() < postSubmitDeadline) {
|
|
@@ -5119,6 +5250,137 @@ async function loginViaUi(page, email, password) {
|
|
|
5119
5250
|
return { success: false, reason: err?.message || String(err) };
|
|
5120
5251
|
}
|
|
5121
5252
|
}
|
|
5253
|
+
async function refreshAccountToken(accountId) {
|
|
5254
|
+
const page = accountPages.get(accountId);
|
|
5255
|
+
if (!page || page.isClosed()) {
|
|
5256
|
+
return { success: false, error: "Account page not active" };
|
|
5257
|
+
}
|
|
5258
|
+
const { getValidAuthSession: getValidAuthSession2, saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
5259
|
+
const session = getValidAuthSession2(accountId);
|
|
5260
|
+
let refreshToken = session?.refreshToken;
|
|
5261
|
+
if (!refreshToken) {
|
|
5262
|
+
try {
|
|
5263
|
+
refreshToken = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
|
|
5264
|
+
} catch {
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5267
|
+
if (refreshToken) {
|
|
5268
|
+
try {
|
|
5269
|
+
const refreshResult = await page.evaluate(
|
|
5270
|
+
async ({ rTok }) => {
|
|
5271
|
+
try {
|
|
5272
|
+
const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
5273
|
+
method: "GET",
|
|
5274
|
+
credentials: "include",
|
|
5275
|
+
headers: {
|
|
5276
|
+
accept: "application/json, text/plain, */*",
|
|
5277
|
+
source: "web",
|
|
5278
|
+
version: "0.3.11",
|
|
5279
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
5280
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
5281
|
+
authorization: `Bearer ${rTok}`
|
|
5282
|
+
}
|
|
5283
|
+
});
|
|
5284
|
+
const json2 = await response.json().catch(() => null);
|
|
5285
|
+
return { ok: response.ok, status: response.status, data: json2 };
|
|
5286
|
+
} catch (e) {
|
|
5287
|
+
return { ok: false, error: e.message };
|
|
5288
|
+
}
|
|
5289
|
+
},
|
|
5290
|
+
{ rTok: refreshToken }
|
|
5291
|
+
);
|
|
5292
|
+
const json = refreshResult?.data;
|
|
5293
|
+
if (json && json.success === true && json.data) {
|
|
5294
|
+
const newAccessToken = json.data.access_token || json.data.token;
|
|
5295
|
+
const newRefreshToken = json.data.refresh_token || refreshToken;
|
|
5296
|
+
if (newAccessToken) {
|
|
5297
|
+
await page.context().addCookies([
|
|
5298
|
+
{
|
|
5299
|
+
name: "token",
|
|
5300
|
+
value: newAccessToken,
|
|
5301
|
+
domain: ".qwen.ai",
|
|
5302
|
+
path: "/",
|
|
5303
|
+
expires: Math.floor(Date.now() / 1e3) + 31536e3,
|
|
5304
|
+
httpOnly: false,
|
|
5305
|
+
secure: true,
|
|
5306
|
+
sameSite: "Lax"
|
|
5307
|
+
}
|
|
5308
|
+
]);
|
|
5309
|
+
await page.evaluate(
|
|
5310
|
+
({ tok, rTok }) => {
|
|
5311
|
+
try {
|
|
5312
|
+
localStorage.removeItem("qwen_token_logged_out_marker");
|
|
5313
|
+
localStorage.setItem("token", tok);
|
|
5314
|
+
localStorage.setItem("access_token", tok);
|
|
5315
|
+
if (rTok) localStorage.setItem("refresh_token", rTok);
|
|
5316
|
+
document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
5317
|
+
} catch {
|
|
5318
|
+
}
|
|
5319
|
+
},
|
|
5320
|
+
{ tok: newAccessToken, rTok: newRefreshToken }
|
|
5321
|
+
).catch(() => {
|
|
5322
|
+
});
|
|
5323
|
+
const liveCookies = await page.context().cookies();
|
|
5324
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
5325
|
+
const cache = getHeaderCache(accountId);
|
|
5326
|
+
cache.headers.cookie = cookieStr;
|
|
5327
|
+
cache.lastRefresh = Date.now();
|
|
5328
|
+
markAccountHeadersReady(accountId);
|
|
5329
|
+
saveAuthSession2(accountId, {
|
|
5330
|
+
cookie: cookieStr,
|
|
5331
|
+
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
5332
|
+
bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
|
|
5333
|
+
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
5334
|
+
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
5335
|
+
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
5336
|
+
secChUaMobile: cache.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
|
|
5337
|
+
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
|
|
5338
|
+
version: cache.headers["version"] || session?.version,
|
|
5339
|
+
userId: session?.userId,
|
|
5340
|
+
tokenExpiresAt: parseJwtExpiry(newAccessToken) || void 0,
|
|
5341
|
+
refreshToken: newRefreshToken,
|
|
5342
|
+
capturedAt: Date.now()
|
|
5343
|
+
});
|
|
5344
|
+
return { success: true, token: newAccessToken };
|
|
5345
|
+
}
|
|
5346
|
+
}
|
|
5347
|
+
} catch {
|
|
5348
|
+
}
|
|
5349
|
+
}
|
|
5350
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
5351
|
+
const creds = getAccountCredentials2(accountId);
|
|
5352
|
+
if (creds && creds.email && creds.password) {
|
|
5353
|
+
const apiResult = await loginViaApi(page, creds.email, creds.password);
|
|
5354
|
+
if (apiResult.success) {
|
|
5355
|
+
const liveCookies = await page.context().cookies();
|
|
5356
|
+
const tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
5357
|
+
if (tokenCookie) {
|
|
5358
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
5359
|
+
const cache = getHeaderCache(accountId);
|
|
5360
|
+
cache.headers.cookie = cookieStr;
|
|
5361
|
+
cache.lastRefresh = Date.now();
|
|
5362
|
+
markAccountHeadersReady(accountId);
|
|
5363
|
+
saveAuthSession2(accountId, {
|
|
5364
|
+
cookie: cookieStr,
|
|
5365
|
+
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
5366
|
+
bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
|
|
5367
|
+
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
5368
|
+
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
5369
|
+
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
5370
|
+
secChUaMobile: cache.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
|
|
5371
|
+
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
|
|
5372
|
+
version: cache.headers["version"] || session?.version,
|
|
5373
|
+
userId: session?.userId,
|
|
5374
|
+
tokenExpiresAt: parseJwtExpiry(tokenCookie.value) || void 0,
|
|
5375
|
+
refreshToken: apiResult.refreshToken,
|
|
5376
|
+
capturedAt: Date.now()
|
|
5377
|
+
});
|
|
5378
|
+
return { success: true, token: tokenCookie.value };
|
|
5379
|
+
}
|
|
5380
|
+
}
|
|
5381
|
+
}
|
|
5382
|
+
return { success: false, error: "Could not refresh or re-authenticate token" };
|
|
5383
|
+
}
|
|
5122
5384
|
async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
|
|
5123
5385
|
const page = pageOverride ?? accountPages.get(accountId);
|
|
5124
5386
|
if (!page || page.isClosed()) {
|
|
@@ -5635,6 +5897,10 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
5635
5897
|
}
|
|
5636
5898
|
};
|
|
5637
5899
|
if (forceReauth) {
|
|
5900
|
+
const refreshed = await refreshAccountToken(accountId);
|
|
5901
|
+
if (refreshed.success) {
|
|
5902
|
+
return;
|
|
5903
|
+
}
|
|
5638
5904
|
await executeReauth();
|
|
5639
5905
|
} else {
|
|
5640
5906
|
try {
|
|
@@ -6069,19 +6335,15 @@ async function keepAlivePlaywrightAccount(accountId) {
|
|
|
6069
6335
|
const now = Date.now();
|
|
6070
6336
|
const currentUrl = page.url();
|
|
6071
6337
|
const cookie = await getCookies(accountId);
|
|
6072
|
-
if (cookie && isTokenExpiringSoon(cookie,
|
|
6338
|
+
if (cookie && isTokenExpiringSoon(cookie, 5)) {
|
|
6073
6339
|
console.log(
|
|
6074
|
-
`\u{1F493} [SessionKeeper] Account ${accountId} token
|
|
6340
|
+
`\u{1F493} [SessionKeeper] Account ${accountId} access token expiring soon (<5m); silently refreshing...`
|
|
6075
6341
|
);
|
|
6076
|
-
|
|
6077
|
-
|
|
6342
|
+
const res = await refreshAccountToken(accountId);
|
|
6343
|
+
if (res.success) {
|
|
6078
6344
|
lastKeepAliveNavigation.set(accountId, now);
|
|
6079
6345
|
touchAccountActivity(accountId);
|
|
6080
6346
|
return true;
|
|
6081
|
-
} catch (err) {
|
|
6082
|
-
console.warn(
|
|
6083
|
-
`[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
|
|
6084
|
-
);
|
|
6085
6347
|
}
|
|
6086
6348
|
}
|
|
6087
6349
|
const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;
|