temp
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
POSTGRES_HOST=localhost
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=
|
||||
POSTGRES_DB=postgres
|
||||
DATABASE_URL=postgresql://postgres:password@localhost:5432/postgres
|
||||
KEVISUAL_ENV=development
|
||||
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
|
||||
16
package.json
16
package.json
@@ -49,7 +49,7 @@
|
||||
"@types/busboy": "^1.5.4",
|
||||
"@types/send": "^1.2.1",
|
||||
"@types/ws": "^8.18.1",
|
||||
"bullmq": "^5.71.1",
|
||||
"bullmq": "^5.73.0",
|
||||
"busboy": "^1.6.0",
|
||||
"drizzle-kit": "^0.31.10",
|
||||
"drizzle-orm": "^0.45.2",
|
||||
@@ -59,10 +59,10 @@
|
||||
"xml2js": "^0.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ai-sdk/openai-compatible": "^2.0.37",
|
||||
"@aws-sdk/client-s3": "^3.1019.0",
|
||||
"@ai-sdk/openai-compatible": "^2.0.38",
|
||||
"@aws-sdk/client-s3": "^3.1024.0",
|
||||
"@kevisual/api": "^0.0.65",
|
||||
"@kevisual/cnb": "^0.0.62",
|
||||
"@kevisual/cnb": "^0.0.65",
|
||||
"@kevisual/context": "^0.0.8",
|
||||
"@kevisual/local-app-manager": "0.1.32",
|
||||
"@kevisual/logger": "^0.0.4",
|
||||
@@ -75,22 +75,22 @@
|
||||
"@types/bun": "^1.3.11",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@types/node": "^25.5.0",
|
||||
"@types/node": "^25.5.2",
|
||||
"@types/pg": "^8.20.0",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/xml2js": "^0.4.14",
|
||||
"ai": "^6.0.141",
|
||||
"ai": "^6.0.146",
|
||||
"archiver": "^7.0.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.20",
|
||||
"dotenv": "^17.3.1",
|
||||
"dotenv": "^17.4.0",
|
||||
"drizzle-zod": "^0.8.3",
|
||||
"es-toolkit": "^1.45.1",
|
||||
"ioredis": "^5.10.1",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
"lunar": "^2.0.0",
|
||||
"nanoid": "^5.1.7",
|
||||
"p-queue": "^9.1.0",
|
||||
"p-queue": "^9.1.1",
|
||||
"pg": "^8.20.0",
|
||||
"pm2": "^6.0.14",
|
||||
"semver": "^7.7.4",
|
||||
|
||||
209
src/route.ts
209
src/route.ts
@@ -1,211 +1,2 @@
|
||||
import './routes/index.ts';
|
||||
import './aura/index.ts';
|
||||
import { app } from './app.ts';
|
||||
import type { App } from '@kevisual/router';
|
||||
import { User } from './models/user.ts';
|
||||
import { createCookie, getSomeInfoFromReq } from './routes/user/me.ts';
|
||||
import { toJSONSchema } from '@kevisual/router';
|
||||
import { pick } from 'es-toolkit';
|
||||
/**
|
||||
* 验证上下文中的 App ID 是否与指定的 App ID 匹配
|
||||
* @param {any} ctx - 上下文对象,可能包含 appId 属性
|
||||
* @param {string} appId - 需要验证的目标 App ID
|
||||
* @returns {boolean} 如果 ctx 中包含 appId 且匹配则返回 true,否则返回 false
|
||||
* @throws {Error} 如果 ctx 中包含 appId 但不匹配,则抛出 403 错误
|
||||
*/
|
||||
const checkAppId = (ctx: any, appId: string) => {
|
||||
const _appId = ctx?.app?.appId;
|
||||
if (_appId) {
|
||||
if (_appId !== appId) {
|
||||
ctx.throw(403, 'Invalid App ID');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加auth中间件, 用于验证token
|
||||
* 添加 id: auth 必须需要user成功
|
||||
* 添加 id: auth-can 可以不需要user成功,有则赋值
|
||||
*
|
||||
* @param app
|
||||
*/
|
||||
export const addAuth = (app: App) => {
|
||||
app
|
||||
.route({
|
||||
path: 'auth',
|
||||
rid: 'auth',
|
||||
description: '验证token,必须成功, 错误返回401,正确赋值到ctx.state.tokenUser',
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const token = ctx.query.token;
|
||||
// if (checkAppId(ctx, app.appId)) {
|
||||
// ctx.state.tokenUser = {
|
||||
// username: 'default',
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// 已经有用户信息则直接返回,不需要重复验证
|
||||
if (ctx.state.tokenUser) {
|
||||
return;
|
||||
}
|
||||
if (!token) {
|
||||
ctx.throw(401, 'Token is required');
|
||||
}
|
||||
const user = await User.getOauthUser(token);
|
||||
if (!user) {
|
||||
ctx.throw(401, 'Token is invalid');
|
||||
return;
|
||||
}
|
||||
// console.log(`auth user: ${user.username} (${user.id})`);
|
||||
const someInfo = getSomeInfoFromReq(ctx);
|
||||
if (someInfo.isBrowser && !ctx.req?.cookies?.['token']) {
|
||||
createCookie({ accessToken: token }, ctx);
|
||||
}
|
||||
ctx.state.tokenUser = user;
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'auth',
|
||||
key: 'can',
|
||||
rid: 'auth-can',
|
||||
description: '验证token,可以不成功,错误不返回401,正确赋值到ctx.state.tokenUser,失败赋值null',
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
// if (checkAppId(ctx, app.appId)) {
|
||||
// ctx.state.tokenUser = {
|
||||
// username: 'default',
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// 已经有用户信息则直接返回,不需要重复验证
|
||||
if (ctx.state.tokenUser) {
|
||||
return;
|
||||
}
|
||||
if (ctx.query?.token) {
|
||||
const token = ctx.query.token;
|
||||
const user = await User.getOauthUser(token);
|
||||
if (token) {
|
||||
ctx.state.tokenUser = user;
|
||||
const someInfo = getSomeInfoFromReq(ctx);
|
||||
if (someInfo.isBrowser && !ctx.req?.cookies?.['token']) {
|
||||
createCookie({ accessToken: token }, ctx);
|
||||
}
|
||||
} else {
|
||||
ctx.state.tokenUser = null;
|
||||
}
|
||||
}
|
||||
})
|
||||
.addTo(app);
|
||||
};
|
||||
addAuth(app);
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'auth',
|
||||
key: 'admin',
|
||||
rid: 'auth-admin',
|
||||
isDebug: true,
|
||||
middleware: ['auth'],
|
||||
description: '验证token,必须是admin用户, 错误返回403,正确赋值到ctx.state.tokenAdmin',
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
// if (checkAppId(ctx, app.appId)) {
|
||||
// ctx.state.tokenUser = {
|
||||
// username: 'default',
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
const tokenUser = ctx.state.tokenUser;
|
||||
if (!tokenUser) {
|
||||
ctx.throw(401, 'No User For authorized');
|
||||
}
|
||||
console.log('auth-admin tokenUser', ctx.state);
|
||||
if (typeof ctx.state.isAdmin !== 'undefined' && ctx.state.isAdmin === true) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const user = await User.findOne({
|
||||
id: tokenUser.id,
|
||||
});
|
||||
if (!user) {
|
||||
ctx.throw(404, 'user not found');
|
||||
}
|
||||
user.setTokenUser(tokenUser);
|
||||
const orgs = await user.getOrgs();
|
||||
if (orgs.includes('admin')) {
|
||||
ctx.body = 'admin';
|
||||
} else {
|
||||
ctx.throw(403, 'forbidden');
|
||||
}
|
||||
ctx.state.isAdmin = true;
|
||||
} catch (e) {
|
||||
console.error(`auth-admin error`, e);
|
||||
console.error('tokenUser', tokenUser?.id, tokenUser?.username, tokenUser?.uid);
|
||||
ctx.throw(500, e.message);
|
||||
}
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'auth-check',
|
||||
key: 'admin',
|
||||
rid: 'check-auth-admin',
|
||||
middleware: ['auth'],
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const tokenUser = ctx.state.tokenUser;
|
||||
if (!tokenUser) {
|
||||
ctx.throw(401, 'No User For authorized');
|
||||
}
|
||||
if (typeof ctx.state.isAdmin !== 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await User.findOne({
|
||||
id: tokenUser.id,
|
||||
});
|
||||
if (!user) {
|
||||
ctx.throw(404, 'user not found');
|
||||
}
|
||||
user.setTokenUser(tokenUser);
|
||||
const orgs = await user.getOrgs();
|
||||
if (orgs.includes('admin')) {
|
||||
ctx.body = 'admin';
|
||||
ctx.state.isAdmin = true;
|
||||
ctx.state.tokenAdmin = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
orgs,
|
||||
};
|
||||
return;
|
||||
} else {
|
||||
ctx.state.isAdmin = false;
|
||||
}
|
||||
ctx.body = 'not admin';
|
||||
} catch (e) {
|
||||
console.error(`auth-admin error`, e);
|
||||
console.error('tokenUser', tokenUser?.id, tokenUser?.username, tokenUser?.uid);
|
||||
ctx.throw(500, e.message);
|
||||
}
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app.createRouteList({
|
||||
middleware: ['auth-can']
|
||||
})
|
||||
|
||||
app.route({
|
||||
path: 'system',
|
||||
key: 'version'
|
||||
}).define(async (ctx) => {
|
||||
ctx.body = {
|
||||
version: '0.0.1',
|
||||
name: 'KeVisual Backend System',
|
||||
}
|
||||
}).addTo(app);
|
||||
197
src/routes/auth/index.ts
Normal file
197
src/routes/auth/index.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
import { app } from '@/app.ts';
|
||||
import type { App } from '@kevisual/router';
|
||||
import { User } from '@/models/user.ts';
|
||||
import { createCookie, getSomeInfoFromReq } from '@/routes/user/me.ts';
|
||||
/**
|
||||
* 验证上下文中的 App ID 是否与指定的 App ID 匹配
|
||||
* @param {any} ctx - 上下文对象,可能包含 appId 属性
|
||||
* @param {string} appId - 需要验证的目标 App ID
|
||||
* @returns {boolean} 如果 ctx 中包含 appId 且匹配则返回 true,否则返回 false
|
||||
* @throws {Error} 如果 ctx 中包含 appId 但不匹配,则抛出 403 错误
|
||||
*/
|
||||
const checkAppId = (ctx: any, appId: string) => {
|
||||
const _appId = ctx?.app?.appId;
|
||||
if (_appId) {
|
||||
if (_appId !== appId) {
|
||||
ctx.throw(403, 'Invalid App ID');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加auth中间件, 用于验证token
|
||||
* 添加 id: auth 必须需要user成功
|
||||
* 添加 id: auth-can 可以不需要user成功,有则赋值
|
||||
*
|
||||
* @param app
|
||||
*/
|
||||
export const addAuth = (app: App) => {
|
||||
app
|
||||
.route({
|
||||
path: 'auth',
|
||||
rid: 'auth',
|
||||
description: '验证token,必须成功, 错误返回401,正确赋值到ctx.state.tokenUser',
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const token = ctx.query.token;
|
||||
// if (checkAppId(ctx, app.appId)) {
|
||||
// ctx.state.tokenUser = {
|
||||
// username: 'default',
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// 已经有用户信息则直接返回,不需要重复验证
|
||||
if (ctx.state.tokenUser) {
|
||||
return;
|
||||
}
|
||||
if (!token) {
|
||||
ctx.throw(401, 'Token is required');
|
||||
}
|
||||
const user = await User.getOauthUser(token);
|
||||
if (!user) {
|
||||
ctx.throw(401, 'Token is invalid');
|
||||
return;
|
||||
}
|
||||
// console.log(`auth user: ${user.username} (${user.id})`);
|
||||
const someInfo = getSomeInfoFromReq(ctx);
|
||||
if (someInfo.isBrowser && !ctx.req?.cookies?.['token']) {
|
||||
createCookie({ accessToken: token }, ctx);
|
||||
}
|
||||
ctx.state.tokenUser = user;
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'auth',
|
||||
key: 'can',
|
||||
rid: 'auth-can',
|
||||
description: '验证token,可以不成功,错误不返回401,正确赋值到ctx.state.tokenUser,失败赋值null',
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
// if (checkAppId(ctx, app.appId)) {
|
||||
// ctx.state.tokenUser = {
|
||||
// username: 'default',
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// 已经有用户信息则直接返回,不需要重复验证
|
||||
if (ctx.state.tokenUser) {
|
||||
return;
|
||||
}
|
||||
if (ctx.query?.token) {
|
||||
const token = ctx.query.token;
|
||||
const user = await User.getOauthUser(token);
|
||||
if (token) {
|
||||
ctx.state.tokenUser = user;
|
||||
const someInfo = getSomeInfoFromReq(ctx);
|
||||
if (someInfo.isBrowser && !ctx.req?.cookies?.['token']) {
|
||||
createCookie({ accessToken: token }, ctx);
|
||||
}
|
||||
} else {
|
||||
ctx.state.tokenUser = null;
|
||||
}
|
||||
}
|
||||
})
|
||||
.addTo(app);
|
||||
};
|
||||
addAuth(app);
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'auth',
|
||||
key: 'admin',
|
||||
rid: 'auth-admin',
|
||||
isDebug: true,
|
||||
middleware: ['auth'],
|
||||
description: '验证token,必须是admin用户, 错误返回403,正确赋值到ctx.state.tokenAdmin',
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
// if (checkAppId(ctx, app.appId)) {
|
||||
// ctx.state.tokenUser = {
|
||||
// username: 'default',
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
const tokenUser = ctx.state.tokenUser;
|
||||
if (!tokenUser) {
|
||||
ctx.throw(401, 'No User For authorized');
|
||||
}
|
||||
console.log('auth-admin tokenUser', ctx.state);
|
||||
if (typeof ctx.state.isAdmin !== 'undefined' && ctx.state.isAdmin === true) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const user = await User.findOne({
|
||||
id: tokenUser.id,
|
||||
});
|
||||
if (!user) {
|
||||
ctx.throw(404, 'user not found');
|
||||
}
|
||||
user.setTokenUser(tokenUser);
|
||||
const orgs = await user.getOrgs();
|
||||
if (orgs.includes('admin')) {
|
||||
ctx.body = 'admin';
|
||||
} else {
|
||||
ctx.throw(403, 'forbidden');
|
||||
}
|
||||
ctx.state.isAdmin = true;
|
||||
} catch (e) {
|
||||
console.error(`auth-admin error`, e);
|
||||
console.error('tokenUser', tokenUser?.id, tokenUser?.username, tokenUser?.uid);
|
||||
ctx.throw(500, e.message);
|
||||
}
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'auth-check',
|
||||
key: 'admin',
|
||||
rid: 'check-auth-admin',
|
||||
middleware: ['auth'],
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const tokenUser = ctx.state.tokenUser;
|
||||
if (!tokenUser) {
|
||||
ctx.throw(401, 'No User For authorized');
|
||||
}
|
||||
if (typeof ctx.state.isAdmin !== 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await User.findOne({
|
||||
id: tokenUser.id,
|
||||
});
|
||||
if (!user) {
|
||||
ctx.throw(404, 'user not found');
|
||||
}
|
||||
user.setTokenUser(tokenUser);
|
||||
const orgs = await user.getOrgs();
|
||||
if (orgs.includes('admin')) {
|
||||
ctx.body = 'admin';
|
||||
ctx.state.isAdmin = true;
|
||||
ctx.state.tokenAdmin = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
orgs,
|
||||
};
|
||||
return;
|
||||
} else {
|
||||
ctx.state.isAdmin = false;
|
||||
}
|
||||
ctx.body = 'not admin';
|
||||
} catch (e) {
|
||||
console.error(`auth-admin error`, e);
|
||||
console.error('tokenUser', tokenUser?.id, tokenUser?.username, tokenUser?.uid);
|
||||
ctx.throw(500, e.message);
|
||||
}
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app.createRouteList({
|
||||
middleware: ['auth-can']
|
||||
})
|
||||
@@ -25,3 +25,7 @@ import './flowme/index.ts'
|
||||
import './n5-link/index.ts'
|
||||
|
||||
import './flowme-life/index.ts'
|
||||
|
||||
import './auth/index.ts';
|
||||
|
||||
import './system/index.ts';
|
||||
11
src/routes/system/index.ts
Normal file
11
src/routes/system/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { app } from '@/app.ts';
|
||||
|
||||
app.route({
|
||||
path: 'system',
|
||||
key: 'version'
|
||||
}).define(async (ctx) => {
|
||||
ctx.body = {
|
||||
version: '0.0.1',
|
||||
name: 'KeVisual Backend System',
|
||||
}
|
||||
}).addTo(app);
|
||||
@@ -7,7 +7,7 @@ const config = useConfig();
|
||||
export const showMore = (res: any) => {
|
||||
return util.inspect(res, { depth: 6, colors: true });
|
||||
}
|
||||
const token = 'st_r3u38c0jbhoc412ovzeeuaucygt6w5qg';
|
||||
const token = '';
|
||||
export const query = new Query({
|
||||
url: 'http://localhost:4005/api/router',
|
||||
});
|
||||
@@ -15,7 +15,6 @@ const loginRes = await query.post({
|
||||
path: 'user',
|
||||
key: 'login',
|
||||
username: 'root',
|
||||
password: config.KEVISUAL_PASSWORD || '',
|
||||
});
|
||||
console.log('login:', showMore(loginRes));
|
||||
query.beforeRequest = async (options) => {
|
||||
|
||||
Reference in New Issue
Block a user