add manual login
This commit is contained in:
+112
-31
@@ -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};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user