qwenproxy-cli 1.4.2 → 1.4.7
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 +242 -109
- package/dist/delete-chats.js +295 -120
- package/dist/index.js +296 -121
- package/dist/login.js +297 -121
- package/dist/reset-cooldowns.js +242 -109
- package/package.json +1 -1
- package/src/core/version.ts +1 -1
- package/src/login.ts +1 -1
- package/src/services/playwright.ts +352 -130
package/dist/index.js
CHANGED
|
@@ -4996,8 +4996,29 @@ function getStealthScript(profile) {
|
|
|
4996
4996
|
const _toBlob = HTMLCanvasElement.prototype.toBlob;
|
|
4997
4997
|
const _getImageData = CanvasRenderingContext2D.prototype.getImageData;
|
|
4998
4998
|
|
|
4999
|
+
function isCaptchaCanvas(canvas) {
|
|
5000
|
+
try {
|
|
5001
|
+
if (!canvas) return false;
|
|
5002
|
+
const id = (canvas.id || "").toLowerCase();
|
|
5003
|
+
const cls = (canvas.className || "").toLowerCase();
|
|
5004
|
+
return (
|
|
5005
|
+
id.includes("baxia") ||
|
|
5006
|
+
id.includes("nc_") ||
|
|
5007
|
+
id.includes("captcha") ||
|
|
5008
|
+
id.includes("punish") ||
|
|
5009
|
+
cls.includes("baxia") ||
|
|
5010
|
+
cls.includes("nc_") ||
|
|
5011
|
+
cls.includes("captcha") ||
|
|
5012
|
+
Boolean(canvas.closest?.("#baxia-dialog, #baxia-punish, [class*='baxia'], [class*='nc_'], .auth-layout"))
|
|
5013
|
+
);
|
|
5014
|
+
} catch(e) {
|
|
5015
|
+
return false;
|
|
5016
|
+
}
|
|
5017
|
+
}
|
|
5018
|
+
|
|
4999
5019
|
function addNoise(canvas) {
|
|
5000
5020
|
try {
|
|
5021
|
+
if (isCaptchaCanvas(canvas)) return;
|
|
5001
5022
|
const ctx = canvas.getContext('2d');
|
|
5002
5023
|
if (!ctx) return;
|
|
5003
5024
|
const style = ctx.fillStyle;
|
|
@@ -5021,6 +5042,9 @@ function getStealthScript(profile) {
|
|
|
5021
5042
|
|
|
5022
5043
|
CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
|
|
5023
5044
|
const imageData = _getImageData.apply(this, arguments);
|
|
5045
|
+
if (isCaptchaCanvas(this.canvas)) {
|
|
5046
|
+
return imageData;
|
|
5047
|
+
}
|
|
5024
5048
|
const data = imageData.data;
|
|
5025
5049
|
const maxPixels = Math.min(data.length / 4, 2500);
|
|
5026
5050
|
for (let i = 0; i < maxPixels * 4; i += 4) {
|
|
@@ -5944,8 +5968,9 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5944
5968
|
}
|
|
5945
5969
|
if (attempt < maxAttempts) {
|
|
5946
5970
|
const backoffMs = attempt * 5e3;
|
|
5971
|
+
const failReason = uiResult.reason || apiResult.reason || "falha tempor\xE1ria";
|
|
5947
5972
|
console.warn(
|
|
5948
|
-
`\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${
|
|
5973
|
+
`\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${failReason}), retrying in ${backoffMs / 1e3}s`
|
|
5949
5974
|
);
|
|
5950
5975
|
await sleep2(backoffMs);
|
|
5951
5976
|
}
|
|
@@ -5975,37 +6000,52 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5975
6000
|
async function loginViaApi(page, email, password) {
|
|
5976
6001
|
try {
|
|
5977
6002
|
const hashedPassword = crypto5.createHash("sha256").update(password).digest("hex");
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
email,
|
|
5986
|
-
password: hashedPassword,
|
|
5987
|
-
login_type: "email"
|
|
5988
|
-
},
|
|
5989
|
-
headers: {
|
|
5990
|
-
"content-type": "application/json",
|
|
5991
|
-
accept: "application/json, text/plain, */*",
|
|
5992
|
-
referer: qwenUrl("/auth"),
|
|
5993
|
-
origin: qwenOrigin(),
|
|
5994
|
-
source: "web"
|
|
5995
|
-
},
|
|
5996
|
-
timeout: 1e4
|
|
5997
|
-
});
|
|
5998
|
-
data = await response.json().catch(() => null);
|
|
5999
|
-
signinSuccess = Boolean(data && (data.success === true || data.token));
|
|
6000
|
-
} catch {
|
|
6001
|
-
}
|
|
6003
|
+
if (!page.url().includes("/auth")) {
|
|
6004
|
+
await page.goto(qwenUrl("/auth"), {
|
|
6005
|
+
waitUntil: "domcontentloaded",
|
|
6006
|
+
timeout: config.timeouts.navigation
|
|
6007
|
+
}).catch(() => {
|
|
6008
|
+
});
|
|
6009
|
+
await sleep2(1e3);
|
|
6002
6010
|
}
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6011
|
+
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
6012
|
+
const requestId = crypto5.randomUUID();
|
|
6013
|
+
const evalRes = await page.evaluate(
|
|
6014
|
+
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
|
|
6015
|
+
try {
|
|
6016
|
+
const response = await fetch(signinUrl2, {
|
|
6017
|
+
method: "POST",
|
|
6018
|
+
signal: AbortSignal.timeout(15e3),
|
|
6019
|
+
credentials: "include",
|
|
6020
|
+
headers: {
|
|
6021
|
+
accept: "application/json, text/plain, */*",
|
|
6022
|
+
"content-type": "application/json",
|
|
6023
|
+
source: "web",
|
|
6024
|
+
version: "0.3.11",
|
|
6025
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
6026
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
6027
|
+
"x-request-id": requestId2
|
|
6028
|
+
},
|
|
6029
|
+
body: JSON.stringify({ email: email2, password: password2 })
|
|
6030
|
+
});
|
|
6031
|
+
const json = await response.json().catch(() => null);
|
|
6032
|
+
return { ok: response.ok, status: response.status, data: json };
|
|
6033
|
+
} catch (e) {
|
|
6034
|
+
return { ok: false, error: e.message };
|
|
6035
|
+
}
|
|
6036
|
+
},
|
|
6037
|
+
{ email, password: hashedPassword, signinUrl, requestId }
|
|
6038
|
+
).catch(() => null);
|
|
6039
|
+
let data = evalRes?.data;
|
|
6040
|
+
let signinSuccess = Boolean(
|
|
6041
|
+
data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
|
|
6042
|
+
);
|
|
6043
|
+
if (!signinSuccess && !data?.data?.code) {
|
|
6044
|
+
const fallbackUrl = qwenUrl("/api/v2/auths/signin");
|
|
6045
|
+
const fallbackRes = await page.evaluate(
|
|
6046
|
+
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
|
|
6007
6047
|
try {
|
|
6008
|
-
const response = await fetch(
|
|
6048
|
+
const response = await fetch(fallbackUrl2, {
|
|
6009
6049
|
method: "POST",
|
|
6010
6050
|
signal: AbortSignal.timeout(1e4),
|
|
6011
6051
|
credentials: "include",
|
|
@@ -6013,10 +6053,11 @@ async function loginViaApi(page, email, password) {
|
|
|
6013
6053
|
accept: "application/json, text/plain, */*",
|
|
6014
6054
|
"content-type": "application/json",
|
|
6015
6055
|
source: "web",
|
|
6056
|
+
version: "0.3.11",
|
|
6016
6057
|
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
6017
6058
|
"x-request-id": requestId2
|
|
6018
6059
|
},
|
|
6019
|
-
body: JSON.stringify({ email: email2, password: password2
|
|
6060
|
+
body: JSON.stringify({ email: email2, password: password2 })
|
|
6020
6061
|
});
|
|
6021
6062
|
const json = await response.json().catch(() => null);
|
|
6022
6063
|
return { ok: response.ok, status: response.status, data: json };
|
|
@@ -6024,11 +6065,13 @@ async function loginViaApi(page, email, password) {
|
|
|
6024
6065
|
return { ok: false, error: e.message };
|
|
6025
6066
|
}
|
|
6026
6067
|
},
|
|
6027
|
-
{ email, password: hashedPassword,
|
|
6068
|
+
{ email, password: hashedPassword, fallbackUrl, requestId }
|
|
6028
6069
|
).catch(() => null);
|
|
6029
|
-
if (
|
|
6030
|
-
data =
|
|
6031
|
-
signinSuccess = Boolean(
|
|
6070
|
+
if (fallbackRes?.data) {
|
|
6071
|
+
data = fallbackRes.data;
|
|
6072
|
+
signinSuccess = Boolean(
|
|
6073
|
+
data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
|
|
6074
|
+
);
|
|
6032
6075
|
}
|
|
6033
6076
|
}
|
|
6034
6077
|
if (data?.success === false) {
|
|
@@ -6042,7 +6085,8 @@ async function loginViaApi(page, email, password) {
|
|
|
6042
6085
|
};
|
|
6043
6086
|
}
|
|
6044
6087
|
if (signinSuccess) {
|
|
6045
|
-
const token = data?.data?.token || data?.token;
|
|
6088
|
+
const token = data?.data?.access_token || data?.data?.token || data?.access_token || data?.token;
|
|
6089
|
+
const refreshToken = data?.data?.refresh_token || data?.refresh_token;
|
|
6046
6090
|
if (token) {
|
|
6047
6091
|
try {
|
|
6048
6092
|
await page.context().addCookies([
|
|
@@ -6066,14 +6110,19 @@ async function loginViaApi(page, email, password) {
|
|
|
6066
6110
|
}).catch(() => {
|
|
6067
6111
|
});
|
|
6068
6112
|
if (token) {
|
|
6069
|
-
await page.evaluate(
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6113
|
+
await page.evaluate(
|
|
6114
|
+
({ tok, rTok }) => {
|
|
6115
|
+
try {
|
|
6116
|
+
localStorage.removeItem("qwen_token_logged_out_marker");
|
|
6117
|
+
localStorage.setItem("token", tok);
|
|
6118
|
+
localStorage.setItem("access_token", tok);
|
|
6119
|
+
if (rTok) localStorage.setItem("refresh_token", rTok);
|
|
6120
|
+
document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
6121
|
+
} catch {
|
|
6122
|
+
}
|
|
6123
|
+
},
|
|
6124
|
+
{ tok: token, rTok: refreshToken }
|
|
6125
|
+
).catch(() => {
|
|
6077
6126
|
});
|
|
6078
6127
|
await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
|
|
6079
6128
|
});
|
|
@@ -6101,11 +6150,23 @@ async function loginViaApi(page, email, password) {
|
|
|
6101
6150
|
}
|
|
6102
6151
|
async function loginViaUi(page, email, password) {
|
|
6103
6152
|
try {
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6153
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3).catch(() => false)) {
|
|
6154
|
+
return { success: true };
|
|
6155
|
+
}
|
|
6156
|
+
try {
|
|
6157
|
+
await page.goto(qwenUrl("/auth"), {
|
|
6158
|
+
waitUntil: "domcontentloaded",
|
|
6159
|
+
timeout: Math.min(config.timeouts.navigation, 15e3)
|
|
6160
|
+
});
|
|
6161
|
+
await sleep2(1e3);
|
|
6162
|
+
} catch (gotoErr) {
|
|
6163
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
6164
|
+
return { success: true };
|
|
6165
|
+
}
|
|
6166
|
+
}
|
|
6167
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
6168
|
+
return { success: true };
|
|
6169
|
+
}
|
|
6109
6170
|
const emailSelector = [
|
|
6110
6171
|
'input[type="email"]',
|
|
6111
6172
|
'input[name="email"]',
|
|
@@ -6115,7 +6176,7 @@ async function loginViaUi(page, email, password) {
|
|
|
6115
6176
|
].join(", ");
|
|
6116
6177
|
try {
|
|
6117
6178
|
await page.waitForSelector(emailSelector, {
|
|
6118
|
-
timeout: Math.min(config.timeouts.page,
|
|
6179
|
+
timeout: Math.min(config.timeouts.page, 5e3)
|
|
6119
6180
|
});
|
|
6120
6181
|
} catch {
|
|
6121
6182
|
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
@@ -6128,30 +6189,55 @@ async function loginViaUi(page, email, password) {
|
|
|
6128
6189
|
return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
|
|
6129
6190
|
}
|
|
6130
6191
|
await clearVisibleChallenge(page);
|
|
6131
|
-
const
|
|
6132
|
-
return page.locator('
|
|
6133
|
-
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
|
|
6134
|
-
}).first();
|
|
6192
|
+
const isPasswordInputPresent = async () => {
|
|
6193
|
+
return await page.locator('input[type="password"], input[name="password"]').count().catch(() => 0) > 0;
|
|
6135
6194
|
};
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
|
|
6195
|
+
const revealPasswordMode = async () => {
|
|
6196
|
+
if (page.url().includes("/forget")) {
|
|
6197
|
+
await page.goto(qwenUrl("/auth"), { waitUntil: "domcontentloaded", timeout: 1e4 }).catch(() => {
|
|
6140
6198
|
});
|
|
6141
|
-
await sleep2(
|
|
6199
|
+
await sleep2(1e3);
|
|
6142
6200
|
}
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
if (await
|
|
6150
|
-
await
|
|
6201
|
+
if (await isPasswordInputPresent()) return;
|
|
6202
|
+
const btn = page.locator("button").filter({
|
|
6203
|
+
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
|
|
6204
|
+
}).filter({
|
|
6205
|
+
hasNotText: /(?:esqueci|forgot|olvid|reset|recover)/i
|
|
6206
|
+
}).first();
|
|
6207
|
+
if (await btn.isVisible({ timeout: 1500 }).catch(() => false)) {
|
|
6208
|
+
await btn.click({ timeout: 2e3 }).catch(() => {
|
|
6151
6209
|
});
|
|
6152
6210
|
await sleep2(500);
|
|
6153
6211
|
}
|
|
6212
|
+
if (await isPasswordInputPresent()) return;
|
|
6213
|
+
await page.evaluate(() => {
|
|
6214
|
+
try {
|
|
6215
|
+
const buttons = Array.from(document.querySelectorAll("button, [role='button'], a"));
|
|
6216
|
+
for (const b of buttons) {
|
|
6217
|
+
const txt = (b.innerText || "").trim().toLowerCase();
|
|
6218
|
+
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")) {
|
|
6219
|
+
b.click();
|
|
6220
|
+
return true;
|
|
6221
|
+
}
|
|
6222
|
+
}
|
|
6223
|
+
} catch {
|
|
6224
|
+
}
|
|
6225
|
+
return false;
|
|
6226
|
+
}).catch(() => false);
|
|
6227
|
+
await sleep2(500);
|
|
6228
|
+
};
|
|
6229
|
+
await revealPasswordMode();
|
|
6230
|
+
try {
|
|
6231
|
+
await page.fill(emailSelector, email, { timeout: 8e3 });
|
|
6232
|
+
await sleep2(300);
|
|
6154
6233
|
} catch {
|
|
6234
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
6235
|
+
return { success: true };
|
|
6236
|
+
}
|
|
6237
|
+
throw new Error(`Campo de e-mail n\xE3o encontrado na tela de autentica\xE7\xE3o`);
|
|
6238
|
+
}
|
|
6239
|
+
if (!await isPasswordInputPresent()) {
|
|
6240
|
+
await revealPasswordMode();
|
|
6155
6241
|
}
|
|
6156
6242
|
const passwordSelector = 'input[type="password"], input[name="password"]';
|
|
6157
6243
|
try {
|
|
@@ -6170,61 +6256,108 @@ async function loginViaUi(page, email, password) {
|
|
|
6170
6256
|
reason: "Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o"
|
|
6171
6257
|
};
|
|
6172
6258
|
}
|
|
6173
|
-
|
|
6174
|
-
|
|
6259
|
+
try {
|
|
6260
|
+
await page.fill(passwordSelector, password, { timeout: 8e3 });
|
|
6261
|
+
await sleep2(500);
|
|
6262
|
+
} catch {
|
|
6263
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
6264
|
+
return { success: true };
|
|
6265
|
+
}
|
|
6266
|
+
throw new Error(`Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o`);
|
|
6267
|
+
}
|
|
6268
|
+
await page.evaluate(() => {
|
|
6269
|
+
try {
|
|
6270
|
+
const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
|
|
6271
|
+
const passEl = document.querySelector('input[type="password"], input[name="password"]');
|
|
6272
|
+
if (emailEl) {
|
|
6273
|
+
emailEl.dispatchEvent(new Event("input", { bubbles: true }));
|
|
6274
|
+
emailEl.dispatchEvent(new Event("change", { bubbles: true }));
|
|
6275
|
+
emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
6276
|
+
}
|
|
6277
|
+
if (passEl) {
|
|
6278
|
+
passEl.dispatchEvent(new Event("input", { bubbles: true }));
|
|
6279
|
+
passEl.dispatchEvent(new Event("change", { bubbles: true }));
|
|
6280
|
+
passEl.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
6281
|
+
}
|
|
6282
|
+
} catch {
|
|
6283
|
+
}
|
|
6284
|
+
}).catch(() => {
|
|
6285
|
+
});
|
|
6175
6286
|
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")';
|
|
6176
6287
|
const submitButton = page.locator(submitSelector).first();
|
|
6177
6288
|
try {
|
|
6178
6289
|
await page.waitForSelector('button[type="submit"]:not([disabled])', {
|
|
6179
|
-
timeout:
|
|
6290
|
+
timeout: 4e3
|
|
6180
6291
|
});
|
|
6181
6292
|
await submitButton.click();
|
|
6182
6293
|
} catch {
|
|
6183
|
-
await
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
|
|
6193
|
-
const codeInput = page.locator(codeSelector).first();
|
|
6194
|
-
if (await codeInput.isVisible().catch(() => false)) {
|
|
6195
|
-
return {
|
|
6196
|
-
success: false,
|
|
6197
|
-
reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
|
|
6198
|
-
};
|
|
6294
|
+
const isDisabled = await submitButton.isDisabled().catch(() => true);
|
|
6295
|
+
if (!isDisabled) {
|
|
6296
|
+
await submitButton.click({ force: true }).catch(() => {
|
|
6297
|
+
});
|
|
6298
|
+
} else {
|
|
6299
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
|
|
6300
|
+
return { success: true };
|
|
6301
|
+
}
|
|
6302
|
+
}
|
|
6199
6303
|
}
|
|
6200
|
-
const
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6304
|
+
const postSubmitDeadline = Date.now() + 15e3;
|
|
6305
|
+
while (Date.now() < postSubmitDeadline) {
|
|
6306
|
+
if (page.isClosed()) break;
|
|
6307
|
+
if (config.captcha.enabled) {
|
|
6308
|
+
await solveBaxiaCaptcha(page, {
|
|
6309
|
+
waitForMs: 1500,
|
|
6310
|
+
maxAttempts: config.captcha.maxAttempts,
|
|
6311
|
+
retryDelayMs: config.captcha.retryDelayMs
|
|
6312
|
+
}).catch(() => {
|
|
6313
|
+
});
|
|
6314
|
+
}
|
|
6315
|
+
const errorSelector = [
|
|
6316
|
+
".qwen-chat-v2-toast-text",
|
|
6317
|
+
".qwen-chat-v2-toast-content",
|
|
6318
|
+
".ant-form-item-explain-error",
|
|
6319
|
+
".ant-message-error",
|
|
6320
|
+
".ant-message-notice",
|
|
6321
|
+
'[role="alert"]',
|
|
6322
|
+
".qwenchat-auth-error",
|
|
6323
|
+
".auth-error-message"
|
|
6324
|
+
].join(", ");
|
|
6325
|
+
const errorEl = page.locator(errorSelector).first();
|
|
6326
|
+
if (await errorEl.isVisible().catch(() => false)) {
|
|
6327
|
+
const errorText = (await errorEl.innerText().catch(() => "")).trim();
|
|
6328
|
+
if (errorText) {
|
|
6329
|
+
const classified = classifyQwenAuthError(void 0, errorText);
|
|
6330
|
+
return {
|
|
6331
|
+
success: false,
|
|
6332
|
+
permanentFailure: classified.isPermanent,
|
|
6333
|
+
reason: `Formul\xE1rio: ${classified.reason}`
|
|
6334
|
+
};
|
|
6335
|
+
}
|
|
6336
|
+
}
|
|
6337
|
+
const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
|
|
6338
|
+
const codeInput = page.locator(codeSelector).first();
|
|
6339
|
+
if (await codeInput.isVisible().catch(() => false)) {
|
|
6215
6340
|
return {
|
|
6216
6341
|
success: false,
|
|
6217
|
-
|
|
6218
|
-
reason: `Formul\xE1rio: ${classified.reason}`
|
|
6342
|
+
reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
|
|
6219
6343
|
};
|
|
6220
6344
|
}
|
|
6345
|
+
try {
|
|
6346
|
+
const liveCookies = await page.context().cookies();
|
|
6347
|
+
if (liveCookies.some((c) => c.name === "token")) {
|
|
6348
|
+
return { success: true };
|
|
6349
|
+
}
|
|
6350
|
+
} catch {
|
|
6351
|
+
}
|
|
6352
|
+
const currentUrl = page.url();
|
|
6353
|
+
if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
|
|
6354
|
+
if (await isPageLoggedIn(page, 3e3)) {
|
|
6355
|
+
return { success: true };
|
|
6356
|
+
}
|
|
6357
|
+
}
|
|
6358
|
+
await sleep2(1e3);
|
|
6221
6359
|
}
|
|
6222
|
-
|
|
6223
|
-
if (isLoggedIn) {
|
|
6224
|
-
await page.goto(qwenUrl("/"), {
|
|
6225
|
-
waitUntil: "domcontentloaded",
|
|
6226
|
-
timeout: config.timeouts.navigation
|
|
6227
|
-
});
|
|
6360
|
+
if (await isPageLoggedIn(page, 3e3)) {
|
|
6228
6361
|
return { success: true };
|
|
6229
6362
|
}
|
|
6230
6363
|
return {
|
|
@@ -6752,6 +6885,17 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
6752
6885
|
}
|
|
6753
6886
|
};
|
|
6754
6887
|
if (forceReauth) {
|
|
6888
|
+
const alreadyIn = await isPageLoggedIn(page, 2e3).catch(() => false);
|
|
6889
|
+
if (alreadyIn) {
|
|
6890
|
+
const liveCookies = await page.context().cookies();
|
|
6891
|
+
if (liveCookies.some((c) => c.name === "token")) {
|
|
6892
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
6893
|
+
cache3.headers.cookie = cookieStr;
|
|
6894
|
+
cache3.lastRefresh = Date.now();
|
|
6895
|
+
markAccountHeadersReady(accountId);
|
|
6896
|
+
return;
|
|
6897
|
+
}
|
|
6898
|
+
}
|
|
6755
6899
|
await executeReauth();
|
|
6756
6900
|
} else {
|
|
6757
6901
|
try {
|
|
@@ -7186,19 +7330,50 @@ async function keepAlivePlaywrightAccount(accountId) {
|
|
|
7186
7330
|
const now = Date.now();
|
|
7187
7331
|
const currentUrl = page.url();
|
|
7188
7332
|
const cookie = await getCookies(accountId);
|
|
7189
|
-
if (cookie && isTokenExpiringSoon(cookie,
|
|
7190
|
-
console.log(
|
|
7191
|
-
`\u{1F493} [SessionKeeper] Account ${accountId} token expires within 45m; proactively renewing session...`
|
|
7192
|
-
);
|
|
7333
|
+
if (cookie && isTokenExpiringSoon(cookie, 2)) {
|
|
7193
7334
|
try {
|
|
7194
|
-
await
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7335
|
+
await page.evaluate(async () => {
|
|
7336
|
+
await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
7337
|
+
method: "GET",
|
|
7338
|
+
credentials: "include"
|
|
7339
|
+
}).catch(() => {
|
|
7340
|
+
});
|
|
7341
|
+
await fetch("/api/v1/auths/", {
|
|
7342
|
+
method: "GET",
|
|
7343
|
+
credentials: "include"
|
|
7344
|
+
}).catch(() => {
|
|
7345
|
+
});
|
|
7346
|
+
}).catch(() => {
|
|
7347
|
+
});
|
|
7348
|
+
const liveCookies = await page.context().cookies();
|
|
7349
|
+
const tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
7350
|
+
if (tokenCookie) {
|
|
7351
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
7352
|
+
const cache3 = getHeaderCache(accountId);
|
|
7353
|
+
cache3.headers.cookie = cookieStr;
|
|
7354
|
+
cache3.lastRefresh = Date.now();
|
|
7355
|
+
markAccountHeadersReady(accountId);
|
|
7356
|
+
lastKeepAliveNavigation.set(accountId, now);
|
|
7357
|
+
touchAccountActivity(accountId);
|
|
7358
|
+
return true;
|
|
7359
|
+
}
|
|
7360
|
+
} catch {
|
|
7361
|
+
}
|
|
7362
|
+
const loggedIn = await isPageLoggedIn(page, 2e3).catch(() => false);
|
|
7363
|
+
if (!loggedIn) {
|
|
7364
|
+
console.log(
|
|
7365
|
+
`\u{1F493} [SessionKeeper] Account ${accountId} session expired; renewing session...`
|
|
7201
7366
|
);
|
|
7367
|
+
try {
|
|
7368
|
+
await refreshHeadersInternal(accountId, config.timeouts.headers, true);
|
|
7369
|
+
lastKeepAliveNavigation.set(accountId, now);
|
|
7370
|
+
touchAccountActivity(accountId);
|
|
7371
|
+
return true;
|
|
7372
|
+
} catch (err) {
|
|
7373
|
+
console.warn(
|
|
7374
|
+
`[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
|
|
7375
|
+
);
|
|
7376
|
+
}
|
|
7202
7377
|
}
|
|
7203
7378
|
}
|
|
7204
7379
|
const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;
|
|
@@ -25498,7 +25673,7 @@ function getAppVersion() {
|
|
|
25498
25673
|
}
|
|
25499
25674
|
} catch {
|
|
25500
25675
|
}
|
|
25501
|
-
cachedVersion = "v1.4.
|
|
25676
|
+
cachedVersion = "v1.4.7";
|
|
25502
25677
|
return cachedVersion;
|
|
25503
25678
|
}
|
|
25504
25679
|
var cachedVersion;
|