manual login compatible with old cookie acquisition
This commit is contained in:
+128
-98
@@ -18,7 +18,7 @@ class YouProvider {
|
|||||||
this.config = config;
|
this.config = config;
|
||||||
this.sessions = {};
|
this.sessions = {};
|
||||||
// 可以是 'chrome', 'edge', 或 'auto'
|
// 可以是 'chrome', 'edge', 或 'auto'
|
||||||
this.preferredBrowser = 'auto';
|
this.preferredBrowser = 'edge';
|
||||||
this.isCustomModeEnabled = process.env.USE_CUSTOM_MODE === "true";
|
this.isCustomModeEnabled = process.env.USE_CUSTOM_MODE === "true";
|
||||||
this.isRotationEnabled = process.env.ENABLE_MODE_ROTATION === "true";
|
this.isRotationEnabled = process.env.ENABLE_MODE_ROTATION === "true";
|
||||||
this.currentMode = "default";
|
this.currentMode = "default";
|
||||||
@@ -66,12 +66,12 @@ class YouProvider {
|
|||||||
} else {
|
} else {
|
||||||
// 使用配置文件中的 cookie
|
// 使用配置文件中的 cookie
|
||||||
for (let index = 0; index < config.sessions.length; index++) {
|
for (let index = 0; index < config.sessions.length; index++) {
|
||||||
let session = config.sessions[index];
|
const session = config.sessions[index];
|
||||||
let {jwtSession, jwtToken, ds, dsr} = extractCookie(session.cookie);
|
const {jwtSession, jwtToken, ds, dsr} = extractCookie(session.cookie);
|
||||||
if (jwtSession && jwtToken) {
|
if (jwtSession && jwtToken) {
|
||||||
// 旧版cookie处理
|
// 旧版cookie处理
|
||||||
try {
|
try {
|
||||||
let jwt = JSON.parse(Buffer.from(jwtToken.split(".")[1], "base64").toString());
|
const jwt = JSON.parse(Buffer.from(jwtToken.split(".")[1], "base64").toString());
|
||||||
this.sessions[jwt.user.name] = {
|
this.sessions[jwt.user.name] = {
|
||||||
configIndex: index,
|
configIndex: index,
|
||||||
jwtSession,
|
jwtSession,
|
||||||
@@ -85,7 +85,7 @@ class YouProvider {
|
|||||||
} else if (ds) {
|
} else if (ds) {
|
||||||
// 新版cookie处理
|
// 新版cookie处理
|
||||||
try {
|
try {
|
||||||
let jwt = JSON.parse(Buffer.from(ds.split(".")[1], "base64").toString());
|
const jwt = JSON.parse(Buffer.from(ds.split(".")[1], "base64").toString());
|
||||||
this.sessions[jwt.email] = {
|
this.sessions[jwt.email] = {
|
||||||
configIndex: index,
|
configIndex: index,
|
||||||
ds,
|
ds,
|
||||||
@@ -107,91 +107,95 @@ class YouProvider {
|
|||||||
console.log(`已添加 ${Object.keys(this.sessions).length} 个 cookie,开始验证有效性`);
|
console.log(`已添加 ${Object.keys(this.sessions).length} 个 cookie,开始验证有效性`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let username of Object.keys(this.sessions)) {
|
for (const originalUsername of Object.keys(this.sessions)) {
|
||||||
let session = this.sessions[username];
|
let currentUsername = originalUsername;
|
||||||
createDirectoryIfNotExists(path.join(__dirname, "browser_profiles", username));
|
let session = this.sessions[currentUsername];
|
||||||
|
createDirectoryIfNotExists(path.join(__dirname, "browser_profiles", currentUsername));
|
||||||
const isWindows = os.platform() === 'win32';
|
const isWindows = os.platform() === 'win32';
|
||||||
|
|
||||||
await connect({
|
try {
|
||||||
headless: isWindows ? false : 'auto',
|
const response = await connect({
|
||||||
turnstile: true,
|
headless: isWindows ? false : 'auto',
|
||||||
customConfig: {
|
turnstile: true,
|
||||||
userDataDir: path.join(__dirname, "browser_profiles", username),
|
customConfig: {
|
||||||
executablePath: browserPath,
|
userDataDir: path.join(__dirname, "browser_profiles", currentUsername),
|
||||||
},
|
executablePath: browserPath,
|
||||||
})
|
},
|
||||||
.then(async (response) => {
|
});
|
||||||
const { page, browser } = response;
|
|
||||||
if (process.env.USE_MANUAL_LOGIN === "true") {
|
const { page, browser } = response;
|
||||||
console.log(`正在为 session #${session.configIndex} 进行手动登录...`);
|
if (process.env.USE_MANUAL_LOGIN === "true") {
|
||||||
await page.goto("https://you.com", { timeout: timeout });
|
console.log(`正在为 session #${session.configIndex} 进行手动登录...`);
|
||||||
// 等待页面加载完毕
|
await page.goto("https://you.com", { timeout: timeout });
|
||||||
await sleep(5000);
|
// 等待页面加载完毕
|
||||||
console.log(`请在打开的浏览器窗口中手动登录 You.com (session #${session.configIndex})`);
|
await sleep(5000);
|
||||||
const { loginInfo, sessionCookie } = await this.waitForManualLogin(page);
|
console.log(`请在打开的浏览器窗口中手动登录 You.com (session #${session.configIndex})`);
|
||||||
if (sessionCookie) {
|
const { loginInfo, sessionCookie } = await this.waitForManualLogin(page);
|
||||||
const email = loginInfo || sessionCookie.email;
|
if (sessionCookie) {
|
||||||
this.sessions[email] = {
|
const email = loginInfo || sessionCookie.email;
|
||||||
...session,
|
this.sessions[email] = {
|
||||||
...sessionCookie,
|
...session,
|
||||||
};
|
...sessionCookie,
|
||||||
delete this.sessions[username];
|
};
|
||||||
username = email;
|
delete this.sessions[currentUsername];
|
||||||
session = this.sessions[username];
|
currentUsername = email;
|
||||||
console.log(`成功获取 ${email} 登录的 cookie`);
|
session = this.sessions[currentUsername];
|
||||||
} else {
|
console.log(`成功获取 ${email} 登录的 cookie (${sessionCookie.isNewVersion ? '新版' : '旧版'})`);
|
||||||
console.error(`未能获取到 session #${session.configIndex} 有效登录的 cookie`);
|
|
||||||
await browser.close();
|
// 兼容设置隐身模式
|
||||||
return;
|
await page.setCookie(...sessionCookie);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
await page.setCookie(...getSessionCookie(
|
console.error(`未能获取到 session #${session.configIndex} 有效登录的 cookie`);
|
||||||
session.jwtSession,
|
await browser.close();
|
||||||
session.jwtToken,
|
continue;
|
||||||
session.ds,
|
|
||||||
session.dsr
|
|
||||||
));
|
|
||||||
await page.goto("https://you.com", { timeout: timeout });
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
await page.setCookie(...getSessionCookie(
|
||||||
|
session.jwtSession,
|
||||||
|
session.jwtToken,
|
||||||
|
session.ds,
|
||||||
|
session.dsr
|
||||||
|
));
|
||||||
|
await page.goto("https://you.com", { timeout: timeout });
|
||||||
|
}
|
||||||
|
|
||||||
await sleep(5000); // 等待加载完毕
|
await sleep(5000); // 等待加载完毕
|
||||||
|
|
||||||
// 如果遇到盾了就多等一段时间
|
// 如果遇到盾了就多等一段时间
|
||||||
let pageContent = await page.content();
|
const pageContent = await page.content();
|
||||||
if (pageContent.indexOf("https://challenges.cloudflare.com") > -1) {
|
if (pageContent.indexOf("https://challenges.cloudflare.com") > -1) {
|
||||||
console.log(`请在30秒内完成人机验证 (${username})`);
|
console.log(`请在30秒内完成人机验证 (${currentUsername})`);
|
||||||
await page.evaluate(() => {
|
await page.evaluate(() => {
|
||||||
alert("请在30秒内完成人机验证");
|
alert("请在30秒内完成人机验证");
|
||||||
});
|
});
|
||||||
await sleep(30000);
|
await sleep(30000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证 cookie 有效性
|
// 验证 cookie 有效性
|
||||||
try {
|
try {
|
||||||
let content = await page.evaluate(() => {
|
const content = await page.evaluate(() => {
|
||||||
return fetch("https://you.com/api/user/getYouProState").then((res) => res.text());
|
return fetch("https://you.com/api/user/getYouProState").then((res) => res.text());
|
||||||
});
|
});
|
||||||
let json = JSON.parse(content);
|
const json = JSON.parse(content);
|
||||||
if (json.subscriptions.length > 0) {
|
if (json.subscriptions.length > 0) {
|
||||||
console.log(`${username} 有效`);
|
console.log(`${currentUsername} 有效`);
|
||||||
session.valid = true;
|
session.valid = true;
|
||||||
session.browser = browser;
|
session.browser = browser;
|
||||||
session.page = page;
|
session.page = page;
|
||||||
} else {
|
} else {
|
||||||
console.log(`${username} 无有效订阅`);
|
console.log(`${currentUsername} 无有效订阅`);
|
||||||
console.warn(`警告: ${username} 可能没有有效的订阅。请检查You是否有有效的Pro订阅。`);
|
console.warn(`警告: ${currentUsername} 可能没有有效的订阅。请检查You是否有有效的Pro订阅。`);
|
||||||
await browser.close();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`${username} 已失效`);
|
|
||||||
console.warn(`警告: ${username} 验证失败。请检查cookie是否有效。`);
|
|
||||||
await browser.close();
|
await browser.close();
|
||||||
}
|
}
|
||||||
})
|
} catch (e) {
|
||||||
.catch((e) => {
|
console.log(`${currentUsername} 已失效`);
|
||||||
console.error(`初始化浏览器失败 (${username})`);
|
console.warn(`警告: ${currentUsername} 验证失败。请检查cookie是否有效。`);
|
||||||
console.error(e);
|
await browser.close();
|
||||||
});
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`初始化浏览器失败 (${currentUsername})`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
console.log(`验证完毕,有效cookie数量 ${Object.keys(this.sessions).filter((username) => this.sessions[username].valid).length}`);
|
console.log(`验证完毕,有效cookie数量 ${Object.keys(this.sessions).filter((username) => this.sessions[username].valid).length}`);
|
||||||
}
|
}
|
||||||
@@ -210,9 +214,14 @@ class YouProvider {
|
|||||||
|
|
||||||
if (loginInfo) {
|
if (loginInfo) {
|
||||||
console.log(`检测到自动登录成功: ${loginInfo}`);
|
console.log(`检测到自动登录成功: ${loginInfo}`);
|
||||||
// 立即获取 cookie
|
|
||||||
const cookies = await page.cookies();
|
const cookies = await page.cookies();
|
||||||
const sessionCookie = this.extractSessionCookie(cookies);
|
const sessionCookie = this.extractSessionCookie(cookies);
|
||||||
|
|
||||||
|
// 设置 隐身模式 cookie
|
||||||
|
if (sessionCookie) {
|
||||||
|
await page.setCookie(...sessionCookie);
|
||||||
|
}
|
||||||
|
|
||||||
resolve({ loginInfo, sessionCookie });
|
resolve({ loginInfo, sessionCookie });
|
||||||
} else {
|
} else {
|
||||||
setTimeout(checkLoginStatus, 1000);
|
setTimeout(checkLoginStatus, 1000);
|
||||||
@@ -223,6 +232,12 @@ class YouProvider {
|
|||||||
if (request.url().includes('https://you.com/api/instrumentation')) {
|
if (request.url().includes('https://you.com/api/instrumentation')) {
|
||||||
const cookies = await page.cookies();
|
const cookies = await page.cookies();
|
||||||
const sessionCookie = this.extractSessionCookie(cookies);
|
const sessionCookie = this.extractSessionCookie(cookies);
|
||||||
|
|
||||||
|
// 设置 隐身模式 cookie
|
||||||
|
if (sessionCookie) {
|
||||||
|
await page.setCookie(...sessionCookie);
|
||||||
|
}
|
||||||
|
|
||||||
resolve({ loginInfo: null, sessionCookie });
|
resolve({ loginInfo: null, sessionCookie });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -234,11 +249,26 @@ class YouProvider {
|
|||||||
extractSessionCookie(cookies) {
|
extractSessionCookie(cookies) {
|
||||||
const ds = cookies.find(c => c.name === 'DS')?.value;
|
const ds = cookies.find(c => c.name === 'DS')?.value;
|
||||||
const dsr = cookies.find(c => c.name === 'DSR')?.value;
|
const dsr = cookies.find(c => c.name === 'DSR')?.value;
|
||||||
if (ds) {
|
const jwtSession = cookies.find(c => c.name === 'stytch_session')?.value;
|
||||||
const jwt = JSON.parse(Buffer.from(ds.split(".")[1], "base64").toString());
|
const jwtToken = cookies.find(c => c.name === 'stytch_session_jwt')?.value;
|
||||||
return {ds, dsr, email: jwt.email};
|
|
||||||
|
let sessionCookie = null;
|
||||||
|
|
||||||
|
if (ds || (jwtSession && jwtToken)) {
|
||||||
|
sessionCookie = getSessionCookie(jwtSession, jwtToken, ds, dsr);
|
||||||
|
|
||||||
|
if (ds) {
|
||||||
|
const jwt = JSON.parse(Buffer.from(ds.split(".")[1], "base64").toString());
|
||||||
|
sessionCookie.email = jwt.email;
|
||||||
|
sessionCookie.isNewVersion = true;
|
||||||
|
} else {
|
||||||
|
const jwt = JSON.parse(Buffer.from(jwtToken.split(".")[1], "base64").toString());
|
||||||
|
sessionCookie.email = jwt.user.name;
|
||||||
|
sessionCookie.isNewVersion = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
return sessionCookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
detectBrowser() {
|
detectBrowser() {
|
||||||
@@ -525,7 +555,7 @@ class YouProvider {
|
|||||||
let traceId = uuidv4();
|
let traceId = uuidv4();
|
||||||
|
|
||||||
// expose function to receive youChatToken
|
// expose function to receive youChatToken
|
||||||
var finalResponse = "";
|
let finalResponse = "";
|
||||||
page.exposeFunction("callback" + traceId, async (event, data) => {
|
page.exposeFunction("callback" + traceId, async (event, data) => {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case "youChatToken":
|
case "youChatToken":
|
||||||
@@ -551,7 +581,7 @@ class YouProvider {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// proxy response
|
// proxy response
|
||||||
var req_param = new URLSearchParams();
|
const req_param = new URLSearchParams();
|
||||||
req_param.append("page", "1");
|
req_param.append("page", "1");
|
||||||
req_param.append("count", "10");
|
req_param.append("count", "10");
|
||||||
req_param.append("safeSearch", "Off");
|
req_param.append("safeSearch", "Off");
|
||||||
@@ -559,9 +589,9 @@ class YouProvider {
|
|||||||
req_param.append("chatId", traceId);
|
req_param.append("chatId", traceId);
|
||||||
req_param.append("traceId", `${traceId}|${msgid}|${new Date().toISOString()}`);
|
req_param.append("traceId", `${traceId}|${msgid}|${new Date().toISOString()}`);
|
||||||
req_param.append("conversationTurnId", msgid);
|
req_param.append("conversationTurnId", msgid);
|
||||||
if (userChatModeId == "custom") req_param.append("selectedAiModel", proxyModel);
|
if (userChatModeId === "custom") req_param.append("selectedAiModel", proxyModel);
|
||||||
req_param.append("selectedChatMode", userChatModeId);
|
req_param.append("selectedChatMode", userChatModeId);
|
||||||
req_param.append("pastChatLength", userMessage.length);
|
req_param.append("pastChatLength", userMessage.length.toString());
|
||||||
req_param.append("queryTraceId", traceId);
|
req_param.append("queryTraceId", traceId);
|
||||||
req_param.append("use_personalization_extraction", "false");
|
req_param.append("use_personalization_extraction", "false");
|
||||||
req_param.append("domain", "youchat");
|
req_param.append("domain", "youchat");
|
||||||
@@ -573,15 +603,15 @@ class YouProvider {
|
|||||||
size: messageBuffer.length
|
size: messageBuffer.length
|
||||||
}]));
|
}]));
|
||||||
req_param.append("chat", JSON.stringify(userMessage));
|
req_param.append("chat", JSON.stringify(userMessage));
|
||||||
var url = "https://you.com/api/streamingSearch?" + req_param.toString();
|
const url = "https://you.com/api/streamingSearch?" + req_param.toString();
|
||||||
console.log("正在发送请求");
|
console.log("正在发送请求");
|
||||||
emitter.emit("start", traceId);
|
emitter.emit("start", traceId);
|
||||||
try {
|
try {
|
||||||
await page.goto(`https://you.com/search?q=&fromSearchBar=true&tbm=youchat&chatMode=custom`, {waitUntil: "domcontentloaded"});
|
await page.goto(`https://you.com/search?q=&fromSearchBar=true&tbm=youchat&chatMode=custom`, {waitUntil: "domcontentloaded"});
|
||||||
await page.evaluate(
|
await page.evaluate(
|
||||||
async (url, traceId) => {
|
async (url, traceId) => {
|
||||||
var evtSource = new EventSource(url);
|
const evtSource = new EventSource(url);
|
||||||
var callbackName = "callback" + traceId;
|
const callbackName = "callback" + traceId;
|
||||||
evtSource.onerror = (error) => {
|
evtSource.onerror = (error) => {
|
||||||
window[callbackName]("error", error);
|
window[callbackName]("error", error);
|
||||||
evtSource.close();
|
evtSource.close();
|
||||||
@@ -589,14 +619,14 @@ class YouProvider {
|
|||||||
evtSource.addEventListener(
|
evtSource.addEventListener(
|
||||||
"youChatToken",
|
"youChatToken",
|
||||||
(event) => {
|
(event) => {
|
||||||
var data = event.data;
|
const data = event.data;
|
||||||
window[callbackName]("youChatToken", data);
|
window[callbackName]("youChatToken", data);
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
evtSource.addEventListener(
|
evtSource.addEventListener(
|
||||||
"done",
|
"done",
|
||||||
(event) => {
|
() => {
|
||||||
window[callbackName]("done", "");
|
window[callbackName]("done", "");
|
||||||
evtSource.close();
|
evtSource.close();
|
||||||
fetch("https://you.com/api/chat/deleteChat", {
|
fetch("https://you.com/api/chat/deleteChat", {
|
||||||
@@ -613,7 +643,7 @@ class YouProvider {
|
|||||||
evtSource.onmessage = (event) => {
|
evtSource.onmessage = (event) => {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
if (data.youChatToken) {
|
if (data.youChatToken) {
|
||||||
window[callbackName](youChatToken);
|
window[callbackName]("youChatToken", data.youChatToken);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// 注册退出函数
|
// 注册退出函数
|
||||||
@@ -628,8 +658,8 @@ class YouProvider {
|
|||||||
console.error("评估过程中出错:", error);
|
console.error("评估过程中出错:", error);
|
||||||
emitter.emit("error", error);
|
emitter.emit("error", error);
|
||||||
return {
|
return {
|
||||||
completion: emitter, cancel: () => {
|
completion: emitter,
|
||||||
}
|
cancel: () => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user