更新依赖项,优化 WebSocket 处理,添加文件流管道功能,改进用户认证逻辑

This commit is contained in:
2025-12-21 02:06:38 +08:00
parent d22be3a840
commit 15fcfdad18
16 changed files with 150 additions and 262 deletions

View File

@@ -1,4 +1,4 @@
import { getDNS, isIpv4OrIpv6, isLocalhost } from '../modules/fm-manager/index.ts';
import { getDNS, isIpv4OrIpv6, isLocalhost, pipeFileStream } from '../modules/fm-manager/index.ts';
import http from 'node:http';
import https from 'node:https';
import { UserApp } from '../modules/user-app/index.ts';
@@ -15,6 +15,7 @@ import { logger } from '../modules/logger.ts';
import { UserV1Proxy } from '../modules/ws-proxy/proxy.ts';
import { hasBadUser, userIsBanned, appIsBanned, userPathIsBanned } from '@/modules/off/index.ts';
import { robotsTxt } from '@/modules/html/index.ts';
import { isBun } from '@/utils/get-engine.ts';
const domain = config?.proxy?.domain;
const allowedOrigins = config?.proxy?.allowedOrigin || [];
@@ -50,7 +51,7 @@ const checkNotAuthPath = (user, app) => {
const forBadUser = (req: http.IncomingMessage, res: http.ServerResponse) => {
// TODO: 记录日志封禁IP等操作
const dns = getDNS(req);
logger.warn(`Bad user access from IP: ${dns.ip}, Host: ${dns.hostName}, URL: ${req.url}`);
logger.warn(`forBadUser: Bad user access from IP: ${dns.ip}, Host: ${dns.hostName}, URL: ${req.url}`);
// 这里可以添加更多的处理逻辑比如封禁IP等
}
export const handleRequest = async (req: http.IncomingMessage, res: http.ServerResponse) => {
@@ -132,7 +133,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
const _orings = allowedOrigins || [];
const host = dns.hostName;
if (
_orings.some((item) => {
host && _orings.some((item) => {
return host.includes(item);
})
) {
@@ -142,11 +143,9 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
let user, app;
let domainApp = false;
if (isLocalhost(dns.hostName)) {
// 本地开发环境 测试
// user = 'root';
// app = 'codeflow';
// domainApp = true;
const isDev = isLocalhost(dns.hostName);
if (isDev) {
console.debug('开发环境访问:', req.url, 'Host:', dns.hostName);
} else {
if (isIpv4OrIpv6(dns.hostName)) {
// 打印出 req.url 和错误信息
@@ -184,14 +183,9 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
const url = pathname;
if (!domainApp && noProxyUrl.includes(url)) {
if (url === '/') {
// TODO: 获取一下登陆用户如果没有登陆用户重定向到ai-chat页面
// 重定向到
// res.writeHead(302, { Location: home });
// return res.end();
rediretHome(req, res);
return;
}
// 不是域名代理且是在不代理的url当中
res.write('No proxy for this URL\n');
return res.end();
}
@@ -205,7 +199,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
res.end(robotsTxt);
return;
}
if(userPathIsBanned(_user)) {
if (userPathIsBanned(_user)) {
logger.warn(`Bad user access from IP: ${dns.ip}, Host: ${dns.hostName}, URL: ${req.url}`);
} else {
console.log('urls error', urls, 'originUrl:', url);
@@ -259,7 +253,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
let isExist = await userApp.getExist();
logger.debug('userApp', userApp, isExist);
if (userIsBanned(user) || appIsBanned(app)) {
forBadUser(req, res);
if (!isDev) forBadUser(req, res);
return createErrorPage();
}
if (!isExist) {
@@ -314,7 +308,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
if (!proxyUrl.startsWith('http')) {
return createNotFoundPage('Invalid proxy url');
}
console.log('proxyUrl', appFileUrl, proxyUrl);
console.log('proxyUrl indexFile', appFileUrl, proxyUrl);
httpProxy(req, res, {
proxyUrl,
userApp,
@@ -332,8 +326,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
const filePath = path.join(fileStore, indexFilePath);
if (!userApp.fileCheck(filePath)) {
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8', tips: 'App Cache expired, Please refresh' });
res.write(createRefreshHtml(user, app));
res.end();
res.end(createRefreshHtml(user, app));
await userApp.clearCacheData();
return;
}
@@ -384,17 +377,14 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
headers.set('Content-Type', contentType);
headers.set('Cache-Control', isHTML ? 'no-cache' : 'public, max-age=3600'); // 设置缓存时间为 1 小时
headers.set('ETag', eTag);
res?.setHeaders?.(headers);
res.writeHead(200, Object.fromEntries(headers));
if (isHTML) {
const newHtml = await getTextFromStreamAndAddStat(fs.createReadStream(filePath));
resContent = newHtml.html;
headers.set('Content-Length', newHtml.contentLength.toString());
res.writeHead(200);
res.end(resContent);
} else {
res.writeHead(200);
const readStream = fs.createReadStream(filePath);
readStream.pipe(res);
pipeFileStream(filePath, res);
}
return;
}
@@ -402,3 +392,4 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
console.error('getFile error', error);
}
};