Skip to content

Commit

Permalink
feat: 中间件
Browse files Browse the repository at this point in the history
  • Loading branch information
bietiaop committed Jan 16, 2025
1 parent b5d8d45 commit baa34b3
Show file tree
Hide file tree
Showing 19 changed files with 303 additions and 115 deletions.
9 changes: 9 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"useTabs": false,
"tabWidth": 2,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "all",
"bracketSpacing": true,
"semi": false
}
4 changes: 4 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import neostandard from 'neostandard'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'

/** 尾随逗号 */
const commaDangle = (val) => {
Expand Down Expand Up @@ -33,6 +34,9 @@ const options = neostandard({
ts: true,
ignores,
globals: ['logger'],
plugins: {
...eslintPluginPrettierRecommended.plugins,
},
}).map(commaDangle)

export default options
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
"main": "",
"type": "module",
"scripts": {
"dev:": "cd packages/core && pnpm run dev"
"dev": "cd packages/core && pnpm run dev"
},
"devDependencies": {
"@types/node": "^22.5.0",
"eslint": "^9.12.0",
"eslint-plugin-prettier": "^5.2.2",
"neostandard": "^0.11.6",
"prettier": "^3.4.2",
"sort-json": "^2.0.1",
"sort-package-json": "^2.10.0",
"tsup": "^8.3.5",
Expand All @@ -23,4 +25,4 @@
"keywords": [],
"author": "shijin",
"license": "MIT"
}
}
36 changes: 17 additions & 19 deletions packages/core/src/server/api/console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import { adapter } from '@/utils/config/adapter'
import { isLocalRequest } from '@/utils/system/ip'

import type { RequestHandler } from 'express'
import {
createBadRequestResponse,
createForbiddenResponse,
createNotFoundResponse,
createPayloadTooLargeResponse,
createServerErrorResponse,
} from '../utils/response'

