This commit is contained in:
2025-11-18 01:30:57 +08:00
parent 388705b646
commit 6d32fedfb0
10 changed files with 126 additions and 51 deletions

View File

@@ -28,7 +28,7 @@ export const runtime = useContextKey('runtime', () => {
}; };
}); });
export const app = useContextKey('app', () => { export const app: App = useContextKey<App>('app', () => {
const init = isInit; const init = isInit;
if (init) { if (init) {
const config = assistantConfig.getConfig(); const config = assistantConfig.getConfig();

View File

View File

@@ -11,7 +11,10 @@ app
path: 'ai', path: 'ai',
key: 'chat', key: 'chat',
description: '与 AI 进行对话, 调用 GPT 的AI 服务,生成结果,并返回。', description: '与 AI 进行对话, 调用 GPT 的AI 服务,生成结果,并返回。',
middleware: ['auth'], middleware: ['admin-auth'],
metadata: {
admin: true,
}
}) })
.define(async (ctx) => { .define(async (ctx) => {
const { messages = [], username, group, question, chatOpts = {} } = ctx.query; const { messages = [], username, group, question, chatOpts = {} } = ctx.query;

View File

@@ -1,43 +1,53 @@
import { Query } from '@kevisual/query/query';
import { app, assistantConfig } from '../app.ts'; import { app, assistantConfig } from '../app.ts';
import './config/index.ts'; import './config/index.ts';
import './shop-install/index.ts'; import './shop-install/index.ts';
import './ai/index.ts'; import './ai/index.ts';
import './light-code/index.ts'; import './light-code/index.ts';
import './user/index.ts';
import os from 'node:os'; 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 checkAuth = async (ctx: any, isAdmin = false) => {
const config = assistantConfig.getConfig(); const config = assistantConfig.getConfig();
const { auth } = config; const { auth = {} } = config;
const host = config.pageApi || config.registry || 'https://kevisual.cn';
const url = new URL('/api/router', host);
const token = ctx.query.token; const token = ctx.query.token;
if (auth && auth.type !== 'public') {
if (!token) { if (!token) {
return ctx.throw(401, 'not login'); return ctx.throw(401, 'not login');
} }
url.searchParams.set('token', token); // 鉴权代理
// 鉴权代理 let tokenUser = await authCache.get(token);
// TODO: if (!tokenUser) {
const query = new Query({ url: url.toString() }); tokenUser = await getTokenUser(ctx);
const res = await query.post({ authCache.set(token, tokenUser);
path: 'user', }
key: 'me', ctx.state = {
}); ...ctx.state,
if (res.code !== 200) { token,
return ctx.throw(401, 'not login'); tokenUser,
} };
const tokenUser = res.data || {}; const { username } = tokenUser;
ctx.state = { if (!auth.username) {
...ctx.state, // 初始管理员账号
tokenUser, auth.username = username;
}; assistantConfig.setConfig({ auth });
const { username } = tokenUser; }
if (isAdmin) { if (isAdmin) {
if (auth.username && auth.username !== username) { if (auth.username && auth.username !== username) {
return ctx.throw(403, 'not admin user'); return ctx.throw(403, 'not admin user');
}
} }
} }
}; };
@@ -45,8 +55,7 @@ app
.route({ .route({
path: 'auth', path: 'auth',
id: 'auth', id: 'auth',
isDebug: true, description: '获取当前登录用户信息, 第一个登录的用户为管理员用户',
description: '获取当前登录用户信息',
}) })
.define(async (ctx) => { .define(async (ctx) => {
await checkAuth(ctx); await checkAuth(ctx);
@@ -56,6 +65,7 @@ app
.route({ .route({
path: 'admin-auth', path: 'admin-auth',
id: 'admin-auth', id: 'admin-auth',
description: '管理员鉴权, 获取用户信息,并验证是否为管理员。',
}) })
.define(async (ctx) => { .define(async (ctx) => {
await checkAuth(ctx, true); await checkAuth(ctx, true);
@@ -66,6 +76,7 @@ app
.route({ .route({
path: 'client', path: 'client',
key: 'version', key: 'version',
description: '获取客户端版本号',
}) })
.define(async (ctx) => { .define(async (ctx) => {
ctx.body = 'v1.0.0'; ctx.body = 'v1.0.0';
@@ -76,6 +87,7 @@ app
.route({ .route({
path: 'client', path: 'client',
key: 'time', key: 'time',
description: '获取当前时间',
}) })
.define(async (ctx) => { .define(async (ctx) => {
ctx.body = { ctx.body = {

View File

@@ -1 +1,3 @@
import './call.ts' import './call.ts'
import './upload.ts'

View File

@@ -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);

View File

@@ -5,7 +5,10 @@ import { shopDefine } from './define.ts';
app app
.route({ .route({
...shopDefine.get('getRegistry'), ...shopDefine.get('getRegistry'),
middleware: ['auth'], middleware: ['admin-auth'],
metadata: {
admin: true,
}
}) })
.define(async (ctx) => { .define(async (ctx) => {
const registry = assistantConfig.getRegistry(); const registry = assistantConfig.getRegistry();
@@ -17,7 +20,10 @@ app
app app
.route({ .route({
...shopDefine.get('listInstalled'), ...shopDefine.get('listInstalled'),
middleware: ['auth'], middleware: ['admin-auth'],
metadata: {
admin: true,
}
}) })
.define(async (ctx) => { .define(async (ctx) => {
const manager = new AssistantApp(assistantConfig); const manager = new AssistantApp(assistantConfig);
@@ -30,7 +36,10 @@ app
app app
.route({ .route({
...shopDefine.get('install'), ...shopDefine.get('install'),
middleware: ['auth'], middleware: ['admin-auth'],
metadata: {
admin: true,
}
}) })
.define(async (ctx) => { .define(async (ctx) => {
// https://localhost:51015/client/router?path=shop&key=install // https://localhost:51015/client/router?path=shop&key=install
@@ -52,7 +61,10 @@ app
app app
.route({ .route({
...shopDefine.get('uninstall'), ...shopDefine.get('uninstall'),
middleware: ['auth'], middleware: ['admin-auth'],
metadata: {
admin: true,
}
}) })
.define(async (ctx) => { .define(async (ctx) => {
// https://localhost:51015/client/router?path=shop&key=uninstall // https://localhost:51015/client/router?path=shop&key=uninstall

View File

@@ -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);

View File

@@ -3,6 +3,8 @@ import path from 'node:path';
import { checkFileExists, AssistantConfig, AssistantConfigData, parseHomeArg, parseHelpArg } from '@/module/assistant/index.ts'; import { checkFileExists, AssistantConfig, AssistantConfigData, parseHomeArg, parseHelpArg } from '@/module/assistant/index.ts';
import { chalk } from '@/module/chalk.ts'; import { chalk } from '@/module/chalk.ts';
import { HttpsPem } from '@/module/assistant/https/sign.ts'; import { HttpsPem } from '@/module/assistant/https/sign.ts';
import { Query } from '@kevisual/query/query';
export { parseHomeArg, parseHelpArg }; export { parseHomeArg, parseHelpArg };
export type AssistantInitOptions = { export type AssistantInitOptions = {
path?: string; path?: string;
@@ -13,6 +15,7 @@ export type AssistantInitOptions = {
* @class AssistantInit * @class AssistantInit
*/ */
export class AssistantInit extends AssistantConfig { export class AssistantInit extends AssistantConfig {
#query: Query
constructor(opts?: AssistantInitOptions) { constructor(opts?: AssistantInitOptions) {
const configDir = opts?.path || process.cwd(); const configDir = opts?.path || process.cwd();
super({ super({
@@ -39,6 +42,17 @@ export class AssistantInit extends AssistantConfig {
this.createOtherConfig(); this.createOtherConfig();
this.initPnpm(); 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() { checkConfigPath() {
const assistantPath = path.join(this.configDir, 'assistant-app', 'assistant-config.json'); const assistantPath = path.join(this.configDir, 'assistant-app', 'assistant-config.json');
return checkFileExists(assistantPath); return checkFileExists(assistantPath);

View File

@@ -5,18 +5,6 @@ const config = getConfig();
export const baseURL = config?.baseURL || 'https://kevisual.cn'; export const baseURL = config?.baseURL || 'https://kevisual.cn';
export { storage }; export { storage };
export const getBaseURL = () => { 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; return baseURL;
}; };
export const query = new Query({ export const query = new Query({