qwenproxy-cli 1.4.3 → 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/login.js CHANGED
@@ -3864,8 +3864,29 @@ function getStealthScript(profile) {
3864
3864
  const _toBlob = HTMLCanvasElement.prototype.toBlob;
3865
3865
  const _getImageData = CanvasRenderingContext2D.prototype.getImageData;
3866
3866
 
3867
+ function isCaptchaCanvas(canvas) {
3868
+ try {
3869
+ if (!canvas) return false;
3870
+ const id = (canvas.id || "").toLowerCase();
3871
+ const cls = (canvas.className || "").toLowerCase();
3872
+ return (
3873
+ id.includes("baxia") ||
3874
+ id.includes("nc_") ||
3875
+ id.includes("captcha") ||
3876
+ id.includes("punish") ||
3877
+ cls.includes("baxia") ||
3878
+ cls.includes("nc_") ||
3879
+ cls.includes("captcha") ||
3880
+ Boolean(canvas.closest?.("#baxia-dialog, #baxia-punish, [class*='baxia'], [class*='nc_'], .auth-layout"))
3881
+ );
3882
+ } catch(e) {
3883
+ return false;
3884
+ }
3885
+ }
3886
+
3867
3887
  function addNoise(canvas) {
3868
3888
  try {
3889
+ if (isCaptchaCanvas(canvas)) return;
3869
3890
  const ctx = canvas.getContext('2d');
3870
3891
  if (!ctx) return;
3871
3892
  const style = ctx.fillStyle;
@@ -3889,6 +3910,9 @@ function getStealthScript(profile) {
3889
3910
 
3890
3911
  CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
3891
3912
  const imageData = _getImageData.apply(this, arguments);
3913
+ if (isCaptchaCanvas(this.canvas)) {
3914
+ return imageData;
3915
+ }
3892
3916
  const data = imageData.data;
3893
3917
  const maxPixels = Math.min(data.length / 4, 2500);
3894
3918
  for (let i = 0; i < maxPixels * 4; i += 4) {
@@ -4844,37 +4868,52 @@ async function loginToQwen(accountId, email, password) {
4844
4868
  async function loginViaApi(page, email, password) {
4845
4869
  try {
4846
4870
  const hashedPassword = crypto3.createHash("sha256").update(password).digest("hex");
4847
- const signinUrl = qwenUrl("/api/v2/auths/signin");
4848
- let signinSuccess = false;
4849
- let data = null;
4850
- if (page.request && typeof page.request.post === "function") {
4851
- try {
4852
- const response = await page.request.post(signinUrl, {
4853
- data: {
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
- }
4871
+ if (!page.url().includes("/auth")) {
4872
+ await page.goto(qwenUrl("/auth"), {
4873
+ waitUntil: "domcontentloaded",
4874
+ timeout: config.timeouts.navigation
4875
+ }).catch(() => {
4876
+ });
4877
+ await sleep2(1e3);
4871
4878
  }
4872
- if (!signinSuccess && !data) {
4873
- const requestId = crypto3.randomUUID();
4874
- const evalRes = await page.evaluate(
4875
- async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
4879
+ const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
4880
+ const requestId = crypto3.randomUUID();
4881
+ const evalRes = await page.evaluate(
4882
+ async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
4883
+ try {
4884
+ const response = await fetch(signinUrl2, {
4885
+ method: "POST",
4886
+ signal: AbortSignal.timeout(15e3),
4887
+ credentials: "include",
4888
+ headers: {
4889
+ accept: "application/json, text/plain, */*",
4890
+ "content-type": "application/json",
4891
+ source: "web",
4892
+ version: "0.3.11",
4893
+ "x-request-origin": "https://chat.qwen.ai",
4894
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
4895
+ "x-request-id": requestId2
4896
+ },
4897
+ body: JSON.stringify({ email: email2, password: password2 })
4898
+ });
4899
+ const json = await response.json().catch(() => null);
4900
+ return { ok: response.ok, status: response.status, data: json };
4901
+ } catch (e) {
4902
+ return { ok: false, error: e.message };
4903
+ }
4904
+ },
4905
+ { email, password: hashedPassword, signinUrl, requestId }
4906
+ ).catch(() => null);
4907
+ let data = evalRes?.data;
4908
+ let signinSuccess = Boolean(
4909
+ data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
4910
+ );
4911
+ if (!signinSuccess && !data?.data?.code) {
4912
+ const fallbackUrl = qwenUrl("/api/v2/auths/signin");
4913
+ const fallbackRes = await page.evaluate(
4914
+ async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
4876
4915
  try {
4877
- const response = await fetch(signinUrl2, {
4916
+ const response = await fetch(fallbackUrl2, {
4878
4917
  method: "POST",
4879
4918
  signal: AbortSignal.timeout(1e4),
4880
4919
  credentials: "include",
@@ -4882,10 +4921,11 @@ async function loginViaApi(page, email, password) {
4882
4921
  accept: "application/json, text/plain, */*",
4883
4922
  "content-type": "application/json",
4884
4923
  source: "web",
4924
+ version: "0.3.11",
4885
4925
  timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
4886
4926
  "x-request-id": requestId2
4887
4927
  },
4888
- body: JSON.stringify({ email: email2, password: password2, login_type: "email" })
4928
+ body: JSON.stringify({ email: email2, password: password2 })
4889
4929
  });
4890
4930
  const json = await response.json().catch(() => null);
4891
4931
  return { ok: response.ok, status: response.status, data: json };
@@ -4893,11 +4933,13 @@ async function loginViaApi(page, email, password) {
4893
4933
  return { ok: false, error: e.message };
4894
4934
  }
4895
4935
  },
4896
- { email, password: hashedPassword, signinUrl, requestId }
4936
+ { email, password: hashedPassword, fallbackUrl, requestId }
4897
4937
  ).catch(() => null);
4898
- if (evalRes?.data) {
4899
- data = evalRes.data;
4900
- signinSuccess = Boolean(data && (data.success === true || data.token));
4938
+ if (fallbackRes?.data) {
4939
+ data = fallbackRes.data;
4940
+ signinSuccess = Boolean(
4941
+ data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
4942
+ );
4901
4943
  }
4902
4944
  }
4903
4945
  if (data?.success === false) {
@@ -4911,7 +4953,8 @@ async function loginViaApi(page, email, password) {
4911
4953
  };
4912
4954
  }
4913
4955
  if (signinSuccess) {
4914
- const token = data?.data?.token || data?.token;
4956
+ const token = data?.data?.access_token || data?.data?.token || data?.access_token || data?.token;
4957
+ const refreshToken = data?.data?.refresh_token || data?.refresh_token;
4915
4958
  if (token) {
4916
4959
  try {
4917
4960
  await page.context().addCookies([
@@ -4935,14 +4978,19 @@ async function loginViaApi(page, email, password) {
4935
4978
  }).catch(() => {
4936
4979
  });
4937
4980
  if (token) {
4938
- await page.evaluate((tok) => {
4939
- try {
4940
- localStorage.removeItem("qwen_token_logged_out_marker");
4941
- localStorage.setItem("token", tok);
4942
- document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
4943
- } catch {
4944
- }
4945
- }, token).catch(() => {
4981
+ await page.evaluate(
4982
+ ({ tok, rTok }) => {
4983
+ try {
4984
+ localStorage.removeItem("qwen_token_logged_out_marker");
4985
+ localStorage.setItem("token", tok);
4986
+ localStorage.setItem("access_token", tok);
4987
+ if (rTok) localStorage.setItem("refresh_token", rTok);
4988
+ document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
4989
+ } catch {
4990
+ }
4991
+ },
4992
+ { tok: token, rTok: refreshToken }
4993
+ ).catch(() => {
4946
4994
  });
4947
4995
  await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
4948
4996
  });
@@ -4970,11 +5018,23 @@ async function loginViaApi(page, email, password) {
4970
5018
  }
4971
5019
  async function loginViaUi(page, email, password) {
4972
5020
  try {
4973
- await page.goto(qwenUrl("/auth"), {
4974
- waitUntil: "domcontentloaded",
4975
- timeout: config.timeouts.navigation
4976
- });
4977
- await sleep2(1500);
5021
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3).catch(() => false)) {
5022
+ return { success: true };
5023
+ }
5024
+ try {
5025
+ await page.goto(qwenUrl("/auth"), {
5026
+ waitUntil: "domcontentloaded",
5027
+ timeout: Math.min(config.timeouts.navigation, 15e3)
5028
+ });
5029
+ await sleep2(1e3);
5030
+ } catch (gotoErr) {
5031
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
5032
+ return { success: true };
5033
+ }
5034
+ }
5035
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
5036
+ return { success: true };
5037
+ }
4978
5038
  const emailSelector = [
4979
5039
  'input[type="email"]',
4980
5040
  'input[name="email"]',
@@ -4984,7 +5044,7 @@ async function loginViaUi(page, email, password) {
4984
5044
  ].join(", ");
4985
5045
  try {
4986
5046
  await page.waitForSelector(emailSelector, {
4987
- timeout: Math.min(config.timeouts.page, 8e3)
5047
+ timeout: Math.min(config.timeouts.page, 5e3)
4988
5048
  });
4989
5049
  } catch {
4990
5050
  if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
@@ -4997,30 +5057,55 @@ async function loginViaUi(page, email, password) {
4997
5057
  return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
4998
5058
  }
4999
5059
  await clearVisibleChallenge(page);
5000
- const findPasswordModeButton = () => {
5001
- return page.locator('button, [role="button"], a, div').filter({
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();
5060
+ const isPasswordInputPresent = async () => {
5061
+ return await page.locator('input[type="password"], input[name="password"]').count().catch(() => 0) > 0;
5004
5062
  };
5005
- try {
5006
- const pwdModeBtn = findPasswordModeButton();
5007
- if (await pwdModeBtn.isVisible({ timeout: 2e3 }).catch(() => false)) {
5008
- await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
5063
+ const revealPasswordMode = async () => {
5064
+ if (page.url().includes("/forget")) {
5065
+ await page.goto(qwenUrl("/auth"), { waitUntil: "domcontentloaded", timeout: 1e4 }).catch(() => {
5009
5066
  });
5010
- await sleep2(500);
5067
+ await sleep2(1e3);
5011
5068
  }
5012
- } catch {
5013
- }
5014
- await page.fill(emailSelector, email);
5015
- await sleep2(300);
5016
- try {
5017
- const pwdModeBtn = findPasswordModeButton();
5018
- if (await pwdModeBtn.isVisible({ timeout: 1500 }).catch(() => false)) {
5019
- await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
5069
+ if (await isPasswordInputPresent()) return;
5070
+ const btn = page.locator("button").filter({
5071
+ 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
5072
+ }).filter({
5073
+ hasNotText: /(?:esqueci|forgot|olvid|reset|recover)/i
5074
+ }).first();
5075
+ if (await btn.isVisible({ timeout: 1500 }).catch(() => false)) {
5076
+ await btn.click({ timeout: 2e3 }).catch(() => {
5020
5077
  });
5021
5078
  await sleep2(500);
5022
5079
  }
5080
+ if (await isPasswordInputPresent()) return;
5081
+ await page.evaluate(() => {
5082
+ try {
5083
+ const buttons = Array.from(document.querySelectorAll("button, [role='button'], a"));
5084
+ for (const b of buttons) {
5085
+ const txt = (b.innerText || "").trim().toLowerCase();
5086
+ 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")) {
5087
+ b.click();
5088
+ return true;
5089
+ }
5090
+ }
5091
+ } catch {
5092
+ }
5093
+ return false;
5094
+ }).catch(() => false);
5095
+ await sleep2(500);
5096
+ };
5097
+ await revealPasswordMode();
5098
+ try {
5099
+ await page.fill(emailSelector, email, { timeout: 8e3 });
5100
+ await sleep2(300);
5023
5101
  } catch {
5102
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
5103
+ return { success: true };
5104
+ }
5105
+ throw new Error(`Campo de e-mail n\xE3o encontrado na tela de autentica\xE7\xE3o`);
5106
+ }
5107
+ if (!await isPasswordInputPresent()) {
5108
+ await revealPasswordMode();
5024
5109
  }
5025
5110
  const passwordSelector = 'input[type="password"], input[name="password"]';
5026
5111
  try {
@@ -5039,17 +5124,50 @@ async function loginViaUi(page, email, password) {
5039
5124
  reason: "Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o"
5040
5125
  };
5041
5126
  }
5042
- await page.fill(passwordSelector, password);
5043
- await sleep2(500);
5127
+ try {
5128
+ await page.fill(passwordSelector, password, { timeout: 8e3 });
5129
+ await sleep2(500);
5130
+ } catch {
5131
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
5132
+ return { success: true };
5133
+ }
5134
+ throw new Error(`Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o`);
5135
+ }
5136
+ await page.evaluate(() => {
5137
+ try {
5138
+ const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
5139
+ const passEl = document.querySelector('input[type="password"], input[name="password"]');
5140
+ if (emailEl) {
5141
+ emailEl.dispatchEvent(new Event("input", { bubbles: true }));
5142
+ emailEl.dispatchEvent(new Event("change", { bubbles: true }));
5143
+ emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
5144
+ }
5145
+ if (passEl) {
5146
+ passEl.dispatchEvent(new Event("input", { bubbles: true }));
5147
+ passEl.dispatchEvent(new Event("change", { bubbles: true }));
5148
+ passEl.dispatchEvent(new Event("blur", { bubbles: true }));
5149
+ }
5150
+ } catch {
5151
+ }
5152
+ }).catch(() => {
5153
+ });
5044
5154
  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
5155
  const submitButton = page.locator(submitSelector).first();
5046
5156
  try {
5047
5157
  await page.waitForSelector('button[type="submit"]:not([disabled])', {
5048
- timeout: 5e3
5158
+ timeout: 4e3
5049
5159
  });
5050
5160
  await submitButton.click();
5051
5161
  } catch {
5052
- await page.keyboard.press("Enter");
5162
+ const isDisabled = await submitButton.isDisabled().catch(() => true);
5163
+ if (!isDisabled) {
5164
+ await submitButton.click({ force: true }).catch(() => {
5165
+ });
5166
+ } else {
5167
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
5168
+ return { success: true };
5169
+ }
5170
+ }
5053
5171
  }
5054
5172
  const postSubmitDeadline = Date.now() + 15e3;
5055
5173
  while (Date.now() < postSubmitDeadline) {
@@ -5635,6 +5753,17 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
5635
5753
  }
5636
5754
  };
5637
5755
  if (forceReauth) {
5756
+ const alreadyIn = await isPageLoggedIn(page, 2e3).catch(() => false);
5757
+ if (alreadyIn) {
5758
+ const liveCookies = await page.context().cookies();
5759
+ if (liveCookies.some((c) => c.name === "token")) {
5760
+ const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
5761
+ cache.headers.cookie = cookieStr;
5762
+ cache.lastRefresh = Date.now();
5763
+ markAccountHeadersReady(accountId);
5764
+ return;
5765
+ }
5766
+ }
5638
5767
  await executeReauth();
5639
5768
  } else {
5640
5769
  try {
@@ -6069,19 +6198,50 @@ async function keepAlivePlaywrightAccount(accountId) {
6069
6198
  const now = Date.now();
6070
6199
  const currentUrl = page.url();
6071
6200
  const cookie = await getCookies(accountId);
6072
- if (cookie && isTokenExpiringSoon(cookie, 45)) {
6073
- console.log(
6074
- `\u{1F493} [SessionKeeper] Account ${accountId} token expires within 45m; proactively renewing session...`
6075
- );
6201
+ if (cookie && isTokenExpiringSoon(cookie, 2)) {
6076
6202
  try {
6077
- await refreshHeadersInternal(accountId, config.timeouts.headers, true);
6078
- lastKeepAliveNavigation.set(accountId, now);
6079
- touchAccountActivity(accountId);
6080
- return true;
6081
- } catch (err) {
6082
- console.warn(
6083
- `[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
6203
+ await page.evaluate(async () => {
6204
+ await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
6205
+ method: "GET",
6206
+ credentials: "include"
6207
+ }).catch(() => {
6208
+ });
6209
+ await fetch("/api/v1/auths/", {
6210
+ method: "GET",
6211
+ credentials: "include"
6212
+ }).catch(() => {
6213
+ });
6214
+ }).catch(() => {
6215
+ });
6216
+ const liveCookies = await page.context().cookies();
6217
+ const tokenCookie = liveCookies.find((c) => c.name === "token");
6218
+ if (tokenCookie) {
6219
+ const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
6220
+ const cache = getHeaderCache(accountId);
6221
+ cache.headers.cookie = cookieStr;
6222
+ cache.lastRefresh = Date.now();
6223
+ markAccountHeadersReady(accountId);
6224
+ lastKeepAliveNavigation.set(accountId, now);
6225
+ touchAccountActivity(accountId);
6226
+ return true;
6227
+ }
6228
+ } catch {
6229
+ }
6230
+ const loggedIn = await isPageLoggedIn(page, 2e3).catch(() => false);
6231
+ if (!loggedIn) {
6232
+ console.log(
6233
+ `\u{1F493} [SessionKeeper] Account ${accountId} session expired; renewing session...`
6084
6234
  );
6235
+ try {
6236
+ await refreshHeadersInternal(accountId, config.timeouts.headers, true);
6237
+ lastKeepAliveNavigation.set(accountId, now);
6238
+ touchAccountActivity(accountId);
6239
+ return true;
6240
+ } catch (err) {
6241
+ console.warn(
6242
+ `[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
6243
+ );
6244
+ }
6085
6245
  }
6086
6246
  }
6087
6247
  const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;