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.
@@ -3287,8 +3287,29 @@ function getStealthScript(profile) {
3287
3287
  const _toBlob = HTMLCanvasElement.prototype.toBlob;
3288
3288
  const _getImageData = CanvasRenderingContext2D.prototype.getImageData;
3289
3289
 
3290
+ function isCaptchaCanvas(canvas) {
3291
+ try {
3292
+ if (!canvas) return false;
3293
+ const id = (canvas.id || "").toLowerCase();
3294
+ const cls = (canvas.className || "").toLowerCase();
3295
+ return (
3296
+ id.includes("baxia") ||
3297
+ id.includes("nc_") ||
3298
+ id.includes("captcha") ||
3299
+ id.includes("punish") ||
3300
+ cls.includes("baxia") ||
3301
+ cls.includes("nc_") ||
3302
+ cls.includes("captcha") ||
3303
+ Boolean(canvas.closest?.("#baxia-dialog, #baxia-punish, [class*='baxia'], [class*='nc_'], .auth-layout"))
3304
+ );
3305
+ } catch(e) {
3306
+ return false;
3307
+ }
3308
+ }
3309
+
3290
3310
  function addNoise(canvas) {
3291
3311
  try {
3312
+ if (isCaptchaCanvas(canvas)) return;
3292
3313
  const ctx = canvas.getContext('2d');
3293
3314
  if (!ctx) return;
3294
3315
  const style = ctx.fillStyle;
@@ -3312,6 +3333,9 @@ function getStealthScript(profile) {
3312
3333
 
3313
3334
  CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
3314
3335
  const imageData = _getImageData.apply(this, arguments);
3336
+ if (isCaptchaCanvas(this.canvas)) {
3337
+ return imageData;
3338
+ }
3315
3339
  const data = imageData.data;
3316
3340
  const maxPixels = Math.min(data.length / 4, 2500);
3317
3341
  for (let i = 0; i < maxPixels * 4; i += 4) {
@@ -3884,37 +3908,52 @@ async function loginToQwen(accountId, email, password) {
3884
3908
  async function loginViaApi(page, email, password) {
3885
3909
  try {
3886
3910
  const hashedPassword = crypto3.createHash("sha256").update(password).digest("hex");
3887
- const signinUrl = qwenUrl("/api/v2/auths/signin");
3888
- let signinSuccess = false;
3889
- let data = null;
3890
- if (page.request && typeof page.request.post === "function") {
3891
- try {
3892
- const response = await page.request.post(signinUrl, {
3893
- data: {
3894
- email,
3895
- password: hashedPassword,
3896
- login_type: "email"
3897
- },
3898
- headers: {
3899
- "content-type": "application/json",
3900
- accept: "application/json, text/plain, */*",
3901
- referer: qwenUrl("/auth"),
3902
- origin: qwenOrigin(),
3903
- source: "web"
3904
- },
3905
- timeout: 1e4
3906
- });
3907
- data = await response.json().catch(() => null);
3908
- signinSuccess = Boolean(data && (data.success === true || data.token));
3909
- } catch {
3910
- }
3911
+ if (!page.url().includes("/auth")) {
3912
+ await page.goto(qwenUrl("/auth"), {
3913
+ waitUntil: "domcontentloaded",
3914
+ timeout: config.timeouts.navigation
3915
+ }).catch(() => {
3916
+ });
3917
+ await sleep2(1e3);
3911
3918
  }
3912
- if (!signinSuccess && !data) {
3913
- const requestId = crypto3.randomUUID();
3914
- const evalRes = await page.evaluate(
3915
- async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
3919
+ const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
3920
+ const requestId = crypto3.randomUUID();
3921
+ const evalRes = await page.evaluate(
3922
+ async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
3923
+ try {
3924
+ const response = await fetch(signinUrl2, {
3925
+ method: "POST",
3926
+ signal: AbortSignal.timeout(15e3),
3927
+ credentials: "include",
3928
+ headers: {
3929
+ accept: "application/json, text/plain, */*",
3930
+ "content-type": "application/json",
3931
+ source: "web",
3932
+ version: "0.3.11",
3933
+ "x-request-origin": "https://chat.qwen.ai",
3934
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
3935
+ "x-request-id": requestId2
3936
+ },
3937
+ body: JSON.stringify({ email: email2, password: password2 })
3938
+ });
3939
+ const json = await response.json().catch(() => null);
3940
+ return { ok: response.ok, status: response.status, data: json };
3941
+ } catch (e) {
3942
+ return { ok: false, error: e.message };
3943
+ }
3944
+ },
3945
+ { email, password: hashedPassword, signinUrl, requestId }
3946
+ ).catch(() => null);
3947
+ let data = evalRes?.data;
3948
+ let signinSuccess = Boolean(
3949
+ data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
3950
+ );
3951
+ if (!signinSuccess && !data?.data?.code) {
3952
+ const fallbackUrl = qwenUrl("/api/v2/auths/signin");
3953
+ const fallbackRes = await page.evaluate(
3954
+ async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
3916
3955
  try {
3917
- const response = await fetch(signinUrl2, {
3956
+ const response = await fetch(fallbackUrl2, {
3918
3957
  method: "POST",
3919
3958
  signal: AbortSignal.timeout(1e4),
3920
3959
  credentials: "include",
@@ -3922,10 +3961,11 @@ async function loginViaApi(page, email, password) {
3922
3961
  accept: "application/json, text/plain, */*",
3923
3962
  "content-type": "application/json",
3924
3963
  source: "web",
3964
+ version: "0.3.11",
3925
3965
  timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
3926
3966
  "x-request-id": requestId2
3927
3967
  },
3928
- body: JSON.stringify({ email: email2, password: password2, login_type: "email" })
3968
+ body: JSON.stringify({ email: email2, password: password2 })
3929
3969
  });
3930
3970
  const json = await response.json().catch(() => null);
3931
3971
  return { ok: response.ok, status: response.status, data: json };
@@ -3933,11 +3973,13 @@ async function loginViaApi(page, email, password) {
3933
3973
  return { ok: false, error: e.message };
3934
3974
  }
3935
3975
  },
3936
- { email, password: hashedPassword, signinUrl, requestId }
3976
+ { email, password: hashedPassword, fallbackUrl, requestId }
3937
3977
  ).catch(() => null);
3938
- if (evalRes?.data) {
3939
- data = evalRes.data;
3940
- signinSuccess = Boolean(data && (data.success === true || data.token));
3978
+ if (fallbackRes?.data) {
3979
+ data = fallbackRes.data;
3980
+ signinSuccess = Boolean(
3981
+ data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
3982
+ );
3941
3983
  }
3942
3984
  }
3943
3985
  if (data?.success === false) {
@@ -3951,7 +3993,8 @@ async function loginViaApi(page, email, password) {
3951
3993
  };
3952
3994
  }
3953
3995
  if (signinSuccess) {
3954
- const token = data?.data?.token || data?.token;
3996
+ const token = data?.data?.access_token || data?.data?.token || data?.access_token || data?.token;
3997
+ const refreshToken = data?.data?.refresh_token || data?.refresh_token;
3955
3998
  if (token) {
3956
3999
  try {
3957
4000
  await page.context().addCookies([
@@ -3975,14 +4018,19 @@ async function loginViaApi(page, email, password) {
3975
4018
  }).catch(() => {
3976
4019
  });
3977
4020
  if (token) {
3978
- await page.evaluate((tok) => {
3979
- try {
3980
- localStorage.removeItem("qwen_token_logged_out_marker");
3981
- localStorage.setItem("token", tok);
3982
- document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
3983
- } catch {
3984
- }
3985
- }, token).catch(() => {
4021
+ await page.evaluate(
4022
+ ({ tok, rTok }) => {
4023
+ try {
4024
+ localStorage.removeItem("qwen_token_logged_out_marker");
4025
+ localStorage.setItem("token", tok);
4026
+ localStorage.setItem("access_token", tok);
4027
+ if (rTok) localStorage.setItem("refresh_token", rTok);
4028
+ document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
4029
+ } catch {
4030
+ }
4031
+ },
4032
+ { tok: token, rTok: refreshToken }
4033
+ ).catch(() => {
3986
4034
  });
3987
4035
  await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
3988
4036
  });
@@ -4010,11 +4058,23 @@ async function loginViaApi(page, email, password) {
4010
4058
  }
4011
4059
  async function loginViaUi(page, email, password) {
4012
4060
  try {
4013
- await page.goto(qwenUrl("/auth"), {
4014
- waitUntil: "domcontentloaded",
4015
- timeout: config.timeouts.navigation
4016
- });
4017
- await sleep2(1500);
4061
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3).catch(() => false)) {
4062
+ return { success: true };
4063
+ }
4064
+ try {
4065
+ await page.goto(qwenUrl("/auth"), {
4066
+ waitUntil: "domcontentloaded",
4067
+ timeout: Math.min(config.timeouts.navigation, 15e3)
4068
+ });
4069
+ await sleep2(1e3);
4070
+ } catch (gotoErr) {
4071
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
4072
+ return { success: true };
4073
+ }
4074
+ }
4075
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
4076
+ return { success: true };
4077
+ }
4018
4078
  const emailSelector = [
4019
4079
  'input[type="email"]',
4020
4080
  'input[name="email"]',
@@ -4024,7 +4084,7 @@ async function loginViaUi(page, email, password) {
4024
4084
  ].join(", ");
4025
4085
  try {
4026
4086
  await page.waitForSelector(emailSelector, {
4027
- timeout: Math.min(config.timeouts.page, 8e3)
4087
+ timeout: Math.min(config.timeouts.page, 5e3)
4028
4088
  });
4029
4089
  } catch {
4030
4090
  if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
@@ -4037,30 +4097,55 @@ async function loginViaUi(page, email, password) {
4037
4097
  return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
4038
4098
  }
4039
4099
  await clearVisibleChallenge(page);
4040
- const findPasswordModeButton = () => {
4041
- return page.locator('button, [role="button"], a, div').filter({
4042
- 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
4043
- }).first();
4100
+ const isPasswordInputPresent = async () => {
4101
+ return await page.locator('input[type="password"], input[name="password"]').count().catch(() => 0) > 0;
4044
4102
  };
4045
- try {
4046
- const pwdModeBtn = findPasswordModeButton();
4047
- if (await pwdModeBtn.isVisible({ timeout: 2e3 }).catch(() => false)) {
4048
- await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
4103
+ const revealPasswordMode = async () => {
4104
+ if (page.url().includes("/forget")) {
4105
+ await page.goto(qwenUrl("/auth"), { waitUntil: "domcontentloaded", timeout: 1e4 }).catch(() => {
4049
4106
  });
4050
- await sleep2(500);
4107
+ await sleep2(1e3);
4051
4108
  }
4052
- } catch {
4053
- }
4054
- await page.fill(emailSelector, email);
4055
- await sleep2(300);
4056
- try {
4057
- const pwdModeBtn = findPasswordModeButton();
4058
- if (await pwdModeBtn.isVisible({ timeout: 1500 }).catch(() => false)) {
4059
- await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
4109
+ if (await isPasswordInputPresent()) return;
4110
+ const btn = page.locator("button").filter({
4111
+ 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
4112
+ }).filter({
4113
+ hasNotText: /(?:esqueci|forgot|olvid|reset|recover)/i
4114
+ }).first();
4115
+ if (await btn.isVisible({ timeout: 1500 }).catch(() => false)) {
4116
+ await btn.click({ timeout: 2e3 }).catch(() => {
4060
4117
  });
4061
4118
  await sleep2(500);
4062
4119
  }
4120
+ if (await isPasswordInputPresent()) return;
4121
+ await page.evaluate(() => {
4122
+ try {
4123
+ const buttons = Array.from(document.querySelectorAll("button, [role='button'], a"));
4124
+ for (const b of buttons) {
4125
+ const txt = (b.innerText || "").trim().toLowerCase();
4126
+ 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")) {
4127
+ b.click();
4128
+ return true;
4129
+ }
4130
+ }
4131
+ } catch {
4132
+ }
4133
+ return false;
4134
+ }).catch(() => false);
4135
+ await sleep2(500);
4136
+ };
4137
+ await revealPasswordMode();
4138
+ try {
4139
+ await page.fill(emailSelector, email, { timeout: 8e3 });
4140
+ await sleep2(300);
4063
4141
  } catch {
4142
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
4143
+ return { success: true };
4144
+ }
4145
+ throw new Error(`Campo de e-mail n\xE3o encontrado na tela de autentica\xE7\xE3o`);
4146
+ }
4147
+ if (!await isPasswordInputPresent()) {
4148
+ await revealPasswordMode();
4064
4149
  }
4065
4150
  const passwordSelector = 'input[type="password"], input[name="password"]';
4066
4151
  try {
@@ -4079,17 +4164,50 @@ async function loginViaUi(page, email, password) {
4079
4164
  reason: "Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o"
4080
4165
  };
4081
4166
  }
4082
- await page.fill(passwordSelector, password);
4083
- await sleep2(500);
4167
+ try {
4168
+ await page.fill(passwordSelector, password, { timeout: 8e3 });
4169
+ await sleep2(500);
4170
+ } catch {
4171
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
4172
+ return { success: true };
4173
+ }
4174
+ throw new Error(`Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o`);
4175
+ }
4176
+ await page.evaluate(() => {
4177
+ try {
4178
+ const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
4179
+ const passEl = document.querySelector('input[type="password"], input[name="password"]');
4180
+ if (emailEl) {
4181
+ emailEl.dispatchEvent(new Event("input", { bubbles: true }));
4182
+ emailEl.dispatchEvent(new Event("change", { bubbles: true }));
4183
+ emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
4184
+ }
4185
+ if (passEl) {
4186
+ passEl.dispatchEvent(new Event("input", { bubbles: true }));
4187
+ passEl.dispatchEvent(new Event("change", { bubbles: true }));
4188
+ passEl.dispatchEvent(new Event("blur", { bubbles: true }));
4189
+ }
4190
+ } catch {
4191
+ }
4192
+ }).catch(() => {
4193
+ });
4084
4194
  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")';
4085
4195
  const submitButton = page.locator(submitSelector).first();
4086
4196
  try {
4087
4197
  await page.waitForSelector('button[type="submit"]:not([disabled])', {
4088
- timeout: 5e3
4198
+ timeout: 4e3
4089
4199
  });
4090
4200
  await submitButton.click();
4091
4201
  } catch {
4092
- await page.keyboard.press("Enter");
4202
+ const isDisabled = await submitButton.isDisabled().catch(() => true);
4203
+ if (!isDisabled) {
4204
+ await submitButton.click({ force: true }).catch(() => {
4205
+ });
4206
+ } else {
4207
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
4208
+ return { success: true };
4209
+ }
4210
+ }
4093
4211
  }
4094
4212
  const postSubmitDeadline = Date.now() + 15e3;
4095
4213
  while (Date.now() < postSubmitDeadline) {