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/clean-cache.js +188 -70
- package/dist/delete-chats.js +241 -81
- package/dist/index.js +242 -82
- package/dist/login.js +241 -81
- package/dist/reset-cooldowns.js +188 -70
- package/package.json +1 -1
- package/src/core/version.ts +1 -1
- package/src/services/playwright.ts +288 -85
package/dist/clean-cache.js
CHANGED
|
@@ -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
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
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
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
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(
|
|
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
|
|
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,
|
|
3976
|
+
{ email, password: hashedPassword, fallbackUrl, requestId }
|
|
3937
3977
|
).catch(() => null);
|
|
3938
|
-
if (
|
|
3939
|
-
data =
|
|
3940
|
-
signinSuccess = Boolean(
|
|
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(
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
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
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
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,
|
|
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
|
|
4041
|
-
return page.locator('
|
|
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
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
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(
|
|
4107
|
+
await sleep2(1e3);
|
|
4051
4108
|
}
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
if (await
|
|
4059
|
-
await
|
|
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
|
-
|
|
4083
|
-
|
|
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:
|
|
4198
|
+
timeout: 4e3
|
|
4089
4199
|
});
|
|
4090
4200
|
await submitButton.click();
|
|
4091
4201
|
} catch {
|
|
4092
|
-
await
|
|
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) {
|