diff --git a/assistant/src/app.ts b/assistant/src/app.ts index 4994a21..7ff5886 100644 --- a/assistant/src/app.ts +++ b/assistant/src/app.ts @@ -28,7 +28,7 @@ export const runtime = useContextKey('runtime', () => { }; }); -export const app = useContextKey('app', () => { +export const app: App = useContextKey('app', () => { const init = isInit; if (init) { const config = assistantConfig.getConfig(); diff --git a/assistant/src/module/assistant/query.ts b/assistant/src/module/assistant/query.ts new file mode 100644 index 0000000..e69de29 diff --git a/assistant/src/routes/ai/index.ts b/assistant/src/routes/ai/index.ts index 6445258..ce2996f 100644 --- a/assistant/src/routes/ai/index.ts +++ b/assistant/src/routes/ai/index.ts @@ -11,7 +11,10 @@ app path: 'ai', key: 'chat', description: '与 AI 进行对话, 调用 GPT 的AI 服务,生成结果,并返回。', - middleware: ['auth'], + middleware: ['admin-auth'], + metadata: { + admin: true, + } }) .define(async (ctx) => { const { messages = [], username, group, question, chatOpts = {} } = ctx.query; diff --git a/assistant/src/routes/index.ts b/assistant/src/routes/index.ts index 20e583c..0bb76ff 100644 --- a/assistant/src/routes/index.ts +++ b/assistant/src/routes/index.ts @@ -1,43 +1,53 @@ -import { Query } from '@kevisual/query/query'; import { app, assistantConfig } from '../app.ts'; import './config/index.ts'; import './shop-install/index.ts'; import './ai/index.ts'; import './light-code/index.ts'; +import './user/index.ts'; import os from 'node:os'; - +import { authCache } from '@/module/cache/auth.ts'; +export const getTokenUser = async (ctx: any) => { + const query = assistantConfig.query + const res = await query.post({ + path: 'user', + key: 'me', + token: ctx.state.token, + }); + if (res.code !== 200) { + return ctx.throw(401, 'not login'); + } + const tokenUser = res.data || {}; + return tokenUser; +} 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 { auth = {} } = config; 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'); - } + + if (!token) { + return ctx.throw(401, 'not login'); + } + // 鉴权代理 + let tokenUser = await authCache.get(token); + if (!tokenUser) { + tokenUser = await getTokenUser(ctx); + authCache.set(token, tokenUser); + } + ctx.state = { + ...ctx.state, + token, + tokenUser, + }; + const { username } = tokenUser; + if (!auth.username) { + // 初始管理员账号 + auth.username = username; + assistantConfig.setConfig({ auth }); + } + if (isAdmin) { + if (auth.username && auth.username !== username) { + return ctx.throw(403, 'not admin user'); } } }; @@ -45,8 +55,7 @@ app .route({ path: 'auth', id: 'auth', - isDebug: true, - description: '获取当前登录用户信息', + description: '获取当前登录用户信息, 第一个登录的用户为管理员用户', }) .define(async (ctx) => { await checkAuth(ctx); @@ -56,6 +65,7 @@ app .route({ path: 'admin-auth', id: 'admin-auth', + description: '管理员鉴权, 获取用户信息,并验证是否为管理员。', }) .define(async (ctx) => { await checkAuth(ctx, true); @@ -66,6 +76,7 @@ app .route({ path: 'client', key: 'version', + description: '获取客户端版本号', }) .define(async (ctx) => { ctx.body = 'v1.0.0'; @@ -76,6 +87,7 @@ app .route({ path: 'client', key: 'time', + description: '获取当前时间', }) .define(async (ctx) => { ctx.body = { diff --git a/assistant/src/routes/light-code/index.ts b/assistant/src/routes/light-code/index.ts index 689e4a1..a769548 100644 --- a/assistant/src/routes/light-code/index.ts +++ b/assistant/src/routes/light-code/index.ts @@ -1 +1,3 @@ -import './call.ts' \ No newline at end of file +import './call.ts' + +import './upload.ts' \ No newline at end of file diff --git a/assistant/src/routes/light-code/upload.ts b/assistant/src/routes/light-code/upload.ts new file mode 100644 index 0000000..0ae634f --- /dev/null +++ b/assistant/src/routes/light-code/upload.ts @@ -0,0 +1,10 @@ +import { app } from '../../app.ts'; + +app.route({ + path: 'light-code', + key: 'upload', + middleware: ['auth'], + description: '上传轻代码应用代码', +}).define(async (ctx) => { + const files = ctx.query.files; +}).addTo(app); \ No newline at end of file diff --git a/assistant/src/routes/shop-install/index.ts b/assistant/src/routes/shop-install/index.ts index 5c7fd87..fa57b4e 100644 --- a/assistant/src/routes/shop-install/index.ts +++ b/assistant/src/routes/shop-install/index.ts @@ -5,7 +5,10 @@ import { shopDefine } from './define.ts'; app .route({ ...shopDefine.get('getRegistry'), - middleware: ['auth'], + middleware: ['admin-auth'], + metadata: { + admin: true, + } }) .define(async (ctx) => { const registry = assistantConfig.getRegistry(); @@ -17,7 +20,10 @@ app app .route({ ...shopDefine.get('listInstalled'), - middleware: ['auth'], + middleware: ['admin-auth'], + metadata: { + admin: true, + } }) .define(async (ctx) => { const manager = new AssistantApp(assistantConfig); @@ -30,7 +36,10 @@ app app .route({ ...shopDefine.get('install'), - middleware: ['auth'], + middleware: ['admin-auth'], + metadata: { + admin: true, + } }) .define(async (ctx) => { // https://localhost:51015/client/router?path=shop&key=install @@ -52,7 +61,10 @@ app app .route({ ...shopDefine.get('uninstall'), - middleware: ['auth'], + middleware: ['admin-auth'], + metadata: { + admin: true, + } }) .define(async (ctx) => { // https://localhost:51015/client/router?path=shop&key=uninstall diff --git a/assistant/src/routes/user/index.ts b/assistant/src/routes/user/index.ts new file mode 100644 index 0000000..430f71f --- /dev/null +++ b/assistant/src/routes/user/index.ts @@ -0,0 +1,34 @@ +import { app, assistantConfig } from '../../app.ts'; + +app.route({ + path: 'admin', + key: 'login', + description: '管理员用户登录', +}).define(async (ctx) => { + const { username, password } = ctx.query; + const query = assistantConfig.query; + const auth = assistantConfig.getConfig().auth; + const res = await query.post({ + path: 'user', + key: 'login', + data: { + username, + password, + }, + }) + if (res.code !== 200) { + return ctx.throw(401, 'login failed'); + } + const loginUser = res.data.username; + if (auth.username && loginUser !== auth.username) { + return ctx.throw(403, 'login user is not admin user'); + } + if (!auth.username) { + // 初始管理员账号 + auth.username = 'admin'; + assistantConfig.setConfig({ auth }); + } + // 保存配置 + + ctx.body = res.data; +}).addTo(app); \ No newline at end of file diff --git a/assistant/src/services/init/index.ts b/assistant/src/services/init/index.ts index 3057f75..8c8c6c0 100644 --- a/assistant/src/services/init/index.ts +++ b/assistant/src/services/init/index.ts @@ -3,6 +3,8 @@ import path from 'node:path'; import { checkFileExists, AssistantConfig, AssistantConfigData, parseHomeArg, parseHelpArg } from '@/module/assistant/index.ts'; import { chalk } from '@/module/chalk.ts'; import { HttpsPem } from '@/module/assistant/https/sign.ts'; +import { Query } from '@kevisual/query/query'; + export { parseHomeArg, parseHelpArg }; export type AssistantInitOptions = { path?: string; @@ -13,6 +15,7 @@ export type AssistantInitOptions = { * @class AssistantInit */ export class AssistantInit extends AssistantConfig { + #query: Query constructor(opts?: AssistantInitOptions) { const configDir = opts?.path || process.cwd(); super({ @@ -39,6 +42,17 @@ export class AssistantInit extends AssistantConfig { this.createOtherConfig(); this.initPnpm(); } + get query() { + if (!this.#query) { + this.setQuery(); + } + return this.#query; + } + setQuery(query?: Query) { + this.#query = query || new Query({ + url: `${this.getConfig()?.pageApi || 'https://kevisual.cn'}/api/router`, + }); + } checkConfigPath() { const assistantPath = path.join(this.configDir, 'assistant-app', 'assistant-config.json'); return checkFileExists(assistantPath); diff --git a/src/module/query.ts b/src/module/query.ts index 52b1baa..248b883 100644 --- a/src/module/query.ts +++ b/src/module/query.ts @@ -5,18 +5,6 @@ const config = getConfig(); export const baseURL = config?.baseURL || 'https://kevisual.cn'; export { storage }; export const getBaseURL = () => { - if (typeof config?.dev === 'undefined') { - return baseURL; - } - if (typeof config?.dev === 'string') { - if (config?.dev === 'true') { - return 'http://localhost:4002'; - } - return baseURL; - } - if (config?.dev === true) { - return 'http://localhost:4002'; - } return baseURL; }; export const query = new Query({