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/index.js
CHANGED
|
@@ -1608,6 +1608,7 @@ function runMigrations(db2) {
|
|
|
1608
1608
|
"sec_ch_ua_mobile TEXT",
|
|
1609
1609
|
"sec_ch_ua_platform TEXT",
|
|
1610
1610
|
"version TEXT",
|
|
1611
|
+
"refresh_token TEXT",
|
|
1611
1612
|
"captured_at INTEGER DEFAULT 0"
|
|
1612
1613
|
];
|
|
1613
1614
|
for (const col of authSessionCols) {
|
|
@@ -1686,11 +1687,11 @@ function saveAuthSession(accountId, session) {
|
|
|
1686
1687
|
INSERT OR REPLACE INTO qwen_auth_sessions (
|
|
1687
1688
|
account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
|
|
1688
1689
|
sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
|
|
1689
|
-
user_id, token_expires_at, captured_at, updated_at
|
|
1690
|
+
user_id, token_expires_at, refresh_token, captured_at, updated_at
|
|
1690
1691
|
) VALUES (
|
|
1691
1692
|
?, ?, ?, ?, ?, ?,
|
|
1692
1693
|
?, ?, ?, ?,
|
|
1693
|
-
?, ?, ?, datetime('now')
|
|
1694
|
+
?, ?, ?, ?, datetime('now')
|
|
1694
1695
|
)
|
|
1695
1696
|
`);
|
|
1696
1697
|
stmt.run(
|
|
@@ -1706,6 +1707,7 @@ function saveAuthSession(accountId, session) {
|
|
|
1706
1707
|
session.version || null,
|
|
1707
1708
|
session.userId || null,
|
|
1708
1709
|
session.tokenExpiresAt || null,
|
|
1710
|
+
session.refreshToken || null,
|
|
1709
1711
|
session.capturedAt ?? Date.now()
|
|
1710
1712
|
);
|
|
1711
1713
|
}
|
|
@@ -1714,7 +1716,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
1714
1716
|
const row = database.prepare(
|
|
1715
1717
|
`SELECT account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
|
|
1716
1718
|
sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
|
|
1717
|
-
user_id, token_expires_at, captured_at
|
|
1719
|
+
user_id, token_expires_at, refresh_token, captured_at
|
|
1718
1720
|
FROM qwen_auth_sessions WHERE account_id = ?`
|
|
1719
1721
|
).get(accountId);
|
|
1720
1722
|
if (!row) return null;
|
|
@@ -1722,7 +1724,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
1722
1724
|
if (capturedAt <= 0 || Date.now() - capturedAt > maxAgeMs) {
|
|
1723
1725
|
return null;
|
|
1724
1726
|
}
|
|
1725
|
-
if (row.token_expires_at) {
|
|
1727
|
+
if (!row.refresh_token && row.token_expires_at) {
|
|
1726
1728
|
const tokenExpMs = Number(row.token_expires_at) * 1e3;
|
|
1727
1729
|
if (tokenExpMs <= Date.now() + 5 * 60 * 1e3) {
|
|
1728
1730
|
return null;
|
|
@@ -1744,6 +1746,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
1744
1746
|
version: row.version || void 0,
|
|
1745
1747
|
userId: row.user_id || void 0,
|
|
1746
1748
|
tokenExpiresAt: row.token_expires_at ? Number(row.token_expires_at) : void 0,
|
|
1749
|
+
refreshToken: row.refresh_token || void 0,
|
|
1747
1750
|
capturedAt
|
|
1748
1751
|
};
|
|
1749
1752
|
}
|
|
@@ -4269,6 +4272,7 @@ __export(playwright_exports, {
|
|
|
4269
4272
|
parseCookiesForBrowser: () => parseCookiesForBrowser,
|
|
4270
4273
|
pruneAllPlaywrightProfiles: () => pruneAllPlaywrightProfiles,
|
|
4271
4274
|
prunePlaywrightProfileCaches: () => prunePlaywrightProfileCaches,
|
|
4275
|
+
refreshAccountToken: () => refreshAccountToken,
|
|
4272
4276
|
refreshHeaders: () => refreshHeaders,
|
|
4273
4277
|
refreshHeadersWithProfileReset: () => refreshHeadersWithProfileReset,
|
|
4274
4278
|
registerPlaywrightAccountForTests: () => registerPlaywrightAccountForTests,
|
|
@@ -4996,8 +5000,29 @@ function getStealthScript(profile) {
|
|
|
4996
5000
|
const _toBlob = HTMLCanvasElement.prototype.toBlob;
|
|
4997
5001
|
const _getImageData = CanvasRenderingContext2D.prototype.getImageData;
|
|
4998
5002
|
|
|
5003
|
+
function isCaptchaCanvas(canvas) {
|
|
5004
|
+
try {
|
|
5005
|
+
if (!canvas) return false;
|
|
5006
|
+
const id = (canvas.id || "").toLowerCase();
|
|
5007
|
+
const cls = (canvas.className || "").toLowerCase();
|
|
5008
|
+
return (
|
|
5009
|
+
id.includes("baxia") ||
|
|
5010
|
+
id.includes("nc_") ||
|
|
5011
|
+
id.includes("captcha") ||
|
|
5012
|
+
id.includes("punish") ||
|
|
5013
|
+
cls.includes("baxia") ||
|
|
5014
|
+
cls.includes("nc_") ||
|
|
5015
|
+
cls.includes("captcha") ||
|
|
5016
|
+
Boolean(canvas.closest?.("#baxia-dialog, #baxia-punish, [class*='baxia'], [class*='nc_'], .auth-layout"))
|
|
5017
|
+
);
|
|
5018
|
+
} catch(e) {
|
|
5019
|
+
return false;
|
|
5020
|
+
}
|
|
5021
|
+
}
|
|
5022
|
+
|
|
4999
5023
|
function addNoise(canvas) {
|
|
5000
5024
|
try {
|
|
5025
|
+
if (isCaptchaCanvas(canvas)) return;
|
|
5001
5026
|
const ctx = canvas.getContext('2d');
|
|
5002
5027
|
if (!ctx) return;
|
|
5003
5028
|
const style = ctx.fillStyle;
|
|
@@ -5021,6 +5046,9 @@ function getStealthScript(profile) {
|
|
|
5021
5046
|
|
|
5022
5047
|
CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
|
|
5023
5048
|
const imageData = _getImageData.apply(this, arguments);
|
|
5049
|
+
if (isCaptchaCanvas(this.canvas)) {
|
|
5050
|
+
return imageData;
|
|
5051
|
+
}
|
|
5024
5052
|
const data = imageData.data;
|
|
5025
5053
|
const maxPixels = Math.min(data.length / 4, 2500);
|
|
5026
5054
|
for (let i = 0; i < maxPixels * 4; i += 4) {
|
|
@@ -5880,6 +5908,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5880
5908
|
secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || void 0,
|
|
5881
5909
|
version: cache3.headers["version"] || void 0,
|
|
5882
5910
|
tokenExpiresAt: exp || void 0,
|
|
5911
|
+
refreshToken: apiResult.refreshToken,
|
|
5883
5912
|
capturedAt: Date.now()
|
|
5884
5913
|
});
|
|
5885
5914
|
}
|
|
@@ -5913,6 +5942,13 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5913
5942
|
markAccountHeadersReady(accountId);
|
|
5914
5943
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
5915
5944
|
const exp = parseJwtExpiry(tokenCookie.value);
|
|
5945
|
+
let rTok = uiResult.refreshToken;
|
|
5946
|
+
if (!rTok) {
|
|
5947
|
+
try {
|
|
5948
|
+
rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
|
|
5949
|
+
} catch {
|
|
5950
|
+
}
|
|
5951
|
+
}
|
|
5916
5952
|
saveAuthSession2(accountId, {
|
|
5917
5953
|
cookie: cookieStr,
|
|
5918
5954
|
userAgent: cache3.headers["user-agent"] || "",
|
|
@@ -5924,6 +5960,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5924
5960
|
secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || void 0,
|
|
5925
5961
|
version: cache3.headers["version"] || void 0,
|
|
5926
5962
|
tokenExpiresAt: exp || void 0,
|
|
5963
|
+
refreshToken: rTok,
|
|
5927
5964
|
capturedAt: Date.now()
|
|
5928
5965
|
});
|
|
5929
5966
|
}
|
|
@@ -5976,37 +6013,52 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5976
6013
|
async function loginViaApi(page, email, password) {
|
|
5977
6014
|
try {
|
|
5978
6015
|
const hashedPassword = crypto5.createHash("sha256").update(password).digest("hex");
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
email,
|
|
5987
|
-
password: hashedPassword,
|
|
5988
|
-
login_type: "email"
|
|
5989
|
-
},
|
|
5990
|
-
headers: {
|
|
5991
|
-
"content-type": "application/json",
|
|
5992
|
-
accept: "application/json, text/plain, */*",
|
|
5993
|
-
referer: qwenUrl("/auth"),
|
|
5994
|
-
origin: qwenOrigin(),
|
|
5995
|
-
source: "web"
|
|
5996
|
-
},
|
|
5997
|
-
timeout: 1e4
|
|
5998
|
-
});
|
|
5999
|
-
data = await response.json().catch(() => null);
|
|
6000
|
-
signinSuccess = Boolean(data && (data.success === true || data.token));
|
|
6001
|
-
} catch {
|
|
6002
|
-
}
|
|
6016
|
+
if (!page.url().includes("/auth")) {
|
|
6017
|
+
await page.goto(qwenUrl("/auth"), {
|
|
6018
|
+
waitUntil: "domcontentloaded",
|
|
6019
|
+
timeout: config.timeouts.navigation
|
|
6020
|
+
}).catch(() => {
|
|
6021
|
+
});
|
|
6022
|
+
await sleep2(1e3);
|
|
6003
6023
|
}
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6024
|
+
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
6025
|
+
const requestId = crypto5.randomUUID();
|
|
6026
|
+
const evalRes = await page.evaluate(
|
|
6027
|
+
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
|
|
6028
|
+
try {
|
|
6029
|
+
const response = await fetch(signinUrl2, {
|
|
6030
|
+
method: "POST",
|
|
6031
|
+
signal: AbortSignal.timeout(15e3),
|
|
6032
|
+
credentials: "include",
|
|
6033
|
+
headers: {
|
|
6034
|
+
accept: "application/json, text/plain, */*",
|
|
6035
|
+
"content-type": "application/json",
|
|
6036
|
+
source: "web",
|
|
6037
|
+
version: "0.3.11",
|
|
6038
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
6039
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
6040
|
+
"x-request-id": requestId2
|
|
6041
|
+
},
|
|
6042
|
+
body: JSON.stringify({ email: email2, password: password2 })
|
|
6043
|
+
});
|
|
6044
|
+
const json = await response.json().catch(() => null);
|
|
6045
|
+
return { ok: response.ok, status: response.status, data: json };
|
|
6046
|
+
} catch (e) {
|
|
6047
|
+
return { ok: false, error: e.message };
|
|
6048
|
+
}
|
|
6049
|
+
},
|
|
6050
|
+
{ email, password: hashedPassword, signinUrl, requestId }
|
|
6051
|
+
).catch(() => null);
|
|
6052
|
+
let data = evalRes?.data;
|
|
6053
|
+
let signinSuccess = Boolean(
|
|
6054
|
+
data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
|
|
6055
|
+
);
|
|
6056
|
+
if (!signinSuccess && !data?.data?.code) {
|
|
6057
|
+
const fallbackUrl = qwenUrl("/api/v2/auths/signin");
|
|
6058
|
+
const fallbackRes = await page.evaluate(
|
|
6059
|
+
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
|
|
6008
6060
|
try {
|
|
6009
|
-
const response = await fetch(
|
|
6061
|
+
const response = await fetch(fallbackUrl2, {
|
|
6010
6062
|
method: "POST",
|
|
6011
6063
|
signal: AbortSignal.timeout(1e4),
|
|
6012
6064
|
credentials: "include",
|
|
@@ -6014,10 +6066,11 @@ async function loginViaApi(page, email, password) {
|
|
|
6014
6066
|
accept: "application/json, text/plain, */*",
|
|
6015
6067
|
"content-type": "application/json",
|
|
6016
6068
|
source: "web",
|
|
6069
|
+
version: "0.3.11",
|
|
6017
6070
|
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
6018
6071
|
"x-request-id": requestId2
|
|
6019
6072
|
},
|
|
6020
|
-
body: JSON.stringify({ email: email2, password: password2
|
|
6073
|
+
body: JSON.stringify({ email: email2, password: password2 })
|
|
6021
6074
|
});
|
|
6022
6075
|
const json = await response.json().catch(() => null);
|
|
6023
6076
|
return { ok: response.ok, status: response.status, data: json };
|
|
@@ -6025,11 +6078,13 @@ async function loginViaApi(page, email, password) {
|
|
|
6025
6078
|
return { ok: false, error: e.message };
|
|
6026
6079
|
}
|
|
6027
6080
|
},
|
|
6028
|
-
{ email, password: hashedPassword,
|
|
6081
|
+
{ email, password: hashedPassword, fallbackUrl, requestId }
|
|
6029
6082
|
).catch(() => null);
|
|
6030
|
-
if (
|
|
6031
|
-
data =
|
|
6032
|
-
signinSuccess = Boolean(
|
|
6083
|
+
if (fallbackRes?.data) {
|
|
6084
|
+
data = fallbackRes.data;
|
|
6085
|
+
signinSuccess = Boolean(
|
|
6086
|
+
data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
|
|
6087
|
+
);
|
|
6033
6088
|
}
|
|
6034
6089
|
}
|
|
6035
6090
|
if (data?.success === false) {
|
|
@@ -6043,7 +6098,8 @@ async function loginViaApi(page, email, password) {
|
|
|
6043
6098
|
};
|
|
6044
6099
|
}
|
|
6045
6100
|
if (signinSuccess) {
|
|
6046
|
-
const token = data?.data?.token || data?.token;
|
|
6101
|
+
const token = data?.data?.access_token || data?.data?.token || data?.access_token || data?.token;
|
|
6102
|
+
const refreshToken = data?.data?.refresh_token || data?.refresh_token;
|
|
6047
6103
|
if (token) {
|
|
6048
6104
|
try {
|
|
6049
6105
|
await page.context().addCookies([
|
|
@@ -6067,18 +6123,23 @@ async function loginViaApi(page, email, password) {
|
|
|
6067
6123
|
}).catch(() => {
|
|
6068
6124
|
});
|
|
6069
6125
|
if (token) {
|
|
6070
|
-
await page.evaluate(
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6126
|
+
await page.evaluate(
|
|
6127
|
+
({ tok, rTok }) => {
|
|
6128
|
+
try {
|
|
6129
|
+
localStorage.removeItem("qwen_token_logged_out_marker");
|
|
6130
|
+
localStorage.setItem("token", tok);
|
|
6131
|
+
localStorage.setItem("access_token", tok);
|
|
6132
|
+
if (rTok) localStorage.setItem("refresh_token", rTok);
|
|
6133
|
+
document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
6134
|
+
} catch {
|
|
6135
|
+
}
|
|
6136
|
+
},
|
|
6137
|
+
{ tok: token, rTok: refreshToken }
|
|
6138
|
+
).catch(() => {
|
|
6078
6139
|
});
|
|
6079
6140
|
await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
|
|
6080
6141
|
});
|
|
6081
|
-
return { success: true };
|
|
6142
|
+
return { success: true, token, refreshToken };
|
|
6082
6143
|
}
|
|
6083
6144
|
}
|
|
6084
6145
|
return {
|
|
@@ -6102,11 +6163,23 @@ async function loginViaApi(page, email, password) {
|
|
|
6102
6163
|
}
|
|
6103
6164
|
async function loginViaUi(page, email, password) {
|
|
6104
6165
|
try {
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6166
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3).catch(() => false)) {
|
|
6167
|
+
return { success: true };
|
|
6168
|
+
}
|
|
6169
|
+
try {
|
|
6170
|
+
await page.goto(qwenUrl("/auth"), {
|
|
6171
|
+
waitUntil: "domcontentloaded",
|
|
6172
|
+
timeout: Math.min(config.timeouts.navigation, 15e3)
|
|
6173
|
+
});
|
|
6174
|
+
await sleep2(1e3);
|
|
6175
|
+
} catch (gotoErr) {
|
|
6176
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
6177
|
+
return { success: true };
|
|
6178
|
+
}
|
|
6179
|
+
}
|
|
6180
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
6181
|
+
return { success: true };
|
|
6182
|
+
}
|
|
6110
6183
|
const emailSelector = [
|
|
6111
6184
|
'input[type="email"]',
|
|
6112
6185
|
'input[name="email"]',
|
|
@@ -6116,7 +6189,7 @@ async function loginViaUi(page, email, password) {
|
|
|
6116
6189
|
].join(", ");
|
|
6117
6190
|
try {
|
|
6118
6191
|
await page.waitForSelector(emailSelector, {
|
|
6119
|
-
timeout: Math.min(config.timeouts.page,
|
|
6192
|
+
timeout: Math.min(config.timeouts.page, 5e3)
|
|
6120
6193
|
});
|
|
6121
6194
|
} catch {
|
|
6122
6195
|
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
@@ -6129,30 +6202,55 @@ async function loginViaUi(page, email, password) {
|
|
|
6129
6202
|
return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
|
|
6130
6203
|
}
|
|
6131
6204
|
await clearVisibleChallenge(page);
|
|
6132
|
-
const
|
|
6133
|
-
return page.locator('
|
|
6134
|
-
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
|
|
6135
|
-
}).first();
|
|
6205
|
+
const isPasswordInputPresent = async () => {
|
|
6206
|
+
return await page.locator('input[type="password"], input[name="password"]').count().catch(() => 0) > 0;
|
|
6136
6207
|
};
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
|
|
6208
|
+
const revealPasswordMode = async () => {
|
|
6209
|
+
if (page.url().includes("/forget")) {
|
|
6210
|
+
await page.goto(qwenUrl("/auth"), { waitUntil: "domcontentloaded", timeout: 1e4 }).catch(() => {
|
|
6141
6211
|
});
|
|
6142
|
-
await sleep2(
|
|
6212
|
+
await sleep2(1e3);
|
|
6143
6213
|
}
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
if (await
|
|
6151
|
-
await
|
|
6214
|
+
if (await isPasswordInputPresent()) return;
|
|
6215
|
+
const btn = page.locator("button").filter({
|
|
6216
|
+
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
|
|
6217
|
+
}).filter({
|
|
6218
|
+
hasNotText: /(?:esqueci|forgot|olvid|reset|recover)/i
|
|
6219
|
+
}).first();
|
|
6220
|
+
if (await btn.isVisible({ timeout: 1500 }).catch(() => false)) {
|
|
6221
|
+
await btn.click({ timeout: 2e3 }).catch(() => {
|
|
6152
6222
|
});
|
|
6153
6223
|
await sleep2(500);
|
|
6154
6224
|
}
|
|
6225
|
+
if (await isPasswordInputPresent()) return;
|
|
6226
|
+
await page.evaluate(() => {
|
|
6227
|
+
try {
|
|
6228
|
+
const buttons = Array.from(document.querySelectorAll("button, [role='button'], a"));
|
|
6229
|
+
for (const b of buttons) {
|
|
6230
|
+
const txt = (b.innerText || "").trim().toLowerCase();
|
|
6231
|
+
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")) {
|
|
6232
|
+
b.click();
|
|
6233
|
+
return true;
|
|
6234
|
+
}
|
|
6235
|
+
}
|
|
6236
|
+
} catch {
|
|
6237
|
+
}
|
|
6238
|
+
return false;
|
|
6239
|
+
}).catch(() => false);
|
|
6240
|
+
await sleep2(500);
|
|
6241
|
+
};
|
|
6242
|
+
await revealPasswordMode();
|
|
6243
|
+
try {
|
|
6244
|
+
await page.fill(emailSelector, email, { timeout: 8e3 });
|
|
6245
|
+
await sleep2(300);
|
|
6155
6246
|
} catch {
|
|
6247
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
6248
|
+
return { success: true };
|
|
6249
|
+
}
|
|
6250
|
+
throw new Error(`Campo de e-mail n\xE3o encontrado na tela de autentica\xE7\xE3o`);
|
|
6251
|
+
}
|
|
6252
|
+
if (!await isPasswordInputPresent()) {
|
|
6253
|
+
await revealPasswordMode();
|
|
6156
6254
|
}
|
|
6157
6255
|
const passwordSelector = 'input[type="password"], input[name="password"]';
|
|
6158
6256
|
try {
|
|
@@ -6171,17 +6269,50 @@ async function loginViaUi(page, email, password) {
|
|
|
6171
6269
|
reason: "Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o"
|
|
6172
6270
|
};
|
|
6173
6271
|
}
|
|
6174
|
-
|
|
6175
|
-
|
|
6272
|
+
try {
|
|
6273
|
+
await page.fill(passwordSelector, password, { timeout: 8e3 });
|
|
6274
|
+
await sleep2(500);
|
|
6275
|
+
} catch {
|
|
6276
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
6277
|
+
return { success: true };
|
|
6278
|
+
}
|
|
6279
|
+
throw new Error(`Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o`);
|
|
6280
|
+
}
|
|
6281
|
+
await page.evaluate(() => {
|
|
6282
|
+
try {
|
|
6283
|
+
const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
|
|
6284
|
+
const passEl = document.querySelector('input[type="password"], input[name="password"]');
|
|
6285
|
+
if (emailEl) {
|
|
6286
|
+
emailEl.dispatchEvent(new Event("input", { bubbles: true }));
|
|
6287
|
+
emailEl.dispatchEvent(new Event("change", { bubbles: true }));
|
|
6288
|
+
emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
6289
|
+
}
|
|
6290
|
+
if (passEl) {
|
|
6291
|
+
passEl.dispatchEvent(new Event("input", { bubbles: true }));
|
|
6292
|
+
passEl.dispatchEvent(new Event("change", { bubbles: true }));
|
|
6293
|
+
passEl.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
6294
|
+
}
|
|
6295
|
+
} catch {
|
|
6296
|
+
}
|
|
6297
|
+
}).catch(() => {
|
|
6298
|
+
});
|
|
6176
6299
|
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")';
|
|
6177
6300
|
const submitButton = page.locator(submitSelector).first();
|
|
6178
6301
|
try {
|
|
6179
6302
|
await page.waitForSelector('button[type="submit"]:not([disabled])', {
|
|
6180
|
-
timeout:
|
|
6303
|
+
timeout: 4e3
|
|
6181
6304
|
});
|
|
6182
6305
|
await submitButton.click();
|
|
6183
6306
|
} catch {
|
|
6184
|
-
await
|
|
6307
|
+
const isDisabled = await submitButton.isDisabled().catch(() => true);
|
|
6308
|
+
if (!isDisabled) {
|
|
6309
|
+
await submitButton.click({ force: true }).catch(() => {
|
|
6310
|
+
});
|
|
6311
|
+
} else {
|
|
6312
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
|
|
6313
|
+
return { success: true };
|
|
6314
|
+
}
|
|
6315
|
+
}
|
|
6185
6316
|
}
|
|
6186
6317
|
const postSubmitDeadline = Date.now() + 15e3;
|
|
6187
6318
|
while (Date.now() < postSubmitDeadline) {
|
|
@@ -6251,6 +6382,137 @@ async function loginViaUi(page, email, password) {
|
|
|
6251
6382
|
return { success: false, reason: err?.message || String(err) };
|
|
6252
6383
|
}
|
|
6253
6384
|
}
|
|
6385
|
+
async function refreshAccountToken(accountId) {
|
|
6386
|
+
const page = accountPages.get(accountId);
|
|
6387
|
+
if (!page || page.isClosed()) {
|
|
6388
|
+
return { success: false, error: "Account page not active" };
|
|
6389
|
+
}
|
|
6390
|
+
const { getValidAuthSession: getValidAuthSession2, saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
6391
|
+
const session = getValidAuthSession2(accountId);
|
|
6392
|
+
let refreshToken = session?.refreshToken;
|
|
6393
|
+
if (!refreshToken) {
|
|
6394
|
+
try {
|
|
6395
|
+
refreshToken = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
|
|
6396
|
+
} catch {
|
|
6397
|
+
}
|
|
6398
|
+
}
|
|
6399
|
+
if (refreshToken) {
|
|
6400
|
+
try {
|
|
6401
|
+
const refreshResult = await page.evaluate(
|
|
6402
|
+
async ({ rTok }) => {
|
|
6403
|
+
try {
|
|
6404
|
+
const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
6405
|
+
method: "GET",
|
|
6406
|
+
credentials: "include",
|
|
6407
|
+
headers: {
|
|
6408
|
+
accept: "application/json, text/plain, */*",
|
|
6409
|
+
source: "web",
|
|
6410
|
+
version: "0.3.11",
|
|
6411
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
6412
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
6413
|
+
authorization: `Bearer ${rTok}`
|
|
6414
|
+
}
|
|
6415
|
+
});
|
|
6416
|
+
const json2 = await response.json().catch(() => null);
|
|
6417
|
+
return { ok: response.ok, status: response.status, data: json2 };
|
|
6418
|
+
} catch (e) {
|
|
6419
|
+
return { ok: false, error: e.message };
|
|
6420
|
+
}
|
|
6421
|
+
},
|
|
6422
|
+
{ rTok: refreshToken }
|
|
6423
|
+
);
|
|
6424
|
+
const json = refreshResult?.data;
|
|
6425
|
+
if (json && json.success === true && json.data) {
|
|
6426
|
+
const newAccessToken = json.data.access_token || json.data.token;
|
|
6427
|
+
const newRefreshToken = json.data.refresh_token || refreshToken;
|
|
6428
|
+
if (newAccessToken) {
|
|
6429
|
+
await page.context().addCookies([
|
|
6430
|
+
{
|
|
6431
|
+
name: "token",
|
|
6432
|
+
value: newAccessToken,
|
|
6433
|
+
domain: ".qwen.ai",
|
|
6434
|
+
path: "/",
|
|
6435
|
+
expires: Math.floor(Date.now() / 1e3) + 31536e3,
|
|
6436
|
+
httpOnly: false,
|
|
6437
|
+
secure: true,
|
|
6438
|
+
sameSite: "Lax"
|
|
6439
|
+
}
|
|
6440
|
+
]);
|
|
6441
|
+
await page.evaluate(
|
|
6442
|
+
({ tok, rTok }) => {
|
|
6443
|
+
try {
|
|
6444
|
+
localStorage.removeItem("qwen_token_logged_out_marker");
|
|
6445
|
+
localStorage.setItem("token", tok);
|
|
6446
|
+
localStorage.setItem("access_token", tok);
|
|
6447
|
+
if (rTok) localStorage.setItem("refresh_token", rTok);
|
|
6448
|
+
document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
6449
|
+
} catch {
|
|
6450
|
+
}
|
|
6451
|
+
},
|
|
6452
|
+
{ tok: newAccessToken, rTok: newRefreshToken }
|
|
6453
|
+
).catch(() => {
|
|
6454
|
+
});
|
|
6455
|
+
const liveCookies = await page.context().cookies();
|
|
6456
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
6457
|
+
const cache3 = getHeaderCache(accountId);
|
|
6458
|
+
cache3.headers.cookie = cookieStr;
|
|
6459
|
+
cache3.lastRefresh = Date.now();
|
|
6460
|
+
markAccountHeadersReady(accountId);
|
|
6461
|
+
saveAuthSession2(accountId, {
|
|
6462
|
+
cookie: cookieStr,
|
|
6463
|
+
userAgent: cache3.headers["user-agent"] || session?.userAgent || "",
|
|
6464
|
+
bxV: cache3.headers["bx-v"] || session?.bxV || "2.5.37",
|
|
6465
|
+
bxUa: cache3.headers["bx-ua"] || session?.bxUa || "",
|
|
6466
|
+
bxUmidtoken: cache3.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
6467
|
+
secChUa: cache3.headers["sec-ch-ua"] || session?.secChUa,
|
|
6468
|
+
secChUaMobile: cache3.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
|
|
6469
|
+
secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
|
|
6470
|
+
version: cache3.headers["version"] || session?.version,
|
|
6471
|
+
userId: session?.userId,
|
|
6472
|
+
tokenExpiresAt: parseJwtExpiry(newAccessToken) || void 0,
|
|
6473
|
+
refreshToken: newRefreshToken,
|
|
6474
|
+
capturedAt: Date.now()
|
|
6475
|
+
});
|
|
6476
|
+
return { success: true, token: newAccessToken };
|
|
6477
|
+
}
|
|
6478
|
+
}
|
|
6479
|
+
} catch {
|
|
6480
|
+
}
|
|
6481
|
+
}
|
|
6482
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
6483
|
+
const creds = getAccountCredentials2(accountId);
|
|
6484
|
+
if (creds && creds.email && creds.password) {
|
|
6485
|
+
const apiResult = await loginViaApi(page, creds.email, creds.password);
|
|
6486
|
+
if (apiResult.success) {
|
|
6487
|
+
const liveCookies = await page.context().cookies();
|
|
6488
|
+
const tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
6489
|
+
if (tokenCookie) {
|
|
6490
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
6491
|
+
const cache3 = getHeaderCache(accountId);
|
|
6492
|
+
cache3.headers.cookie = cookieStr;
|
|
6493
|
+
cache3.lastRefresh = Date.now();
|
|
6494
|
+
markAccountHeadersReady(accountId);
|
|
6495
|
+
saveAuthSession2(accountId, {
|
|
6496
|
+
cookie: cookieStr,
|
|
6497
|
+
userAgent: cache3.headers["user-agent"] || session?.userAgent || "",
|
|
6498
|
+
bxV: cache3.headers["bx-v"] || session?.bxV || "2.5.37",
|
|
6499
|
+
bxUa: cache3.headers["bx-ua"] || session?.bxUa || "",
|
|
6500
|
+
bxUmidtoken: cache3.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
6501
|
+
secChUa: cache3.headers["sec-ch-ua"] || session?.secChUa,
|
|
6502
|
+
secChUaMobile: cache3.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
|
|
6503
|
+
secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
|
|
6504
|
+
version: cache3.headers["version"] || session?.version,
|
|
6505
|
+
userId: session?.userId,
|
|
6506
|
+
tokenExpiresAt: parseJwtExpiry(tokenCookie.value) || void 0,
|
|
6507
|
+
refreshToken: apiResult.refreshToken,
|
|
6508
|
+
capturedAt: Date.now()
|
|
6509
|
+
});
|
|
6510
|
+
return { success: true, token: tokenCookie.value };
|
|
6511
|
+
}
|
|
6512
|
+
}
|
|
6513
|
+
}
|
|
6514
|
+
return { success: false, error: "Could not refresh or re-authenticate token" };
|
|
6515
|
+
}
|
|
6254
6516
|
async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
|
|
6255
6517
|
const page = pageOverride ?? accountPages.get(accountId);
|
|
6256
6518
|
if (!page || page.isClosed()) {
|
|
@@ -6767,6 +7029,10 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
6767
7029
|
}
|
|
6768
7030
|
};
|
|
6769
7031
|
if (forceReauth) {
|
|
7032
|
+
const refreshed = await refreshAccountToken(accountId);
|
|
7033
|
+
if (refreshed.success) {
|
|
7034
|
+
return;
|
|
7035
|
+
}
|
|
6770
7036
|
await executeReauth();
|
|
6771
7037
|
} else {
|
|
6772
7038
|
try {
|
|
@@ -7201,19 +7467,15 @@ async function keepAlivePlaywrightAccount(accountId) {
|
|
|
7201
7467
|
const now = Date.now();
|
|
7202
7468
|
const currentUrl = page.url();
|
|
7203
7469
|
const cookie = await getCookies(accountId);
|
|
7204
|
-
if (cookie && isTokenExpiringSoon(cookie,
|
|
7470
|
+
if (cookie && isTokenExpiringSoon(cookie, 5)) {
|
|
7205
7471
|
console.log(
|
|
7206
|
-
`\u{1F493} [SessionKeeper] Account ${accountId} token
|
|
7472
|
+
`\u{1F493} [SessionKeeper] Account ${accountId} access token expiring soon (<5m); silently refreshing...`
|
|
7207
7473
|
);
|
|
7208
|
-
|
|
7209
|
-
|
|
7474
|
+
const res = await refreshAccountToken(accountId);
|
|
7475
|
+
if (res.success) {
|
|
7210
7476
|
lastKeepAliveNavigation.set(accountId, now);
|
|
7211
7477
|
touchAccountActivity(accountId);
|
|
7212
7478
|
return true;
|
|
7213
|
-
} catch (err) {
|
|
7214
|
-
console.warn(
|
|
7215
|
-
`[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
|
|
7216
|
-
);
|
|
7217
7479
|
}
|
|
7218
7480
|
}
|
|
7219
7481
|
const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;
|
|
@@ -9097,7 +9359,7 @@ function classifyRetryAction(err, options) {
|
|
|
9097
9359
|
accountCooldownReason: "PersonalizationFailed"
|
|
9098
9360
|
});
|
|
9099
9361
|
}
|
|
9100
|
-
if (code === "createchatinvalidresponse" || code === "createchatfailed" || code === "unauthorized" || message.includes("401 n\xE3o autorizado") || message.includes("n\xE3o tem permiss\xE3o para acessar") || message.includes("401 unauthorized") || message.includes('"code":"unauthorized"') || message.includes('"code": "unauthorized"')) {
|
|
9362
|
+
if (code === "createchatinvalidresponse" || code === "createchatfailed" || code === "unauthorized" || message.includes("401 n\xE3o autorizado") || message.includes("n\xE3o tem permiss\xE3o para acessar") || message.includes("401 unauthorized") || message.includes('"code":"unauthorized"') || message.includes('"code": "unauthorized"') || message.includes("token has expired")) {
|
|
9101
9363
|
return makeRetryAction("account_initialization_failed", {
|
|
9102
9364
|
switchAccount: true,
|
|
9103
9365
|
forceNewChat: true,
|
|
@@ -10574,6 +10836,16 @@ async function createQwenChatSession(headers, model, accountId, chatMode = "thre
|
|
|
10574
10836
|
}
|
|
10575
10837
|
}
|
|
10576
10838
|
if (json?.data?.code === "Unauthorized" || json?.code === "Unauthorized" || rawLower.includes("unauthorized") || rawLower.includes("permission to access")) {
|
|
10839
|
+
if (accountId) {
|
|
10840
|
+
try {
|
|
10841
|
+
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
10842
|
+
const refreshed = await refreshAccountToken2(accountId);
|
|
10843
|
+
if (refreshed.success) {
|
|
10844
|
+
return createQwenChatSession(headers, model, accountId, chatMode);
|
|
10845
|
+
}
|
|
10846
|
+
} catch {
|
|
10847
|
+
}
|
|
10848
|
+
}
|
|
10577
10849
|
throw new QwenUpstreamError(
|
|
10578
10850
|
`Qwen create chat unauthorized: ${raw.substring(0, 300)}`,
|
|
10579
10851
|
"Unauthorized",
|
|
@@ -11269,16 +11541,28 @@ async function requestQwenTextInBrowser(accountId, method, path21, headers, body
|
|
|
11269
11541
|
});
|
|
11270
11542
|
if (response2.status === 401) {
|
|
11271
11543
|
try {
|
|
11272
|
-
const
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11544
|
+
const rTok = localStorage.getItem("refresh_token");
|
|
11545
|
+
if (rTok) {
|
|
11546
|
+
const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
11547
|
+
method: "GET",
|
|
11548
|
+
credentials: "include",
|
|
11549
|
+
headers: {
|
|
11550
|
+
accept: "application/json, text/plain, */*",
|
|
11551
|
+
source: "web",
|
|
11552
|
+
version: "0.3.11",
|
|
11553
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
11554
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
11555
|
+
authorization: `Bearer ${rTok}`
|
|
11556
|
+
},
|
|
11557
|
+
signal: AbortSignal.timeout(5e3)
|
|
11558
|
+
});
|
|
11278
11559
|
const refreshJson = await refreshRes.json().catch(() => null);
|
|
11279
|
-
|
|
11280
|
-
|
|
11560
|
+
const freshTok = refreshJson?.data?.access_token || refreshJson?.data?.token;
|
|
11561
|
+
const nextRTok = refreshJson?.data?.refresh_token;
|
|
11562
|
+
if (refreshJson?.success === true && freshTok) {
|
|
11281
11563
|
localStorage.setItem("token", freshTok);
|
|
11564
|
+
localStorage.setItem("access_token", freshTok);
|
|
11565
|
+
if (nextRTok) localStorage.setItem("refresh_token", nextRTok);
|
|
11282
11566
|
document.cookie = `token=${encodeURIComponent(freshTok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
11283
11567
|
if (headers2["authorization"] || headers2["Authorization"]) {
|
|
11284
11568
|
headers2["authorization"] = `Bearer ${freshTok}`;
|
|
@@ -11316,13 +11600,29 @@ async function requestQwenTextInBrowser(accountId, method, path21, headers, body
|
|
|
11316
11600
|
}
|
|
11317
11601
|
);
|
|
11318
11602
|
const recoverOnTimeout = !options.noMutexRecovery;
|
|
11319
|
-
|
|
11603
|
+
let response = await withQwenBrowserPage(
|
|
11320
11604
|
accountId,
|
|
11321
11605
|
evaluateRequest,
|
|
11322
11606
|
void 0,
|
|
11323
11607
|
options.timeoutMs,
|
|
11324
11608
|
recoverOnTimeout
|
|
11325
11609
|
);
|
|
11610
|
+
if (response.status === 401 && accountId) {
|
|
11611
|
+
try {
|
|
11612
|
+
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
11613
|
+
const refreshed = await refreshAccountToken2(accountId);
|
|
11614
|
+
if (refreshed.success) {
|
|
11615
|
+
response = await withQwenBrowserPage(
|
|
11616
|
+
accountId,
|
|
11617
|
+
evaluateRequest,
|
|
11618
|
+
void 0,
|
|
11619
|
+
options.timeoutMs,
|
|
11620
|
+
recoverOnTimeout
|
|
11621
|
+
);
|
|
11622
|
+
}
|
|
11623
|
+
} catch {
|
|
11624
|
+
}
|
|
11625
|
+
}
|
|
11326
11626
|
return new Response(response.raw, {
|
|
11327
11627
|
status: response.status,
|
|
11328
11628
|
headers: response.contentType ? { "content-type": response.contentType } : void 0
|
|
@@ -11845,7 +12145,11 @@ async function syncQwenRequestPersonalization(instruction, accountId, metadata =
|
|
|
11845
12145
|
);
|
|
11846
12146
|
try {
|
|
11847
12147
|
currentSettings = null;
|
|
11848
|
-
const {
|
|
12148
|
+
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
12149
|
+
if (accountId) {
|
|
12150
|
+
await refreshAccountToken2(accountId);
|
|
12151
|
+
}
|
|
12152
|
+
const { headers: freshHeaders } = await getQwenHeaders(false, accountId);
|
|
11849
12153
|
requestHeaders = buildCapturedQwenHeaders(freshHeaders, {
|
|
11850
12154
|
referer: qwenUrl("/settings/personalization")
|
|
11851
12155
|
});
|
|
@@ -25513,7 +25817,7 @@ function getAppVersion() {
|
|
|
25513
25817
|
}
|
|
25514
25818
|
} catch {
|
|
25515
25819
|
}
|
|
25516
|
-
cachedVersion = "v1.4.
|
|
25820
|
+
cachedVersion = "v1.4.8";
|
|
25517
25821
|
return cachedVersion;
|
|
25518
25822
|
}
|
|
25519
25823
|
var cachedVersion;
|