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/reset-cooldowns.js
CHANGED
|
@@ -3523,8 +3523,29 @@ function getStealthScript(profile) {
|
|
|
3523
3523
|
const _toBlob = HTMLCanvasElement.prototype.toBlob;
|
|
3524
3524
|
const _getImageData = CanvasRenderingContext2D.prototype.getImageData;
|
|
3525
3525
|
|
|
3526
|
+
function isCaptchaCanvas(canvas) {
|
|
3527
|
+
try {
|
|
3528
|
+
if (!canvas) return false;
|
|
3529
|
+
const id = (canvas.id || "").toLowerCase();
|
|
3530
|
+
const cls = (canvas.className || "").toLowerCase();
|
|
3531
|
+
return (
|
|
3532
|
+
id.includes("baxia") ||
|
|
3533
|
+
id.includes("nc_") ||
|
|
3534
|
+
id.includes("captcha") ||
|
|
3535
|
+
id.includes("punish") ||
|
|
3536
|
+
cls.includes("baxia") ||
|
|
3537
|
+
cls.includes("nc_") ||
|
|
3538
|
+
cls.includes("captcha") ||
|
|
3539
|
+
Boolean(canvas.closest?.("#baxia-dialog, #baxia-punish, [class*='baxia'], [class*='nc_'], .auth-layout"))
|
|
3540
|
+
);
|
|
3541
|
+
} catch(e) {
|
|
3542
|
+
return false;
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
|
|
3526
3546
|
function addNoise(canvas) {
|
|
3527
3547
|
try {
|
|
3548
|
+
if (isCaptchaCanvas(canvas)) return;
|
|
3528
3549
|
const ctx = canvas.getContext('2d');
|
|
3529
3550
|
if (!ctx) return;
|
|
3530
3551
|
const style = ctx.fillStyle;
|
|
@@ -3548,6 +3569,9 @@ function getStealthScript(profile) {
|
|
|
3548
3569
|
|
|
3549
3570
|
CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
|
|
3550
3571
|
const imageData = _getImageData.apply(this, arguments);
|
|
3572
|
+
if (isCaptchaCanvas(this.canvas)) {
|
|
3573
|
+
return imageData;
|
|
3574
|
+
}
|
|
3551
3575
|
const data = imageData.data;
|
|
3552
3576
|
const maxPixels = Math.min(data.length / 4, 2500);
|
|
3553
3577
|
for (let i = 0; i < maxPixels * 4; i += 4) {
|
|
@@ -4088,8 +4112,9 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4088
4112
|
}
|
|
4089
4113
|
if (attempt < maxAttempts) {
|
|
4090
4114
|
const backoffMs = attempt * 5e3;
|
|
4115
|
+
const failReason = uiResult.reason || apiResult.reason || "falha tempor\xE1ria";
|
|
4091
4116
|
console.warn(
|
|
4092
|
-
`\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${
|
|
4117
|
+
`\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${failReason}), retrying in ${backoffMs / 1e3}s`
|
|
4093
4118
|
);
|
|
4094
4119
|
await sleep2(backoffMs);
|
|
4095
4120
|
}
|
|
@@ -4119,37 +4144,52 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4119
4144
|
async function loginViaApi(page, email, password) {
|
|
4120
4145
|
try {
|
|
4121
4146
|
const hashedPassword = crypto3.createHash("sha256").update(password).digest("hex");
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
email,
|
|
4130
|
-
password: hashedPassword,
|
|
4131
|
-
login_type: "email"
|
|
4132
|
-
},
|
|
4133
|
-
headers: {
|
|
4134
|
-
"content-type": "application/json",
|
|
4135
|
-
accept: "application/json, text/plain, */*",
|
|
4136
|
-
referer: qwenUrl("/auth"),
|
|
4137
|
-
origin: qwenOrigin(),
|
|
4138
|
-
source: "web"
|
|
4139
|
-
},
|
|
4140
|
-
timeout: 1e4
|
|
4141
|
-
});
|
|
4142
|
-
data = await response.json().catch(() => null);
|
|
4143
|
-
signinSuccess = Boolean(data && (data.success === true || data.token));
|
|
4144
|
-
} catch {
|
|
4145
|
-
}
|
|
4147
|
+
if (!page.url().includes("/auth")) {
|
|
4148
|
+
await page.goto(qwenUrl("/auth"), {
|
|
4149
|
+
waitUntil: "domcontentloaded",
|
|
4150
|
+
timeout: config.timeouts.navigation
|
|
4151
|
+
}).catch(() => {
|
|
4152
|
+
});
|
|
4153
|
+
await sleep2(1e3);
|
|
4146
4154
|
}
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4155
|
+
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
4156
|
+
const requestId = crypto3.randomUUID();
|
|
4157
|
+
const evalRes = await page.evaluate(
|
|
4158
|
+
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
|
|
4159
|
+
try {
|
|
4160
|
+
const response = await fetch(signinUrl2, {
|
|
4161
|
+
method: "POST",
|
|
4162
|
+
signal: AbortSignal.timeout(15e3),
|
|
4163
|
+
credentials: "include",
|
|
4164
|
+
headers: {
|
|
4165
|
+
accept: "application/json, text/plain, */*",
|
|
4166
|
+
"content-type": "application/json",
|
|
4167
|
+
source: "web",
|
|
4168
|
+
version: "0.3.11",
|
|
4169
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
4170
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
4171
|
+
"x-request-id": requestId2
|
|
4172
|
+
},
|
|
4173
|
+
body: JSON.stringify({ email: email2, password: password2 })
|
|
4174
|
+
});
|
|
4175
|
+
const json = await response.json().catch(() => null);
|
|
4176
|
+
return { ok: response.ok, status: response.status, data: json };
|
|
4177
|
+
} catch (e) {
|
|
4178
|
+
return { ok: false, error: e.message };
|
|
4179
|
+
}
|
|
4180
|
+
},
|
|
4181
|
+
{ email, password: hashedPassword, signinUrl, requestId }
|
|
4182
|
+
).catch(() => null);
|
|
4183
|
+
let data = evalRes?.data;
|
|
4184
|
+
let signinSuccess = Boolean(
|
|
4185
|
+
data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
|
|
4186
|
+
);
|
|
4187
|
+
if (!signinSuccess && !data?.data?.code) {
|
|
4188
|
+
const fallbackUrl = qwenUrl("/api/v2/auths/signin");
|
|
4189
|
+
const fallbackRes = await page.evaluate(
|
|
4190
|
+
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
|
|
4151
4191
|
try {
|
|
4152
|
-
const response = await fetch(
|
|
4192
|
+
const response = await fetch(fallbackUrl2, {
|
|
4153
4193
|
method: "POST",
|
|
4154
4194
|
signal: AbortSignal.timeout(1e4),
|
|
4155
4195
|
credentials: "include",
|
|
@@ -4157,10 +4197,11 @@ async function loginViaApi(page, email, password) {
|
|
|
4157
4197
|
accept: "application/json, text/plain, */*",
|
|
4158
4198
|
"content-type": "application/json",
|
|
4159
4199
|
source: "web",
|
|
4200
|
+
version: "0.3.11",
|
|
4160
4201
|
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
4161
4202
|
"x-request-id": requestId2
|
|
4162
4203
|
},
|
|
4163
|
-
body: JSON.stringify({ email: email2, password: password2
|
|
4204
|
+
body: JSON.stringify({ email: email2, password: password2 })
|
|
4164
4205
|
});
|
|
4165
4206
|
const json = await response.json().catch(() => null);
|
|
4166
4207
|
return { ok: response.ok, status: response.status, data: json };
|
|
@@ -4168,11 +4209,13 @@ async function loginViaApi(page, email, password) {
|
|
|
4168
4209
|
return { ok: false, error: e.message };
|
|
4169
4210
|
}
|
|
4170
4211
|
},
|
|
4171
|
-
{ email, password: hashedPassword,
|
|
4212
|
+
{ email, password: hashedPassword, fallbackUrl, requestId }
|
|
4172
4213
|
).catch(() => null);
|
|
4173
|
-
if (
|
|
4174
|
-
data =
|
|
4175
|
-
signinSuccess = Boolean(
|
|
4214
|
+
if (fallbackRes?.data) {
|
|
4215
|
+
data = fallbackRes.data;
|
|
4216
|
+
signinSuccess = Boolean(
|
|
4217
|
+
data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
|
|
4218
|
+
);
|
|
4176
4219
|
}
|
|
4177
4220
|
}
|
|
4178
4221
|
if (data?.success === false) {
|
|
@@ -4186,7 +4229,8 @@ async function loginViaApi(page, email, password) {
|
|
|
4186
4229
|
};
|
|
4187
4230
|
}
|
|
4188
4231
|
if (signinSuccess) {
|
|
4189
|
-
const token = data?.data?.token || data?.token;
|
|
4232
|
+
const token = data?.data?.access_token || data?.data?.token || data?.access_token || data?.token;
|
|
4233
|
+
const refreshToken = data?.data?.refresh_token || data?.refresh_token;
|
|
4190
4234
|
if (token) {
|
|
4191
4235
|
try {
|
|
4192
4236
|
await page.context().addCookies([
|
|
@@ -4210,14 +4254,19 @@ async function loginViaApi(page, email, password) {
|
|
|
4210
4254
|
}).catch(() => {
|
|
4211
4255
|
});
|
|
4212
4256
|
if (token) {
|
|
4213
|
-
await page.evaluate(
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4257
|
+
await page.evaluate(
|
|
4258
|
+
({ tok, rTok }) => {
|
|
4259
|
+
try {
|
|
4260
|
+
localStorage.removeItem("qwen_token_logged_out_marker");
|
|
4261
|
+
localStorage.setItem("token", tok);
|
|
4262
|
+
localStorage.setItem("access_token", tok);
|
|
4263
|
+
if (rTok) localStorage.setItem("refresh_token", rTok);
|
|
4264
|
+
document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
4265
|
+
} catch {
|
|
4266
|
+
}
|
|
4267
|
+
},
|
|
4268
|
+
{ tok: token, rTok: refreshToken }
|
|
4269
|
+
).catch(() => {
|
|
4221
4270
|
});
|
|
4222
4271
|
await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
|
|
4223
4272
|
});
|
|
@@ -4245,11 +4294,23 @@ async function loginViaApi(page, email, password) {
|
|
|
4245
4294
|
}
|
|
4246
4295
|
async function loginViaUi(page, email, password) {
|
|
4247
4296
|
try {
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4297
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3).catch(() => false)) {
|
|
4298
|
+
return { success: true };
|
|
4299
|
+
}
|
|
4300
|
+
try {
|
|
4301
|
+
await page.goto(qwenUrl("/auth"), {
|
|
4302
|
+
waitUntil: "domcontentloaded",
|
|
4303
|
+
timeout: Math.min(config.timeouts.navigation, 15e3)
|
|
4304
|
+
});
|
|
4305
|
+
await sleep2(1e3);
|
|
4306
|
+
} catch (gotoErr) {
|
|
4307
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
4308
|
+
return { success: true };
|
|
4309
|
+
}
|
|
4310
|
+
}
|
|
4311
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
4312
|
+
return { success: true };
|
|
4313
|
+
}
|
|
4253
4314
|
const emailSelector = [
|
|
4254
4315
|
'input[type="email"]',
|
|
4255
4316
|
'input[name="email"]',
|
|
@@ -4259,7 +4320,7 @@ async function loginViaUi(page, email, password) {
|
|
|
4259
4320
|
].join(", ");
|
|
4260
4321
|
try {
|
|
4261
4322
|
await page.waitForSelector(emailSelector, {
|
|
4262
|
-
timeout: Math.min(config.timeouts.page,
|
|
4323
|
+
timeout: Math.min(config.timeouts.page, 5e3)
|
|
4263
4324
|
});
|
|
4264
4325
|
} catch {
|
|
4265
4326
|
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
@@ -4272,30 +4333,55 @@ async function loginViaUi(page, email, password) {
|
|
|
4272
4333
|
return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
|
|
4273
4334
|
}
|
|
4274
4335
|
await clearVisibleChallenge(page);
|
|
4275
|
-
const
|
|
4276
|
-
return page.locator('
|
|
4277
|
-
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
|
|
4278
|
-
}).first();
|
|
4336
|
+
const isPasswordInputPresent = async () => {
|
|
4337
|
+
return await page.locator('input[type="password"], input[name="password"]').count().catch(() => 0) > 0;
|
|
4279
4338
|
};
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
|
|
4339
|
+
const revealPasswordMode = async () => {
|
|
4340
|
+
if (page.url().includes("/forget")) {
|
|
4341
|
+
await page.goto(qwenUrl("/auth"), { waitUntil: "domcontentloaded", timeout: 1e4 }).catch(() => {
|
|
4284
4342
|
});
|
|
4285
|
-
await sleep2(
|
|
4343
|
+
await sleep2(1e3);
|
|
4286
4344
|
}
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
if (await
|
|
4294
|
-
await
|
|
4345
|
+
if (await isPasswordInputPresent()) return;
|
|
4346
|
+
const btn = page.locator("button").filter({
|
|
4347
|
+
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
|
|
4348
|
+
}).filter({
|
|
4349
|
+
hasNotText: /(?:esqueci|forgot|olvid|reset|recover)/i
|
|
4350
|
+
}).first();
|
|
4351
|
+
if (await btn.isVisible({ timeout: 1500 }).catch(() => false)) {
|
|
4352
|
+
await btn.click({ timeout: 2e3 }).catch(() => {
|
|
4295
4353
|
});
|
|
4296
4354
|
await sleep2(500);
|
|
4297
4355
|
}
|
|
4356
|
+
if (await isPasswordInputPresent()) return;
|
|
4357
|
+
await page.evaluate(() => {
|
|
4358
|
+
try {
|
|
4359
|
+
const buttons = Array.from(document.querySelectorAll("button, [role='button'], a"));
|
|
4360
|
+
for (const b of buttons) {
|
|
4361
|
+
const txt = (b.innerText || "").trim().toLowerCase();
|
|
4362
|
+
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")) {
|
|
4363
|
+
b.click();
|
|
4364
|
+
return true;
|
|
4365
|
+
}
|
|
4366
|
+
}
|
|
4367
|
+
} catch {
|
|
4368
|
+
}
|
|
4369
|
+
return false;
|
|
4370
|
+
}).catch(() => false);
|
|
4371
|
+
await sleep2(500);
|
|
4372
|
+
};
|
|
4373
|
+
await revealPasswordMode();
|
|
4374
|
+
try {
|
|
4375
|
+
await page.fill(emailSelector, email, { timeout: 8e3 });
|
|
4376
|
+
await sleep2(300);
|
|
4298
4377
|
} catch {
|
|
4378
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
4379
|
+
return { success: true };
|
|
4380
|
+
}
|
|
4381
|
+
throw new Error(`Campo de e-mail n\xE3o encontrado na tela de autentica\xE7\xE3o`);
|
|
4382
|
+
}
|
|
4383
|
+
if (!await isPasswordInputPresent()) {
|
|
4384
|
+
await revealPasswordMode();
|
|
4299
4385
|
}
|
|
4300
4386
|
const passwordSelector = 'input[type="password"], input[name="password"]';
|
|
4301
4387
|
try {
|
|
@@ -4314,61 +4400,108 @@ async function loginViaUi(page, email, password) {
|
|
|
4314
4400
|
reason: "Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o"
|
|
4315
4401
|
};
|
|
4316
4402
|
}
|
|
4317
|
-
|
|
4318
|
-
|
|
4403
|
+
try {
|
|
4404
|
+
await page.fill(passwordSelector, password, { timeout: 8e3 });
|
|
4405
|
+
await sleep2(500);
|
|
4406
|
+
} catch {
|
|
4407
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
|
|
4408
|
+
return { success: true };
|
|
4409
|
+
}
|
|
4410
|
+
throw new Error(`Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o`);
|
|
4411
|
+
}
|
|
4412
|
+
await page.evaluate(() => {
|
|
4413
|
+
try {
|
|
4414
|
+
const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
|
|
4415
|
+
const passEl = document.querySelector('input[type="password"], input[name="password"]');
|
|
4416
|
+
if (emailEl) {
|
|
4417
|
+
emailEl.dispatchEvent(new Event("input", { bubbles: true }));
|
|
4418
|
+
emailEl.dispatchEvent(new Event("change", { bubbles: true }));
|
|
4419
|
+
emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
4420
|
+
}
|
|
4421
|
+
if (passEl) {
|
|
4422
|
+
passEl.dispatchEvent(new Event("input", { bubbles: true }));
|
|
4423
|
+
passEl.dispatchEvent(new Event("change", { bubbles: true }));
|
|
4424
|
+
passEl.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
4425
|
+
}
|
|
4426
|
+
} catch {
|
|
4427
|
+
}
|
|
4428
|
+
}).catch(() => {
|
|
4429
|
+
});
|
|
4319
4430
|
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")';
|
|
4320
4431
|
const submitButton = page.locator(submitSelector).first();
|
|
4321
4432
|
try {
|
|
4322
4433
|
await page.waitForSelector('button[type="submit"]:not([disabled])', {
|
|
4323
|
-
timeout:
|
|
4434
|
+
timeout: 4e3
|
|
4324
4435
|
});
|
|
4325
4436
|
await submitButton.click();
|
|
4326
4437
|
} catch {
|
|
4327
|
-
await
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
|
|
4337
|
-
const codeInput = page.locator(codeSelector).first();
|
|
4338
|
-
if (await codeInput.isVisible().catch(() => false)) {
|
|
4339
|
-
return {
|
|
4340
|
-
success: false,
|
|
4341
|
-
reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
|
|
4342
|
-
};
|
|
4438
|
+
const isDisabled = await submitButton.isDisabled().catch(() => true);
|
|
4439
|
+
if (!isDisabled) {
|
|
4440
|
+
await submitButton.click({ force: true }).catch(() => {
|
|
4441
|
+
});
|
|
4442
|
+
} else {
|
|
4443
|
+
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
|
|
4444
|
+
return { success: true };
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4343
4447
|
}
|
|
4344
|
-
const
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4448
|
+
const postSubmitDeadline = Date.now() + 15e3;
|
|
4449
|
+
while (Date.now() < postSubmitDeadline) {
|
|
4450
|
+
if (page.isClosed()) break;
|
|
4451
|
+
if (config.captcha.enabled) {
|
|
4452
|
+
await solveBaxiaCaptcha(page, {
|
|
4453
|
+
waitForMs: 1500,
|
|
4454
|
+
maxAttempts: config.captcha.maxAttempts,
|
|
4455
|
+
retryDelayMs: config.captcha.retryDelayMs
|
|
4456
|
+
}).catch(() => {
|
|
4457
|
+
});
|
|
4458
|
+
}
|
|
4459
|
+
const errorSelector = [
|
|
4460
|
+
".qwen-chat-v2-toast-text",
|
|
4461
|
+
".qwen-chat-v2-toast-content",
|
|
4462
|
+
".ant-form-item-explain-error",
|
|
4463
|
+
".ant-message-error",
|
|
4464
|
+
".ant-message-notice",
|
|
4465
|
+
'[role="alert"]',
|
|
4466
|
+
".qwenchat-auth-error",
|
|
4467
|
+
".auth-error-message"
|
|
4468
|
+
].join(", ");
|
|
4469
|
+
const errorEl = page.locator(errorSelector).first();
|
|
4470
|
+
if (await errorEl.isVisible().catch(() => false)) {
|
|
4471
|
+
const errorText = (await errorEl.innerText().catch(() => "")).trim();
|
|
4472
|
+
if (errorText) {
|
|
4473
|
+
const classified = classifyQwenAuthError(void 0, errorText);
|
|
4474
|
+
return {
|
|
4475
|
+
success: false,
|
|
4476
|
+
permanentFailure: classified.isPermanent,
|
|
4477
|
+
reason: `Formul\xE1rio: ${classified.reason}`
|
|
4478
|
+
};
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4481
|
+
const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
|
|
4482
|
+
const codeInput = page.locator(codeSelector).first();
|
|
4483
|
+
if (await codeInput.isVisible().catch(() => false)) {
|
|
4359
4484
|
return {
|
|
4360
4485
|
success: false,
|
|
4361
|
-
|
|
4362
|
-
reason: `Formul\xE1rio: ${classified.reason}`
|
|
4486
|
+
reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
|
|
4363
4487
|
};
|
|
4364
4488
|
}
|
|
4489
|
+
try {
|
|
4490
|
+
const liveCookies = await page.context().cookies();
|
|
4491
|
+
if (liveCookies.some((c) => c.name === "token")) {
|
|
4492
|
+
return { success: true };
|
|
4493
|
+
}
|
|
4494
|
+
} catch {
|
|
4495
|
+
}
|
|
4496
|
+
const currentUrl = page.url();
|
|
4497
|
+
if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
|
|
4498
|
+
if (await isPageLoggedIn(page, 3e3)) {
|
|
4499
|
+
return { success: true };
|
|
4500
|
+
}
|
|
4501
|
+
}
|
|
4502
|
+
await sleep2(1e3);
|
|
4365
4503
|
}
|
|
4366
|
-
|
|
4367
|
-
if (isLoggedIn) {
|
|
4368
|
-
await page.goto(qwenUrl("/"), {
|
|
4369
|
-
waitUntil: "domcontentloaded",
|
|
4370
|
-
timeout: config.timeouts.navigation
|
|
4371
|
-
});
|
|
4504
|
+
if (await isPageLoggedIn(page, 3e3)) {
|
|
4372
4505
|
return { success: true };
|
|
4373
4506
|
}
|
|
4374
4507
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qwenproxy-cli",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.7",
|
|
4
4
|
"description": "High-performance OpenAI & Anthropic compatible API gateway for Qwen with multi-account rotation, interactive TUI, and resilient tool calling.",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"bin": {
|
package/src/core/version.ts
CHANGED
package/src/login.ts
CHANGED
|
@@ -120,7 +120,7 @@ async function addAccountFlow() {
|
|
|
120
120
|
|
|
121
121
|
const ok = await validateAccountLogin(
|
|
122
122
|
{ id: tempId, email: trimmedEmail, password: trimmedPassword },
|
|
123
|
-
|
|
123
|
+
false, // Visible browser so user can see and complete challenges if needed
|
|
124
124
|
config.playwright.browser,
|
|
125
125
|
);
|
|
126
126
|
|