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/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) {
@@ -5976,37 +6000,52 @@ async function loginToQwen(accountId, email, password) {
5976
6000
  async function loginViaApi(page, email, password) {
5977
6001
  try {
5978
6002
  const hashedPassword = crypto5.createHash("sha256").update(password).digest("hex");
5979
- const signinUrl = qwenUrl("/api/v2/auths/signin");
5980
- let signinSuccess = false;
5981
- let data = null;
5982
- if (page.request && typeof page.request.post === "function") {
5983
- try {
5984
- const response = await page.request.post(signinUrl, {
5985
- data: {
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
- }
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);
6003
6010
  }
6004
- if (!signinSuccess && !data) {
6005
- const requestId = crypto5.randomUUID();
6006
- const evalRes = await page.evaluate(
6007
- async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
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 }) => {
6008
6047
  try {
6009
- const response = await fetch(signinUrl2, {
6048
+ const response = await fetch(fallbackUrl2, {
6010
6049
  method: "POST",
6011
6050
  signal: AbortSignal.timeout(1e4),
6012
6051
  credentials: "include",
@@ -6014,10 +6053,11 @@ async function loginViaApi(page, email, password) {
6014
6053
  accept: "application/json, text/plain, */*",
6015
6054
  "content-type": "application/json",
6016
6055
  source: "web",
6056
+ version: "0.3.11",
6017
6057
  timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
6018
6058
  "x-request-id": requestId2
6019
6059
  },
6020
- body: JSON.stringify({ email: email2, password: password2, login_type: "email" })
6060
+ body: JSON.stringify({ email: email2, password: password2 })
6021
6061
  });
6022
6062
  const json = await response.json().catch(() => null);
6023
6063
  return { ok: response.ok, status: response.status, data: json };
@@ -6025,11 +6065,13 @@ async function loginViaApi(page, email, password) {
6025
6065
  return { ok: false, error: e.message };
6026
6066
  }
6027
6067
  },
6028
- { email, password: hashedPassword, signinUrl, requestId }
6068
+ { email, password: hashedPassword, fallbackUrl, requestId }
6029
6069
  ).catch(() => null);
6030
- if (evalRes?.data) {
6031
- data = evalRes.data;
6032
- signinSuccess = Boolean(data && (data.success === true || data.token));
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
+ );
6033
6075
  }
6034
6076
  }
6035
6077
  if (data?.success === false) {
@@ -6043,7 +6085,8 @@ async function loginViaApi(page, email, password) {
6043
6085
  };
6044
6086
  }
6045
6087
  if (signinSuccess) {
6046
- 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;
6047
6090
  if (token) {
6048
6091
  try {
6049
6092
  await page.context().addCookies([
@@ -6067,14 +6110,19 @@ async function loginViaApi(page, email, password) {
6067
6110
  }).catch(() => {
6068
6111
  });
6069
6112
  if (token) {
6070
- await page.evaluate((tok) => {
6071
- try {
6072
- localStorage.removeItem("qwen_token_logged_out_marker");
6073
- localStorage.setItem("token", tok);
6074
- document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
6075
- } catch {
6076
- }
6077
- }, token).catch(() => {
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(() => {
6078
6126
  });
6079
6127
  await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
6080
6128
  });
@@ -6102,11 +6150,23 @@ async function loginViaApi(page, email, password) {
6102
6150
  }
6103
6151
  async function loginViaUi(page, email, password) {
6104
6152
  try {
6105
- await page.goto(qwenUrl("/auth"), {
6106
- waitUntil: "domcontentloaded",
6107
- timeout: config.timeouts.navigation
6108
- });
6109
- await sleep2(1500);
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
+ }
6110
6170
  const emailSelector = [
6111
6171
  'input[type="email"]',
6112
6172
  'input[name="email"]',
@@ -6116,7 +6176,7 @@ async function loginViaUi(page, email, password) {
6116
6176
  ].join(", ");
6117
6177
  try {
6118
6178
  await page.waitForSelector(emailSelector, {
6119
- timeout: Math.min(config.timeouts.page, 8e3)
6179
+ timeout: Math.min(config.timeouts.page, 5e3)
6120
6180
  });
6121
6181
  } catch {
6122
6182
  if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
@@ -6129,30 +6189,55 @@ async function loginViaUi(page, email, password) {
6129
6189
  return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
6130
6190
  }
6131
6191
  await clearVisibleChallenge(page);
6132
- const findPasswordModeButton = () => {
6133
- return page.locator('button, [role="button"], a, div').filter({
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();
6192
+ const isPasswordInputPresent = async () => {
6193
+ return await page.locator('input[type="password"], input[name="password"]').count().catch(() => 0) > 0;
6136
6194
  };
6137
- try {
6138
- const pwdModeBtn = findPasswordModeButton();
6139
- if (await pwdModeBtn.isVisible({ timeout: 2e3 }).catch(() => false)) {
6140
- 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(() => {
6141
6198
  });
6142
- await sleep2(500);
6199
+ await sleep2(1e3);
6143
6200
  }
6144
- } catch {
6145
- }
6146
- await page.fill(emailSelector, email);
6147
- await sleep2(300);
6148
- try {
6149
- const pwdModeBtn = findPasswordModeButton();
6150
- if (await pwdModeBtn.isVisible({ timeout: 1500 }).catch(() => false)) {
6151
- await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
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(() => {
6152
6209
  });
6153
6210
  await sleep2(500);
6154
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);
6155
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();
6156
6241
  }
6157
6242
  const passwordSelector = 'input[type="password"], input[name="password"]';
6158
6243
  try {
@@ -6171,17 +6256,50 @@ async function loginViaUi(page, email, password) {
6171
6256
  reason: "Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o"
6172
6257
  };
6173
6258
  }
6174
- await page.fill(passwordSelector, password);
6175
- await sleep2(500);
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
+ });
6176
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")';
6177
6287
  const submitButton = page.locator(submitSelector).first();
6178
6288
  try {
6179
6289
  await page.waitForSelector('button[type="submit"]:not([disabled])', {
6180
- timeout: 5e3
6290
+ timeout: 4e3
6181
6291
  });
6182
6292
  await submitButton.click();
6183
6293
  } catch {
6184
- await page.keyboard.press("Enter");
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
+ }
6185
6303
  }
6186
6304
  const postSubmitDeadline = Date.now() + 15e3;
6187
6305
  while (Date.now() < postSubmitDeadline) {
@@ -6767,6 +6885,17 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
6767
6885
  }
6768
6886
  };
6769
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
+ }
6770
6899
  await executeReauth();
6771
6900
  } else {
6772
6901
  try {
@@ -7201,19 +7330,50 @@ async function keepAlivePlaywrightAccount(accountId) {
7201
7330
  const now = Date.now();
7202
7331
  const currentUrl = page.url();
7203
7332
  const cookie = await getCookies(accountId);
7204
- if (cookie && isTokenExpiringSoon(cookie, 45)) {
7205
- console.log(
7206
- `\u{1F493} [SessionKeeper] Account ${accountId} token expires within 45m; proactively renewing session...`
7207
- );
7333
+ if (cookie && isTokenExpiringSoon(cookie, 2)) {
7208
7334
  try {
7209
- await refreshHeadersInternal(accountId, config.timeouts.headers, true);
7210
- lastKeepAliveNavigation.set(accountId, now);
7211
- touchAccountActivity(accountId);
7212
- return true;
7213
- } catch (err) {
7214
- console.warn(
7215
- `[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
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...`
7216
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
+ }
7217
7377
  }
7218
7378
  }
7219
7379
  const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;
@@ -25513,7 +25673,7 @@ function getAppVersion() {
25513
25673
  }
25514
25674
  } catch {
25515
25675
  }
25516
- cachedVersion = "v1.4.3";
25676
+ cachedVersion = "v1.4.7";
25517
25677
  return cachedVersion;
25518
25678
  }
25519
25679
  var cachedVersion;