From dfc619a181448eb7b2db41c7f05a94aaccd5e226 Mon Sep 17 00:00:00 2001 From: Aritro37 <85866469+Aritro37@users.noreply.github.com> Date: Wed, 19 Mar 2025 15:26:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BC=95=E5=85=A5SUB=5FSTORE=5FBACKEND?= =?UTF-8?q?=5FMERGE=20=E5=8F=98=E9=87=8F=E5=AE=9E=E7=8E=B0=E5=89=8D?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E7=AB=AF=E5=8F=A3=E5=90=88=E5=B9=B6=E5=8F=8A?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E5=A2=9E=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增SUB_STORE_BACKEND_MERGE配置变量,支持功能整合模式: - 当设置SUB_STORE_BACKEND_MERGE为非空任意值时,后端支持同时处理API和前端资源请求 - 新增配置示例: #合并前后端端口 SUB_STORE_BACKEND_MERGE=true #设置接口安全地址 SUB_STORE_FRONTEND_BACKEND_PATH=/safe-api #设置前端文件的路径 SUB_STORE_FRONTEND_PATH=./dist #后端监听的端口 SUB_STORE_BACKEND_API_PORT=3000 #后端监听的HOST SUB_STORE_BACKEND_API_HOST="127.0.0.1" 2. 合并后支持前端在子路由界面刷新: - 原前端在subs、files、sync等页面刷新时会出现404问题,合并后修复了该问题 --- backend/package.json | 5 ++-- backend/src/restful/index.js | 55 +++++++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/backend/package.json b/backend/package.json index 6f4a5f7..94a6117 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "sub-store", - "version": "2.18.7", + "version": "2.18.8", "description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.", "main": "src/main.js", "scripts": { @@ -32,6 +32,7 @@ "cron": "^3.1.6", "dns-packet": "^5.6.1", "express": "^4.17.1", + "mime-types": "^2.1.35", "http-proxy-middleware": "^3.0.3", "ip-address": "^9.0.5", "js-base64": "^3.7.2", @@ -71,4 +72,4 @@ "prettier-plugin-sort-imports": "^1.6.1", "tinyify": "^3.0.0" } -} \ No newline at end of file +} diff --git a/backend/src/restful/index.js b/backend/src/restful/index.js index 762e9d5..47a0ec6 100644 --- a/backend/src/restful/index.js +++ b/backend/src/restful/index.js @@ -30,10 +30,12 @@ export default function serve() { } const $app = express({ substore: $, port, host }); if ($.env.isNode) { + const be_merge = eval('process.env.SUB_STORE_BACKEND_MERGE'); const be_prefix = eval('process.env.SUB_STORE_BACKEND_PREFIX'); const fe_be_path = eval('process.env.SUB_STORE_FRONTEND_BACKEND_PATH'); - if (be_prefix) { - if (!fe_be_path.startsWith('/')) { + const fe_path = eval('process.env.SUB_STORE_FRONTEND_PATH'); + if (be_prefix || be_merge) { + if(!fe_be_path.startsWith('/')){ throw new Error( 'SUB_STORE_FRONTEND_BACKEND_PATH should start with /', ); @@ -43,12 +45,50 @@ export default function serve() { ); $app.use((req, res, next) => { if (req.path.startsWith(fe_be_path)) { - const newPath = req.url.replace(fe_be_path, '') || '/'; - req.url = newPath; + req.url = req.url.replace(fe_be_path, '') || '/'; + if(be_merge && req.url.startsWith('/api/')){ + req.query['share'] = 'true'; + } next(); - } else { - res.status(403).send(); + return; } + const pathname = req._parsedUrl.pathname || '/'; + if(be_merge && req.path.startsWith('/share/') && req.query.token){ + if (req.method.toLowerCase() !== 'get'){ + res.status(405).send('Method not allowed'); + return; + } + const tokens = $.read(TOKENS_KEY) || []; + const token = tokens.find( + (t) => + t.token === req.query.token && + `/share/${t.type}/${t.name}` === pathname && + (t.exp == null || t.exp > Date.now()), + ); + if (token){ + next(); + return; + } + } + if (be_merge && fe_path && req.path.indexOf('/',1) == -1) { + if (req.path.indexOf('.') == -1){ + req.url = "/index.html" + } + const express_ = eval(`require("express")`); + const mime_ = eval(`require("mime-types")`); + const staticFileMiddleware = express_.static(fe_path, { + setHeaders: (res, path) => { + const type = mime_.contentType(path); + if (type) { + res.set('Content-Type', type); + } + } + }); + staticFileMiddleware(req, res, next); + return; + } + res.status(403).end('Forbbiden'); + return; }); } } @@ -198,7 +238,8 @@ export default function serve() { const fe_abs_path = path.resolve( fe_path || path.join(__dirname, 'frontend'), ); - if (fe_path) { + const be_merge = eval('process.env.SUB_STORE_BACKEND_MERGE'); + if (fe_path && !be_merge) { try { fs.accessSync(path.join(fe_abs_path, 'index.html')); } catch (e) {