add manual login

This commit is contained in:
被遗忘的记忆
2024-08-25 15:17:15 +08:00
committed by GitHub
parent f0e9d8e24b
commit 5dc7bfc1b6
+112 -31
View File
@@ -1,14 +1,14 @@
import { EventEmitter } from "events"; import {EventEmitter} from "events";
import { connect } from "puppeteer-real-browser"; import {connect} from "puppeteer-real-browser";
import { v4 as uuidv4 } from "uuid"; import {v4 as uuidv4} from "uuid";
import path from "path"; import path from "path";
import fs from "fs"; import fs from "fs";
import { fileURLToPath } from "url"; import {fileURLToPath} from "url";
import { createDirectoryIfNotExists, sleep, extractCookie, getSessionCookie, createDocx } from "./utils.mjs"; import {createDirectoryIfNotExists, createDocx, extractCookie, getSessionCookie, sleep} from "./utils.mjs";
import { execSync } from 'child_process'; import {execSync} from 'child_process';
import os from 'os'; import os from 'os';
import './proxyAgent.mjs'; import './proxyAgent.mjs';
import { formatMessages } from './formatMessages.mjs'; import {formatMessages} from './formatMessages.mjs';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
@@ -54,9 +54,20 @@ class YouProvider {
// 检测Chrome和Edge浏览器 // 检测Chrome和Edge浏览器
const browserPath = this.detectBrowser(); const browserPath = this.detectBrowser();
// extract essential jwt session and token from cookie this.sessions = {};
const timeout = 120000; // 120 秒超时
if (process.env.USE_MANUAL_LOGIN === "true") {
this.sessions['manual_login'] = {
configIndex: 0,
valid: false,
};
console.log("当前使用手动登录模式,跳过config.mjs文件中的 cookie 验证");
} else {
// 使用配置文件中的 cookie
for (let index = 0; index < config.sessions.length; index++) { for (let index = 0; index < config.sessions.length; index++) {
let session = config.sessions[index], {jwtSession, jwtToken, ds, dsr} = extractCookie(session.cookie); let session = config.sessions[index];
let {jwtSession, jwtToken, ds, dsr} = extractCookie(session.cookie);
if (jwtSession && jwtToken) { if (jwtSession && jwtToken) {
// 旧版cookie处理 // 旧版cookie处理
try { try {
@@ -94,12 +105,15 @@ 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 (let username of Object.keys(this.sessions)) {
let session = this.sessions[username]; let session = this.sessions[username];
createDirectoryIfNotExists(path.join(__dirname, "browser_profiles", username)); createDirectoryIfNotExists(path.join(__dirname, "browser_profiles", username));
const isWindows = os.platform() === 'win32';
await connect({ await connect({
headless: "auto", headless: isWindows ? false : 'auto',
turnstile: true, turnstile: true,
customConfig: { customConfig: {
userDataDir: path.join(__dirname, "browser_profiles", username), userDataDir: path.join(__dirname, "browser_profiles", username),
@@ -107,27 +121,53 @@ class YouProvider {
}, },
}) })
.then(async (response) => { .then(async (response) => {
const { page, browser, setTarget } = response; const { page, browser } = response;
if (process.env.USE_MANUAL_LOGIN === "true") {
console.log(`正在为 session #${session.configIndex} 进行手动登录...`);
await page.goto("https://you.com", { timeout: timeout });
// 等待页面加载完毕
await sleep(5000);
console.log(`请在打开的浏览器窗口中手动登录 You.com (session #${session.configIndex})`);
await this.waitForManualLogin(page);
const cookies = await page.cookies();
const sessionCookie = this.extractSessionCookie(cookies);
if (sessionCookie) {
this.sessions[sessionCookie.email] = {
...session,
...sessionCookie,
};
delete this.sessions[username];
username = sessionCookie.email;
session = this.sessions[username];
console.log(`成功获取 ${sessionCookie.email} 登录的 cookie`);
} else {
console.error(`未能获取到 session #${session.configIndex} 有效登录的 cookie`);
await browser.close();
return;
}
} else {
await page.setCookie(...getSessionCookie( await page.setCookie(...getSessionCookie(
session.jwtSession, session.jwtSession,
session.jwtToken, session.jwtToken,
session.ds, session.ds,
session.dsr session.dsr
)); ));
await page.goto("https://you.com", { timeout: timeout });
}
page.goto("https://you.com", { timeout: 60000 });
await sleep(5000); // 等待加载完毕 await sleep(5000); // 等待加载完毕
// 如果遇到盾了就多等一段时间 // 如果遇到盾了就多等一段时间
let pageContent = await page.content(); let pageContent = await page.content();
if (pageContent.indexOf("https://challenges.cloudflare.com") > -1) { if (pageContent.indexOf("https://challenges.cloudflare.com") > -1) {
console.log(`请在30秒内完成人机验证`); console.log(`请在30秒内完成人机验证 (${username})`);
page.evaluate(() => { await page.evaluate(() => {
alert("请在30秒内完成人机验证"); alert("请在30秒内完成人机验证");
}); });
await sleep(30000); await sleep(30000);
} }
// get page content and try parse JSON // 验证 cookie 有效性
try { try {
let content = await page.evaluate(() => { let 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());
@@ -150,13 +190,47 @@ class YouProvider {
} }
}) })
.catch((e) => { .catch((e) => {
console.error(`初始化浏览器失败`); console.error(`初始化浏览器失败 (${username})`);
console.error(e); 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}`);
} }
async waitForManualLogin(page) {
return new Promise((resolve) => {
const checkLoginStatus = async () => {
const isLoggedIn = await page.evaluate(() => {
return !!document.querySelector('button[aria-label="User menu"]');
});
if (isLoggedIn) {
console.log("检测到登录成功");
resolve();
} else {
setTimeout(checkLoginStatus, 1000);
}
};
page.on('request', request => {
if (request.url().includes('https://you.com/api/instrumentation')) {
resolve();
}
});
checkLoginStatus();
});
}
extractSessionCookie(cookies) {
const ds = cookies.find(c => c.name === 'DS')?.value;
const dsr = cookies.find(c => c.name === 'DSR')?.value;
if (ds) {
const jwt = JSON.parse(Buffer.from(ds.split(".")[1], "base64").toString());
return {ds, dsr, email: jwt.email};
}
return null;
}
detectBrowser() { detectBrowser() {
const platform = os.platform(); const platform = os.platform();
let browsers = { let browsers = {
@@ -265,7 +339,7 @@ class YouProvider {
throw new Error(`用户 ${username} 的会话无效`); throw new Error(`用户 ${username} 的会话无效`);
} }
const { page, browser } = session; const {page, browser} = session;
const emitter = new EventEmitter(); const emitter = new EventEmitter();
// 处理模式轮换逻辑 // 处理模式轮换逻辑
if (this.isCustomModeEnabled && this.isRotationEnabled) { if (this.isCustomModeEnabled && this.isRotationEnabled) {
@@ -288,15 +362,15 @@ class YouProvider {
if (!isLoaded) { if (!isLoaded) {
console.log('页面尚未加载完成,等待加载...'); console.log('页面尚未加载完成,等待加载...');
await page.waitForNavigation({ waitUntil: 'domcontentloaded', timeout: 10000 }).catch(() => { await page.waitForNavigation({waitUntil: 'domcontentloaded', timeout: 10000}).catch(() => {
console.log('页面加载超时,继续执行'); console.log('页面加载超时,继续执行');
}); });
} }
await page.goto("https://you.com/?chatMode=default", { waitUntil: "domcontentloaded" }); await page.goto("https://you.com/?chatMode=default", {waitUntil: "domcontentloaded"});
// 计算用户消息长度 // 计算用户消息长度
let userMessage = [{ question: "", answer: "" }]; let userMessage = [{question: "", answer: ""}];
let userQuery = ""; let userQuery = "";
let lastUpdate = true; let lastUpdate = true;
@@ -307,7 +381,7 @@ class YouProvider {
} else if (userMessage[userMessage.length - 1].question == "") { } else if (userMessage[userMessage.length - 1].question == "") {
userMessage[userMessage.length - 1].question += msg.content + "\n"; userMessage[userMessage.length - 1].question += msg.content + "\n";
} else { } else {
userMessage.push({ question: msg.content + "\n", answer: "" }); userMessage.push({question: msg.content + "\n", answer: ""});
} }
lastUpdate = true; lastUpdate = true;
} else if (msg.role == "assistant") { } else if (msg.role == "assistant") {
@@ -316,7 +390,7 @@ class YouProvider {
} else if (userMessage[userMessage.length - 1].answer == "") { } else if (userMessage[userMessage.length - 1].answer == "") {
userMessage[userMessage.length - 1].answer += msg.content + "\n"; userMessage[userMessage.length - 1].answer += msg.content + "\n";
} else { } else {
userMessage.push({ question: "", answer: msg.content + "\n" }); userMessage.push({question: "", answer: msg.content + "\n"});
} }
lastUpdate = false; lastUpdate = false;
} }
@@ -342,7 +416,7 @@ class YouProvider {
hideInstructions: true, hideInstructions: true,
includeFollowUps: false, includeFollowUps: false,
instructions: "Please review the attached prompt", instructions: "Please review the attached prompt",
instructionsSummary:"", instructionsSummary: "",
isUserOwned: true, isUserOwned: true,
name: proxyModelName, name: proxyModelName,
visibility: "private", visibility: "private",
@@ -355,12 +429,12 @@ class YouProvider {
proxyModel, proxyModel,
uuidv4().substring(0, 4) uuidv4().substring(0, 4)
); );
if(userChatMode.chat_mode_id){ if (userChatMode.chat_mode_id) {
this.config.sessions[session.configIndex].user_chat_mode_id[proxyModel] = userChatMode.chat_mode_id; this.config.sessions[session.configIndex].user_chat_mode_id[proxyModel] = userChatMode.chat_mode_id;
// 写回config // 写回config
fs.writeFileSync("./config.mjs", "export const config = " + JSON.stringify(this.config, null, 4)); fs.writeFileSync("./config.mjs", "export const config = " + JSON.stringify(this.config, null, 4));
}else{ } else {
if(userChatMode.error) console.log(userChatMode.error) if (userChatMode.error) console.log(userChatMode.error)
console.log("Failed to create user chat mode, will use default mode instead."); console.log("Failed to create user chat mode, will use default mode instead.");
} }
} }
@@ -483,13 +557,17 @@ class YouProvider {
req_param.append("domain", "youchat"); req_param.append("domain", "youchat");
req_param.append("mkt", "ja-JP"); req_param.append("mkt", "ja-JP");
if (uploadedFile) if (uploadedFile)
req_param.append("userFiles", JSON.stringify([{ user_filename: randomFileName, filename: uploadedFile.filename, size: messageBuffer.length }])); req_param.append("userFiles", JSON.stringify([{
user_filename: randomFileName,
filename: uploadedFile.filename,
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(); var 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); var evtSource = new EventSource(url);
@@ -515,7 +593,7 @@ class YouProvider {
headers: { headers: {
"content-type": "application/json", "content-type": "application/json",
}, },
body: JSON.stringify({ chatId: traceId }), body: JSON.stringify({chatId: traceId}),
method: "DELETE", method: "DELETE",
}); });
}, },
@@ -539,7 +617,10 @@ class YouProvider {
} catch (error) { } catch (error) {
console.error("评估过程中出错:", error); console.error("评估过程中出错:", error);
emitter.emit("error", error); emitter.emit("error", error);
return { completion: emitter, cancel: () => {} }; return {
completion: emitter, cancel: () => {
}
};
} }
const cancel = () => { const cancel = () => {
@@ -548,7 +629,7 @@ class YouProvider {
}, traceId).catch(console.error); }, traceId).catch(console.error);
}; };
return { completion: emitter, cancel }; return {completion: emitter, cancel};
} }
} }