/** 允许的文件类型及其对应的 Content-Type */
const ALLOWED_TYPES = {
Expand Down Expand Up @@ -36,38 +43,32 @@ const consoleRouter: RequestHandler = async (req, res) => {

url = url.split('/').pop() || ''
if (!url) {
res.status(400).json({ error: '无效的请求', message: '文件名不能为空' })
return
return createBadRequestResponse(res, '文件名不能为空')
}

/** 防止路径穿越 */
if (url.includes('..') || url.includes('~') || !url.match(/^[a-zA-Z0-9-_.]+$/)) {
res.status(403).json({ error: '禁止访问', message: '非法请求' })
return
return createForbiddenResponse(res, '非法请求')
}

const ext = path.extname(url).toLowerCase()
if (!ALLOWED_TYPES[ext as keyof typeof ALLOWED_TYPES]) {
res.status(403).json({ error: '禁止访问', message: '不支持的文件类型' })
return
return createBadRequestResponse(res, '不支持的文件类型')
}

const isLocal = await isLocalRequest(req)
if (cfg.console.isLocal) {
if (!isLocal) {
res.status(403).json({ error: '禁止访问', message: '无效的请求' })
return
return createForbiddenResponse(res, '非法请求')
}
} else {
if (!cfg.console.token) {
res.status(500).json({ error: '配置错误', message: '缺少 token 配置' })
return
return createServerErrorResponse(res, '缺少 token 配置')
}

const token = req.query.token
if (!token || token !== cfg.console.token) {
res.status(403).json({ error: '禁止访问', message: '无效的 token' })
return
return createForbiddenResponse(res, '无效的 token')
}
}

Expand All @@ -76,18 +77,15 @@ const consoleRouter: RequestHandler = async (req, res) => {
try {
/** 组合路径之后 判断一下文件是否处于 consolePath 目录下 */
if (!file.startsWith(consolePath)) {
res.status(403).json({ error: '禁止访问', message: '非法请求' })
return
return createForbiddenResponse(res, '非法请求')
}

const stats = await fs.stat(file)
if (stats.size > MAX_FILE_SIZE) {
res.status(413).json({ error: '文件过大', message: '文件大小超过限制' })
return
return createPayloadTooLargeResponse(res, '文件过大')
}
} catch {
res.status(404).json({ error: '文件不存在', message: '文件不存在' })
return
return createNotFoundResponse(res, '文件不存在')
}

const data = await fs.readFile(file)
Expand All @@ -97,7 +95,7 @@ const consoleRouter: RequestHandler = async (req, res) => {
res.send(data)
} catch (error) {
console.error('Console router error:', error)
res.status(500).json({ error: '内部错误', message: '服务器错误' })
return createServerErrorResponse(res, '服务器错误')
}
}

Expand Down
11 changes: 3 additions & 8 deletions packages/core/src/server/api/exit.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import { router } from './router'
import { auth } from '../auth'
import type { RequestHandler } from 'express'
import { createSuccessResponse } from '../utils/response'

const exitRouter: RequestHandler = async (req, res) => {
if (!auth.getAuth(req)) {
res.status(401).json({ message: '无效的token' })
return
}

const exitRouter: RequestHandler = async (_req, res) => {
logger.mark('收到退出请求,正在退出...')
res.json({ message: '退出成功' })
createSuccessResponse(res, null, '退出成功')
const { processExit } = await import('@/core/internal/process')
await processExit(0)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import { router } from './router'
import { auth } from '../../auth'
import { setYaml, getYaml } from '@/utils/config/config'
import type { RequestHandler } from 'express'
import type { FileList } from '@/types/config'
import { createSuccessResponse } from '../utils/response'

const list: FileList[] = [
'adapter',
'config',
'groups',
'pm2',
'privates',
'redis',
'render',
]
const list: FileList[] = ['adapter', 'config', 'groups', 'pm2', 'privates', 'redis', 'render']

const nameMap = {
adapter: '适配器配置',
Expand All @@ -29,19 +21,14 @@ const nameMap = {
* @param req 请求
* @param res 响应
*/
const fileRouter: RequestHandler = async (req, res) => {
if (!auth.getAuth(req)) {
res.status(401).json({ message: '无效的token' })
return
}

const fileRouter: RequestHandler = async (_req, res) => {
// 组合文件列表
const files = list.map(name => ({
const files = list.map((name) => ({
name,
title: nameMap[name],
}))

res.json(files)
createSuccessResponse(res, files)
}

/**
Expand All @@ -57,7 +44,7 @@ const setFileRouter: RequestHandler = async (req, res) => {
}

setYaml(name, data)
res.json({ message: '设置成功' })
createSuccessResponse(res, null, '设置成功')
}

/**
Expand All @@ -69,10 +56,10 @@ const getFileRouter: RequestHandler = async (req, res) => {
const { name } = req.body
if (!name || !list.includes(name)) {
res.status(400).json({ message: '参数错误' })
return
return createSuccessResponse(res, null, '获取成功')
}

res.json(getYaml(name, 'user'))
createSuccessResponse(res, getYaml(name, 'user'), '获取成功')
}

router.get('/file', fileRouter)
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/server/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import './ping'
import './root'
import './console'
import './restart'
import './web'
import './file'
import './login'
9 changes: 9 additions & 0 deletions packages/core/src/server/api/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createSuccessResponse } from '../utils/response'
import { router } from './router'
import type { RequestHandler } from 'express'

const loginRouter: RequestHandler = async (_req, res) => {
createSuccessResponse(res, null, '登录成功')
}

router.get('/login', loginRouter)
23 changes: 11 additions & 12 deletions packages/core/src/server/api/ping.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { auth } from '../auth'
import { createSuccessResponse } from '../utils/response'
import { router } from './router'
import type { RequestHandler } from 'express'

const pingRouter: RequestHandler = (req, res) => {
res.send({
ping: 'pong',
})
const pingRouter: RequestHandler = (_req, res) => {
createSuccessResponse(
res,
{
ping: 'pong',
},
'成功',
)
}

const statusRouter: RequestHandler = (req, res) => {
if (!auth.getAuth(req)) {
res.status(401).json({ message: '无效的token' })
return
}

const statusRouter: RequestHandler = (_req, res) => {
const data = {
name: 'karin',
pid: process.pid,
Expand All @@ -25,7 +24,7 @@ const statusRouter: RequestHandler = (req, res) => {
karin_runtime: process.env.RUNTIME,
}

res.status(200).json(data)
createSuccessResponse(res, data, '成功')
}

router.get('/ping', pingRouter)
Expand Down
11 changes: 3 additions & 8 deletions packages/core/src/server/api/restart.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import { router } from './router'
import { auth } from '../auth'
import { restartDirect } from '@/utils/system/restart'
import type { RequestHandler } from 'express'
import { createSuccessResponse } from '../utils/response'

const restartRouter: RequestHandler = async (req, res) => {
if (!auth.getAuth(req)) {
res.status(401).json({ message: '无效的token' })
return
}

res.status(200).end()
const restartRouter: RequestHandler = async (_req, res) => {
createSuccessResponse(res, null, '指令发送成功')
restartDirect()
}

Expand Down
8 changes: 3 additions & 5 deletions packages/core/src/server/api/root.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { app } from '../app'
import { createSuccessResponse } from '../utils/response'

app.get('/', (req, res) => {
res.send({
code: 200,
msg: '雪霁银妆素,桔高映琼枝。',
})
app.get('/', (_req, res) => {
createSuccessResponse(res, null, '雪霁银妆素,桔高映琼枝。')
})
2 changes: 0 additions & 2 deletions packages/core/src/server/api/web/index.ts

This file was deleted.

14 changes: 0 additions & 14 deletions packages/core/src/server/api/web/login.ts

This file was deleted.

8 changes: 0 additions & 8 deletions packages/core/src/server/api/web/router.ts

This file was deleted.

9 changes: 6 additions & 3 deletions packages/core/src/server/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@ import path from 'node:path'
import express from 'express'
import { createServer } from 'node:http'
import { router } from './api/router'
import { router as webRouter } from './api/web/router'
import { listeners } from '@/core/internal'

import type { Express } from 'express'
import { authMiddleware } from './middleware'

/** express 服务 */
export const app: Express = express()
/** http 服务 */
export const server = createServer(app)

/** 中间件鉴权 */
app.use(authMiddleware)

// TODO: WEB
app.use('/web', express.static(path.join(process.cwd(), 'web')))
app.use('/api/web', webRouter)
app.use('/web/*', express.static(path.join(process.cwd(), 'web')))

app.use('/v1', router)
app.use('/api/v1', router)

/**
* 监听端口
Expand Down
17 changes: 17 additions & 0 deletions packages/core/src/server/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Request, Response, NextFunction } from 'express'
import { auth } from './auth'

export const authMiddleware = async (req: Request, res: Response, next: NextFunction) => {
if (req.path.startsWith('/api')) {
if (req.path === '/api/v1/ping' || req.path.startsWith('/api/v1/console')) {
next()
return
}
if (!auth.getAuth(req)) {
res.status(401).json({ message: '无效的token' })
return
}
}

next()
}
Loading

0 comments on commit baa34b3

Please sign in to comment.