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/delete-chats.js
CHANGED
|
@@ -3779,8 +3779,29 @@ function getStealthScript(profile) {
|
|
|
3779
3779
|
const _toBlob = HTMLCanvasElement.prototype.toBlob;
|
|
3780
3780
|
const _getImageData = CanvasRenderingContext2D.prototype.getImageData;
|
|
3781
3781
|
|
|
3782
|
+
function isCaptchaCanvas(canvas) {
|
|
3783
|
+
try {
|
|
3784
|
+
if (!canvas) return false;
|
|
3785
|
+
const id = (canvas.id || "").toLowerCase();
|
|
3786
|
+
const cls = (canvas.className || "").toLowerCase();
|
|
3787
|
+
return (
|
|
3788
|
+
id.includes("baxia") ||
|
|
3789
|
+
id.includes("nc_") ||
|
|
3790
|
+
id.includes("captcha") ||
|
|
3791
|
+
id.includes("punish") ||
|
|
3792
|
+
cls.includes("baxia") ||
|
|
3793
|
+
cls.includes("nc_") ||
|
|
3794
|
+
cls.includes("captcha") ||
|
|
3795
|
+
Boolean(canvas.closest?.("#baxia-dialog, #baxia-punish, [class*='baxia'], [class*='nc_'], .auth-layout"))
|
|
3796
|
+
);
|
|
3797
|
+
} catch(e) {
|
|
3798
|
+
return false;
|
|
3799
|
+
}
|
|
3800
|
+
}
|
|
3801
|
+
|
|
3782
3802
|
function addNoise(canvas) {
|
|
3783
3803
|
try {
|
|
3804
|
+
if (isCaptchaCanvas(canvas)) return;
|
|
3784
3805
|
const ctx = canvas.getContext('2d');
|
|
3785
3806
|
if (!ctx) return;
|
|
3786
3807
|
const style = ctx.fillStyle;
|
|
@@ -3804,6 +3825,9 @@ function getStealthScript(profile) {
|
|
|
3804
3825
|
|
|
3805
3826
|
CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
|
|
3806
3827
|
const imageData = _getImageData.apply(this, arguments);
|
|
3828
|
+
if (isCaptchaCanvas(this.canvas)) {
|
|
3829
|
+
return imageData;
|
|
3830
|
+
}
|
|
3807
3831
|
const data = imageData.data;
|
|
3808
3832
|
const maxPixels = Math.min(data.length / 4, 2500);
|
|
3809
3833
|
for (let i = 0; i < maxPixels * 4; i += 4) {
|
|
@@ -4727,8 +4751,9 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4727
4751
|
}
|
|
4728
4752
|
if (attempt < maxAttempts) {
|
|
4729
4753
|
const backoffMs = attempt * 5e3;
|
|
4754
|
+
const failReason = uiResult.reason || apiResult.reason || "falha tempor\xE1ria";
|
|
4730
4755
|
console.warn(
|
|
4731
|
-
`\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${
|
|
4756
|
+
`\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${failReason}), retrying in ${backoffMs / 1e3}s`
|
|
4732
4757
|
);
|
|
4733
4758
|
await sleep2(backoffMs);
|
|
4734
4759
|
}
|
|
@@ -4758,37 +4783,52 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4758
4783
|
async function loginViaApi(page, email, password) {
|
|
4759
4784
|
try {
|
|
4760
4785
|
const hashedPassword = crypto3.createHash("sha256").update(password).digest("hex");
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
email,
|
|
4769
|
-
password: hashedPassword,
|
|
4770
|
-
login_type: "email"
|
|
4771
|
-
},
|
|
4772
|
-
headers: {
|
|
4773
|
-
"content-type": "application/json",
|
|
4774
|
-
accept: "application/json, text/plain, */*",
|
|
4775
|
-
referer: qwenUrl("/auth"),
|
|
4776
|
-
origin: qwenOrigin(),
|
|
4777
|
-
source: "web"
|
|
4778
|
-
},
|
|
4779
|
-
timeout: 1e4
|
|
4780
|
-
});
|
|
4781
|
-
data = await response.json().catch(() => null);
|
|
4782
|
-
signinSuccess = Boolean(data && (data.success === true || data.token));
|
|
4783
|
-
} catch {
|
|
4784
|
-
}
|
|
4786
|
+
if (!page.url().includes("/auth")) {
|
|
4787
|
+
await page.goto(qwenUrl("/auth"), {
|
|
4788
|
+
waitUntil: "domcontentloaded",
|
|
4789
|
+
timeout: config.timeouts.navigation
|
|
4790
|
+
}).catch(() => {
|
|
4791
|
+
});
|
|
4792
|
+
await sleep2(1e3);
|
|
4785
4793
|
}
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4794
|
+
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
4795
|
+
const requestId = crypto3.randomUUID();
|
|
4796
|
+
const evalRes = await page.evaluate(
|
|
4797
|
+
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
|
|
4798
|
+
try {
|
|
4799
|
+
const response = await fetch(signinUrl2, {
|
|
4800
|
+
method: "POST",
|
|
4801
|
+
signal: AbortSignal.timeout(15e3),
|
|
4802
|
+
credentials: "include",
|
|
4803
|
+
headers: {
|
|
4804
|
+
accept: "application/json, text/plain, */*",
|
|
4805
|
+
"content-type": "application/json",
|
|
4806
|
+
source: "web",
|
|
4807
|
+
version: "0.3.11",
|
|
4808
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
4809
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
4810
|
+
"x-request-id": requestId2
|
|
4811
|
+
},
|
|
4812
|
+
body: JSON.stringify({ email: email2, password: password2 })
|
|
4813
|
+
});
|
|
4814
|
+
const json = await response.json().catch(() => null);
|
|
4815
|
+
return { ok: response.ok, status: response.status, data: json };
|
|
4816
|
+
} catch (e) {
|
|
4817
|
+
return { ok: false, error: e.message };
|
|
4818
|
+
}
|
|
4819
|
+
},
|
|
4820
|
+
{ email, password: hashedPassword, signinUrl, requestId }
|
|
4821
|
+
).catch(() => null);
|
|
4822
|
+
let data = evalRes?.data;
|
|
4823
|
+
let signinSuccess = Boolean(
|
|
4824
|
+
data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
|
|
4825
|
+
);
|
|
4826
|
+
if (!signinSuccess && !data?.data?.code) {
|
|
4827
|
+
const fallbackUrl = qwenUrl("/api/v2/auths/signin");
|
|
4828
|
+
const fallbackRes = await page.evaluate(
|
|
4829
|
+
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
|
|
4790
4830
|
try {
|
|
4791
|
-
const response = await fetch(
|
|
4831
|
+
const response = await fetch(fallbackUrl2, {
|
|
4792
4832
|
method: "POST",
|
|
4793
4833
|
signal: AbortSignal.timeout(1e4),
|
|
4794
4834
|
credentials: "include",
|
|
@@ -4796,10 +4836,11 @@ async function loginViaApi(page, email, password) {
|
|
|
4796
4836
|
accept: "application/json, text/plain, */*",
|
|
4797
4837
|
"content-type": "application/json",
|
|
4798
4838
|
source: "web",
|
|
4839
|
+
version: "0.3.11",
|
|
4799
4840
|
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
4800
4841
|
"x-request-id": requestId2
|
|
4801
4842
|
},
|
|
4802
|
-
body: JSON.stringify({ email: email2, password: password2
|
|
4843
|
+
body: JSON.stringify({ email: email2, password: password2 })
|
|
4803
4844
|
});
|
|
4804
4845
|
const json = await response.json().catch(() => null);
|
|
4805
4846
|
return { ok: response.ok, status: response.status, data: json };
|
|
@@ -4807,11 +4848,13 @@ async function loginViaApi(page, email, password) {
|
|
|
4807
4848
|
return { ok: false, error: e.message };
|
|
4808
4849
|
}
|
|
4809
4850
|
},
|
|
4810
|
-
{ email, password: hashedPassword,
|
|
4851
|
+
{ email, password: hashedPassword, fallbackUrl, requestId }
|
|
4811
4852
|
).catch(() => null);
|
|
4812
|
-
if (
|
|
4813
|
-
data =
|
|
4814
|
-
signinSuccess = Boolean(
|
|
4853
|
+
if (fallbackRes?.data) {
|
|
4854
|
+
data = fallbackRes.data;
|
|
4855
|
+
signinSuccess = Boolean(
|
|
4856
|
+
data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
|
|
4857
|
+
);
|
|
4815
4858
|
}
|
|
4816
4859
|
}
|
|
4817
4860
|
if (data?.success === false) {
|
|
@@ -4825,7 +4868,8 @@ async function loginViaApi(page, email, password) {
|
|
|
4825
4868
|
};
|
|
4826
4869
|
}
|
|
4827
4870
|
if (signinSuccess) {
|
|
4828
|
-
const token = data?.data?.token || data?.token;
|
|
4871
|
+
const token = data?.data?.access_token || data?.data?.token || data?.access_token || data?.token;
|
|
4872
|
+
const refreshToken = data?.data?.refresh_token || data?.refresh_token;
|
|
4829
4873
|
if (token) {
|
|
4830
4874
|
try {
|
|
4831
4875
|
await page.context().addCookies([
|
|
@@ -4849,14 +4893,19 @@ async function loginViaApi(page, email, password) {
|
|
|
4849
4893
|
}).catch(() => {
|
|
4850
4894
|
});
|
|
4851
4895
|
if (token) {
|
|
4852
|
-
await page.evaluate(
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4896
|
+
await page.evaluate(
|
|
4897
|
+
({ tok, rTok }) => {
|
|
4898
|
+
try {
|
|
4899
|
+
localStorage.removeItem("qwen_token_logged_out_marker");
|
|
4900
|
+
localStorage.setItem("token", tok);
|
|
4901
|
+
localStorage.setItem("access_token", tok);
|
|
4902
|
+
if (rTok) localStorage.setItem("refresh_token", rTok);
|
|
4903
|
+
document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
4904
|
+
} catch {
|
|
4905
|
+
}
|
|
4906
|
+
},
|
|
4907
|
+
{ tok: token, rTok: refreshToken }
|
|
4908
|
+
).catch(() => {
|
|
4860
4909
|
});
|
|
4861
4910
|
await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
|
|
4862
4911
|
});
|
|
@@ -4884,11 +4933,23 @@ async function loginViaApi(page, email, password) {
|
|
|
4884
4933
|
}
|
|
4885
4934
|
async function loginViaUi(page, email, password) {
|
|
4886
4935
|
try {
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4936
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3).catch(() => false)) {
|
|
4937
|
+
return { success: true };
|
|
4938
|
+
}
|
|
4939
|
+
try {
|
|
4940
|
+
await page.goto(qwenUrl("/auth"), {
|
|
4941
|
+
waitUntil: "domcontentloaded",
|
|
4942
|
+
timeout: Math.min(config.timeouts.navigation, 15e3)
|
|
4943
|
+
});
|
|
4944
|
+
await sleep2(1e3);
|
|
4945
|
+
} catch (gotoErr) {
|
|
4946
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
4947
|
+
return { success: true };
|
|
4948
|
+
}
|
|
4949
|
+
}
|
|
4950
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
4951
|
+
return { success: true };
|
|
4952
|
+
}
|
|
4892
4953
|
const emailSelector = [
|
|
4893
4954
|
'input[type="email"]',
|
|
4894
4955
|
'input[name="email"]',
|
|
@@ -4898,7 +4959,7 @@ async function loginViaUi(page, email, password) {
|
|
|
4898
4959
|
].join(", ");
|
|
4899
4960
|
try {
|
|
4900
4961
|
await page.waitForSelector(emailSelector, {
|
|
4901
|
-
timeout: Math.min(config.timeouts.page,
|
|
4962
|
+
timeout: Math.min(config.timeouts.page, 5e3)
|
|
4902
4963
|
});
|
|
4903
4964
|
} catch {
|
|
4904
4965
|
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
@@ -4911,30 +4972,55 @@ async function loginViaUi(page, email, password) {
|
|
|
4911
4972
|
return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
|
|
4912
4973
|
}
|
|
4913
4974
|
await clearVisibleChallenge(page);
|
|
4914
|
-
const
|
|
4915
|
-
return page.locator('
|
|
4916
|
-
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
|
|
4917
|
-
}).first();
|
|
4975
|
+
const isPasswordInputPresent = async () => {
|
|
4976
|
+
return await page.locator('input[type="password"], input[name="password"]').count().catch(() => 0) > 0;
|
|
4918
4977
|
};
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
|
|
4978
|
+
const revealPasswordMode = async () => {
|
|
4979
|
+
if (page.url().includes("/forget")) {
|
|
4980
|
+
await page.goto(qwenUrl("/auth"), { waitUntil: "domcontentloaded", timeout: 1e4 }).catch(() => {
|
|
4923
4981
|
});
|
|
4924
|
-
await sleep2(
|
|
4982
|
+
await sleep2(1e3);
|
|
4925
4983
|
}
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
if (await
|
|
4933
|
-
await
|
|
4984
|
+
if (await isPasswordInputPresent()) return;
|
|
4985
|
+
const btn = page.locator("button").filter({
|
|
4986
|
+
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
|
|
4987
|
+
}).filter({
|
|
4988
|
+
hasNotText: /(?:esqueci|forgot|olvid|reset|recover)/i
|
|
4989
|
+
}).first();
|
|
4990
|
+
if (await btn.isVisible({ timeout: 1500 }).catch(() => false)) {
|
|
4991
|
+
await btn.click({ timeout: 2e3 }).catch(() => {
|
|
4934
4992
|
});
|
|
4935
4993
|
await sleep2(500);
|
|
4936
4994
|
}
|
|
4995
|
+
if (await isPasswordInputPresent()) return;
|
|
4996
|
+
await page.evaluate(() => {
|
|
4997
|
+
try {
|
|
4998
|
+
const buttons = Array.from(document.querySelectorAll("button, [role='button'], a"));
|
|
4999
|
+
for (const b of buttons) {
|
|
5000
|
+
const txt = (b.innerText || "").trim().toLowerCase();
|
|
5001
|
+
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")) {
|
|
5002
|
+
b.click();
|
|
5003
|
+
return true;
|
|
5004
|
+
}
|
|
5005
|
+
}
|
|
5006
|
+
} catch {
|
|
5007
|
+
}
|
|
5008
|
+
return false;
|
|
5009
|
+
}).catch(() => false);
|
|
5010
|
+
await sleep2(500);
|
|
5011
|
+
};
|
|
5012
|
+
await revealPasswordMode();
|
|
5013
|
+
try {
|
|
5014
|
+
await page.fill(emailSelector, email, { timeout: 8e3 });
|
|
5015
|
+
await sleep2(300);
|
|
4937
5016
|
} catch {
|
|
5017
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
5018
|
+
return { success: true };
|
|
5019
|
+
}
|
|
5020
|
+
throw new Error(`Campo de e-mail n\xE3o encontrado na tela de autentica\xE7\xE3o`);
|
|
5021
|
+
}
|
|
5022
|
+
if (!await isPasswordInputPresent()) {
|
|
5023
|
+
await revealPasswordMode();
|
|
4938
5024
|
}
|
|
4939
5025
|
const passwordSelector = 'input[type="password"], input[name="password"]';
|
|
4940
5026
|
try {
|
|
@@ -4953,61 +5039,108 @@ async function loginViaUi(page, email, password) {
|
|
|
4953
5039
|
reason: "Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o"
|
|
4954
5040
|
};
|
|
4955
5041
|
}
|
|
4956
|
-
|
|
4957
|
-
|
|
5042
|
+
try {
|
|
5043
|
+
await page.fill(passwordSelector, password, { timeout: 8e3 });
|
|
5044
|
+
await sleep2(500);
|
|
5045
|
+
} catch {
|
|
5046
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
5047
|
+
return { success: true };
|
|
5048
|
+
}
|
|
5049
|
+
throw new Error(`Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o`);
|
|
5050
|
+
}
|
|
5051
|
+
await page.evaluate(() => {
|
|
5052
|
+
try {
|
|
5053
|
+
const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
|
|
5054
|
+
const passEl = document.querySelector('input[type="password"], input[name="password"]');
|
|
5055
|
+
if (emailEl) {
|
|
5056
|
+
emailEl.dispatchEvent(new Event("input", { bubbles: true }));
|
|
5057
|
+
emailEl.dispatchEvent(new Event("change", { bubbles: true }));
|
|
5058
|
+
emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
5059
|
+
}
|
|
5060
|
+
if (passEl) {
|
|
5061
|
+
passEl.dispatchEvent(new Event("input", { bubbles: true }));
|
|
5062
|
+
passEl.dispatchEvent(new Event("change", { bubbles: true }));
|
|
5063
|
+
passEl.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
5064
|
+
}
|
|
5065
|
+
} catch {
|
|
5066
|
+
}
|
|
5067
|
+
}).catch(() => {
|
|
5068
|
+
});
|
|
4958
5069
|
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")';
|
|
4959
5070
|
const submitButton = page.locator(submitSelector).first();
|
|
4960
5071
|
try {
|
|
4961
5072
|
await page.waitForSelector('button[type="submit"]:not([disabled])', {
|
|
4962
|
-
timeout:
|
|
5073
|
+
timeout: 4e3
|
|
4963
5074
|
});
|
|
4964
5075
|
await submitButton.click();
|
|
4965
5076
|
} catch {
|
|
4966
|
-
await
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
|
|
4976
|
-
const codeInput = page.locator(codeSelector).first();
|
|
4977
|
-
if (await codeInput.isVisible().catch(() => false)) {
|
|
4978
|
-
return {
|
|
4979
|
-
success: false,
|
|
4980
|
-
reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
|
|
4981
|
-
};
|
|
5077
|
+
const isDisabled = await submitButton.isDisabled().catch(() => true);
|
|
5078
|
+
if (!isDisabled) {
|
|
5079
|
+
await submitButton.click({ force: true }).catch(() => {
|
|
5080
|
+
});
|
|
5081
|
+
} else {
|
|
5082
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
|
|
5083
|
+
return { success: true };
|
|
5084
|
+
}
|
|
5085
|
+
}
|
|
4982
5086
|
}
|
|
4983
|
-
const
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
5087
|
+
const postSubmitDeadline = Date.now() + 15e3;
|
|
5088
|
+
while (Date.now() < postSubmitDeadline) {
|
|
5089
|
+
if (page.isClosed()) break;
|
|
5090
|
+
if (config.captcha.enabled) {
|
|
5091
|
+
await solveBaxiaCaptcha(page, {
|
|
5092
|
+
waitForMs: 1500,
|
|
5093
|
+
maxAttempts: config.captcha.maxAttempts,
|
|
5094
|
+
retryDelayMs: config.captcha.retryDelayMs
|
|
5095
|
+
}).catch(() => {
|
|
5096
|
+
});
|
|
5097
|
+
}
|
|
5098
|
+
const errorSelector = [
|
|
5099
|
+
".qwen-chat-v2-toast-text",
|
|
5100
|
+
".qwen-chat-v2-toast-content",
|
|
5101
|
+
".ant-form-item-explain-error",
|
|
5102
|
+
".ant-message-error",
|
|
5103
|
+
".ant-message-notice",
|
|
5104
|
+
'[role="alert"]',
|
|
5105
|
+
".qwenchat-auth-error",
|
|
5106
|
+
".auth-error-message"
|
|
5107
|
+
].join(", ");
|
|
5108
|
+
const errorEl = page.locator(errorSelector).first();
|
|
5109
|
+
if (await errorEl.isVisible().catch(() => false)) {
|
|
5110
|
+
const errorText = (await errorEl.innerText().catch(() => "")).trim();
|
|
5111
|
+
if (errorText) {
|
|
5112
|
+
const classified = classifyQwenAuthError(void 0, errorText);
|
|
5113
|
+
return {
|
|
5114
|
+
success: false,
|
|
5115
|
+
permanentFailure: classified.isPermanent,
|
|
5116
|
+
reason: `Formul\xE1rio: ${classified.reason}`
|
|
5117
|
+
};
|
|
5118
|
+
}
|
|
5119
|
+
}
|
|
5120
|
+
const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
|
|
5121
|
+
const codeInput = page.locator(codeSelector).first();
|
|
5122
|
+
if (await codeInput.isVisible().catch(() => false)) {
|
|
4998
5123
|
return {
|
|
4999
5124
|
success: false,
|
|
5000
|
-
|
|
5001
|
-
reason: `Formul\xE1rio: ${classified.reason}`
|
|
5125
|
+
reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
|
|
5002
5126
|
};
|
|
5003
5127
|
}
|
|
5128
|
+
try {
|
|
5129
|
+
const liveCookies = await page.context().cookies();
|
|
5130
|
+
if (liveCookies.some((c) => c.name === "token")) {
|
|
5131
|
+
return { success: true };
|
|
5132
|
+
}
|
|
5133
|
+
} catch {
|
|
5134
|
+
}
|
|
5135
|
+
const currentUrl = page.url();
|
|
5136
|
+
if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
|
|
5137
|
+
if (await isPageLoggedIn(page, 3e3)) {
|
|
5138
|
+
return { success: true };
|
|
5139
|
+
}
|
|
5140
|
+
}
|
|
5141
|
+
await sleep2(1e3);
|
|
5004
5142
|
}
|
|
5005
|
-
|
|
5006
|
-
if (isLoggedIn) {
|
|
5007
|
-
await page.goto(qwenUrl("/"), {
|
|
5008
|
-
waitUntil: "domcontentloaded",
|
|
5009
|
-
timeout: config.timeouts.navigation
|
|
5010
|
-
});
|
|
5143
|
+
if (await isPageLoggedIn(page, 3e3)) {
|
|
5011
5144
|
return { success: true };
|
|
5012
5145
|
}
|
|
5013
5146
|
return {
|
|
@@ -5535,6 +5668,17 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
5535
5668
|
}
|
|
5536
5669
|
};
|
|
5537
5670
|
if (forceReauth) {
|
|
5671
|
+
const alreadyIn = await isPageLoggedIn(page, 2e3).catch(() => false);
|
|
5672
|
+
if (alreadyIn) {
|
|
5673
|
+
const liveCookies = await page.context().cookies();
|
|
5674
|
+
if (liveCookies.some((c) => c.name === "token")) {
|
|
5675
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
5676
|
+
cache.headers.cookie = cookieStr;
|
|
5677
|
+
cache.lastRefresh = Date.now();
|
|
5678
|
+
markAccountHeadersReady(accountId);
|
|
5679
|
+
return;
|
|
5680
|
+
}
|
|
5681
|
+
}
|
|
5538
5682
|
await executeReauth();
|
|
5539
5683
|
} else {
|
|
5540
5684
|
try {
|
|
@@ -5969,19 +6113,50 @@ async function keepAlivePlaywrightAccount(accountId) {
|
|
|
5969
6113
|
const now = Date.now();
|
|
5970
6114
|
const currentUrl = page.url();
|
|
5971
6115
|
const cookie = await getCookies(accountId);
|
|
5972
|
-
if (cookie && isTokenExpiringSoon(cookie,
|
|
5973
|
-
console.log(
|
|
5974
|
-
`\u{1F493} [SessionKeeper] Account ${accountId} token expires within 45m; proactively renewing session...`
|
|
5975
|
-
);
|
|
6116
|
+
if (cookie && isTokenExpiringSoon(cookie, 2)) {
|
|
5976
6117
|
try {
|
|
5977
|
-
await
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
6118
|
+
await page.evaluate(async () => {
|
|
6119
|
+
await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
6120
|
+
method: "GET",
|
|
6121
|
+
credentials: "include"
|
|
6122
|
+
}).catch(() => {
|
|
6123
|
+
});
|
|
6124
|
+
await fetch("/api/v1/auths/", {
|
|
6125
|
+
method: "GET",
|
|
6126
|
+
credentials: "include"
|
|
6127
|
+
}).catch(() => {
|
|
6128
|
+
});
|
|
6129
|
+
}).catch(() => {
|
|
6130
|
+
});
|
|
6131
|
+
const liveCookies = await page.context().cookies();
|
|
6132
|
+
const tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
6133
|
+
if (tokenCookie) {
|
|
6134
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
6135
|
+
const cache = getHeaderCache(accountId);
|
|
6136
|
+
cache.headers.cookie = cookieStr;
|
|
6137
|
+
cache.lastRefresh = Date.now();
|
|
6138
|
+
markAccountHeadersReady(accountId);
|
|
6139
|
+
lastKeepAliveNavigation.set(accountId, now);
|
|
6140
|
+
touchAccountActivity(accountId);
|
|
6141
|
+
return true;
|
|
6142
|
+
}
|
|
6143
|
+
} catch {
|
|
6144
|
+
}
|
|
6145
|
+
const loggedIn = await isPageLoggedIn(page, 2e3).catch(() => false);
|
|
6146
|
+
if (!loggedIn) {
|
|
6147
|
+
console.log(
|
|
6148
|
+
`\u{1F493} [SessionKeeper] Account ${accountId} session expired; renewing session...`
|
|
5984
6149
|
);
|
|
6150
|
+
try {
|
|
6151
|
+
await refreshHeadersInternal(accountId, config.timeouts.headers, true);
|
|
6152
|
+
lastKeepAliveNavigation.set(accountId, now);
|
|
6153
|
+
touchAccountActivity(accountId);
|
|
6154
|
+
return true;
|
|
6155
|
+
} catch (err) {
|
|
6156
|
+
console.warn(
|
|
6157
|
+
`[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
|
|
6158
|
+
);
|
|
6159
|
+
}
|
|
5985
6160
|
}
|
|
5986
6161
|
}
|
|
5987
6162
|
const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;
|