From 239ba3ad106b2f9c2efb09d58042b17aca1662a6 Mon Sep 17 00:00:00 2001 From: abearxiong Date: Fri, 30 May 2025 18:16:36 +0800 Subject: [PATCH] fix --- assistant/src/app.ts | 7 +- .../src/module/assistant/config/index.ts | 7 ++ assistant/src/module/assistant/https/sign.ts | 24 ++++++ assistant/src/module/reload-server.ts | 25 ++++++ assistant/src/routes/config/index.ts | 10 +-- assistant/src/routes/index.ts | 76 ++++++++++++------- package.json | 3 +- 7 files changed, 115 insertions(+), 37 deletions(-) create mode 100644 assistant/src/module/reload-server.ts diff --git a/assistant/src/app.ts b/assistant/src/app.ts index 9c01c27..4b00d55 100644 --- a/assistant/src/app.ts +++ b/assistant/src/app.ts @@ -8,13 +8,18 @@ import { useContextKey } from '@kevisual/use-config/context'; const manualParse = parseHomeArg(HomeConfigDir); const _configDir = manualParse.configDir; export const configDir = AssistantInit.detectConfigDir(_configDir); +const isInit = manualParse?.options?.help ? false : true; export const assistantConfig = new AssistantInit({ path: configDir, - init: manualParse?.options?.help ? false : true, + init: isInit, }); const httpsPem = new HttpsPem(assistantConfig); export const app = useContextKey('app', () => { + const init = isInit; + if (init) { + // const config = assistantConfig.getConfig(); + } return new App({ serverOptions: { path: '/client/router', diff --git a/assistant/src/module/assistant/config/index.ts b/assistant/src/module/assistant/config/index.ts index f7fac88..c939dcd 100644 --- a/assistant/src/module/assistant/config/index.ts +++ b/assistant/src/module/assistant/config/index.ts @@ -62,6 +62,8 @@ export type ReturnInitConfigType = ReturnType; type AuthPermission = { type?: 'auth-proxy' | 'public' | 'private' | 'project'; + username?: string; // 用户名 + admin?: Omit; }; export type AssistantConfigData = { pageApi?: string; // https://kevisual.cn @@ -99,6 +101,11 @@ export type AssistantConfigData = { [key: string]: string; }; auth?: AuthPermission; + https?: { + type?: 'https' | 'http'; + keyPath?: string; // 证书私钥路径 + certPath?: string; // 证书路径 + }; }; let assistantConfig: AssistantConfigData; type AssistantConfigOptions = { diff --git a/assistant/src/module/assistant/https/sign.ts b/assistant/src/module/assistant/https/sign.ts index 28ac854..0cf3670 100644 --- a/assistant/src/module/assistant/https/sign.ts +++ b/assistant/src/module/assistant/https/sign.ts @@ -21,6 +21,30 @@ export class HttpsPem { cert: string; constructor(assistantConfig: AssistantConfig) { this.assistantConfig = assistantConfig; + this.#initKeyCert(); + } + #initKeyCert() { + this.assistantConfig.checkMounted(); + const config = this.assistantConfig.getConfig(); + if (config.https) { + const httpsType = config.https?.type || 'https'; + if (httpsType !== 'https') { + console.log(chalk.yellow('当前配置文件 https.type 不是 https, 不使用证书')); + return; + } + if (config.https.keyPath) { + const keyPath = config.https.keyPath; + const certPath = config.https.certPath; + if (checkFileExists(keyPath) && checkFileExists(certPath)) { + this.key = fs.readFileSync(keyPath, 'utf-8'); + this.cert = fs.readFileSync(certPath, 'utf-8'); + console.log(chalk.green('使用配置文件 https.keyPath 和 https.certPath 的证书'), keyPath, certPath); + return; + } else { + console.log(chalk.red('证书路径不存在,请检查配置文件 https.keyPath 和 https.certPath 是否正确')); + } + } + } const { key, cert } = this.getCert(); this.key = key; this.cert = cert; diff --git a/assistant/src/module/reload-server.ts b/assistant/src/module/reload-server.ts new file mode 100644 index 0000000..c0cebb6 --- /dev/null +++ b/assistant/src/module/reload-server.ts @@ -0,0 +1,25 @@ +import pm2 from 'pm2'; +import { logger } from './logger.js'; + +export async function reload() { + return new Promise((resolve, reject) => { + pm2.connect((err) => { + if (err) { + logger.error('PM2 connection error:', err); + return reject(err); + } + + pm2.reload('assistant-server', (err) => { + if (err) { + logger.error('PM2 reload error:', err); + pm2.disconnect(); + return reject(err); + } + + logger.info('PM2 server reloaded successfully'); + pm2.disconnect(); + resolve(); + }); + }); + }); +} diff --git a/assistant/src/routes/config/index.ts b/assistant/src/routes/config/index.ts index de147fb..c4d478b 100644 --- a/assistant/src/routes/config/index.ts +++ b/assistant/src/routes/config/index.ts @@ -1,12 +1,11 @@ import { app, assistantConfig } from '@/app.ts'; -// import { getCacheAssistantConfig, setConfig } from '@/modules/config/index.ts'; -// import { reload } from '@/modules/parent-msg.ts'; +import { reload } from '../../module/reload-server.ts'; app .route({ path: 'config', description: '获取配置', - middleware: ['auth'], + middleware: ['admin-auth'], }) .define(async (ctx) => { ctx.body = assistantConfig.getCacheAssistantConfig(); @@ -18,12 +17,11 @@ app path: 'config', key: 'set', description: '设置配置', - middleware: ['auth'], + middleware: ['admin-auth'], }) .define(async (ctx) => { const { data } = ctx.query; - // reload(); - ctx.body = assistantConfig.setConfig(data); + reload(); }) .addTo(app); diff --git a/assistant/src/routes/index.ts b/assistant/src/routes/index.ts index 14d3a85..9dff62c 100644 --- a/assistant/src/routes/index.ts +++ b/assistant/src/routes/index.ts @@ -1,4 +1,4 @@ -import { Query } from '@kevisual/query'; +import { Query } from '@kevisual/query/query'; import { app, assistantConfig } from '../app.ts'; import './config/index.ts'; import './shop-install/index.ts'; @@ -6,40 +6,58 @@ import './ai/index.ts'; import os from 'node:os'; +const checkAuth = async (ctx: any, isAdmin = false) => { + const config = assistantConfig.getConfig(); + const { auth } = config; + const host = config.pageApi || config.registry || 'https://kevisual.cn'; + const url = new URL('/api/router', host); + const token = ctx.query.token; + if (auth && auth.type !== 'public') { + if (!token) { + return ctx.throw(401, 'not login'); + } + url.searchParams.set('token', token); + // 鉴权代理 + // TODO: + const query = new Query({ url: url.toString() }); + const res = await query.post({ + path: 'user', + key: 'me', + }); + if (res.code !== 200) { + return ctx.throw(401, 'not login'); + } + const tokenUser = res.data || {}; + ctx.state = { + ...ctx.state, + tokenUser, + }; + const { username } = tokenUser; + if (isAdmin) { + if (auth.username && auth.username !== username) { + return ctx.throw(403, 'not admin user'); + } + } + } +}; app .route({ path: 'auth', id: 'auth', + isDebug: true, + description: '获取当前登录用户信息', }) .define(async (ctx) => { - const config = assistantConfig.getConfig(); - const { auth } = config; - const host = config.pageApi || config.registry || 'https://kevisual.cn'; - const url = new URL('/api/router', host); - const token = ctx.token; - if (auth && auth.type !== 'public') { - if (!token) { - return ctx.throw(4001, 'not login'); - } - url.searchParams.set('token', token); - // 鉴权代理 - // TODO: - const query = new Query({ baseURL: url.toString() }); - const res = await query.post({ - path: 'user', - key: 'me', - }); - console.log('res', res); - if (res.code !== 200) { - return ctx.throw(4001, 'not login'); - } - const tokenUser = res.data || {}; - ctx.state = { - ...ctx.state, - tokenUser, - }; - const { username } = tokenUser; - } + await checkAuth(ctx); + }) + .addTo(app); +app + .route({ + path: 'admin-auth', + id: 'admin-auth', + }) + .define(async (ctx) => { + await checkAuth(ctx, true); }) .addTo(app); diff --git a/package.json b/package.json index 17e0eb3..d875908 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/cli", - "version": "0.0.55-beta-3", + "version": "0.0.56-beta.4", "description": "envision command tools", "main": "dist/app.mjs", "type": "module", @@ -31,6 +31,7 @@ "dev": "NODE_ENV=development bun src/run.ts ", "dev:tsx": "tsx src/run.ts ", "build": "rimraf dist && bun run bun.config.mjs", + "pub:me": "npm publish --registry https://npm.xiongxiao.me --tag beta", "postbuild": "cd assistant && pnpm build ", "dts": "dts-bundle-generator --external-inlines=@types/jsonwebtoken src/index.ts -o dist/index.d.ts ", "build:all": "rimraf dist && bun run bun.config.mjs && bun run assistant/bun.config.mjs"