mirror of
https://github.com/cool-team-official/cool-admin-midway.git
synced 2025-12-11 16:52:49 +00:00
修复清理日志,完善本地文件上传
This commit is contained in:
parent
c8574dd5b0
commit
43b0e10f6e
@ -5,7 +5,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||||
<title>COOL-AMIND 一个很酷的后台权限管理系统</title>
|
<title>COOL-ADMIN 一个很酷的后台权限管理系统</title>
|
||||||
<meta name="keywords" content="cool-admin,后台管理系统,vue,element-ui,nodejs" />
|
<meta name="keywords" content="cool-admin,后台管理系统,vue,element-ui,nodejs" />
|
||||||
<meta name="description" content="element-ui、midway.js、mysql、redis、node.js、前后端分离、权限管理、快速开发, COOL-AMIND 一个很酷的后台权限管理系统" />
|
<meta name="description" content="element-ui、midway.js、mysql、redis、node.js、前后端分离、权限管理、快速开发, COOL-AMIND 一个很酷的后台权限管理系统" />
|
||||||
<link rel="stylesheet" href="css/welcome.css">
|
<link rel="stylesheet" href="css/welcome.css">
|
||||||
|
|||||||
@ -53,8 +53,8 @@ export class BaseSysLogService extends BaseService {
|
|||||||
}
|
}
|
||||||
const keepDay = await this.baseSysConfService.getValue('logKeep');
|
const keepDay = await this.baseSysConfService.getValue('logKeep');
|
||||||
if (keepDay) {
|
if (keepDay) {
|
||||||
const beforeDate = moment().add(-keepDay, 'days').startOf('day').toDate();
|
const beforeDate = moment().add(-keepDay, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss');
|
||||||
await this.baseSysLogEntity.delete({ createTime: LessThan(beforeDate) });
|
await this.baseSysLogEntity.createQueryBuilder().delete().where('createTime < :beforeDate', { beforeDate }).execute();
|
||||||
} else {
|
} else {
|
||||||
await this.baseSysLogEntity.clear();
|
await this.baseSysLogEntity.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,49 @@ import { pUploadPath } from '../../../../comm/path';
|
|||||||
* 文件上传
|
* 文件上传
|
||||||
*/
|
*/
|
||||||
export class CoolPlugin extends BasePluginHook implements BaseUpload {
|
export class CoolPlugin extends BasePluginHook implements BaseUpload {
|
||||||
|
/**
|
||||||
|
* 验证路径安全性,防止路径遍历攻击
|
||||||
|
* @param userInput 用户输入的文件名或路径
|
||||||
|
* @returns 安全的文件名
|
||||||
|
*/
|
||||||
|
private sanitizePath(userInput: string): string {
|
||||||
|
if (!userInput) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
// 检查是否包含路径遍历字符
|
||||||
|
if (
|
||||||
|
userInput.includes('..') ||
|
||||||
|
userInput.includes('./') ||
|
||||||
|
userInput.includes('.\\') ||
|
||||||
|
userInput.includes('\\') ||
|
||||||
|
userInput.includes('//') ||
|
||||||
|
userInput.includes('\0') ||
|
||||||
|
/^[a-zA-Z]:/.test(userInput) || // Windows绝对路径
|
||||||
|
userInput.startsWith('/')
|
||||||
|
) {
|
||||||
|
throw new CoolCommException('非法的文件路径');
|
||||||
|
}
|
||||||
|
// 规范化路径后再次检查
|
||||||
|
const normalized = path.normalize(userInput);
|
||||||
|
if (normalized.includes('..') || normalized.startsWith('/')) {
|
||||||
|
throw new CoolCommException('非法的文件路径');
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证最终路径是否在允许的目录内
|
||||||
|
* @param targetPath 目标路径
|
||||||
|
* @param basePath 基础路径
|
||||||
|
*/
|
||||||
|
private validateTargetPath(targetPath: string, basePath: string): void {
|
||||||
|
const resolvedTarget = path.resolve(targetPath);
|
||||||
|
const resolvedBase = path.resolve(basePath);
|
||||||
|
if (!resolvedTarget.startsWith(resolvedBase + path.sep)) {
|
||||||
|
throw new CoolCommException('文件路径超出允许范围');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得上传模式
|
* 获得上传模式
|
||||||
* @returns
|
* @returns
|
||||||
@ -38,27 +81,40 @@ export class CoolPlugin extends BasePluginHook implements BaseUpload {
|
|||||||
*/
|
*/
|
||||||
async downAndUpload(url: string, fileName?: string) {
|
async downAndUpload(url: string, fileName?: string) {
|
||||||
const { domain } = this.pluginInfo.config;
|
const { domain } = this.pluginInfo.config;
|
||||||
|
const basePath = pUploadPath();
|
||||||
|
const dateDir = moment().format('YYYYMMDD');
|
||||||
|
|
||||||
// 从url获取扩展名
|
// 从url获取扩展名
|
||||||
const extend = path.extname(fileName ? fileName : url);
|
const extend = path.extname(fileName ? fileName : url);
|
||||||
|
|
||||||
|
// 验证文件名安全性
|
||||||
|
let safeFileName: string;
|
||||||
|
if (fileName) {
|
||||||
|
safeFileName = this.sanitizePath(fileName);
|
||||||
|
// 只取文件名部分,去除可能的子目录
|
||||||
|
safeFileName = path.basename(safeFileName);
|
||||||
|
} else {
|
||||||
|
safeFileName = uuid() + extend;
|
||||||
|
}
|
||||||
|
|
||||||
const download = require('download');
|
const download = require('download');
|
||||||
// 数据
|
// 数据
|
||||||
const data = url.includes('http')
|
const data = url.includes('http')
|
||||||
? await download(url)
|
? await download(url)
|
||||||
: fs.readFileSync(url);
|
: fs.readFileSync(url);
|
||||||
|
|
||||||
// 创建文件夹
|
// 创建文件夹
|
||||||
const dirPath = path.join(pUploadPath(), `${moment().format('YYYYMMDD')}`);
|
const dirPath = path.join(basePath, dateDir);
|
||||||
if (!fs.existsSync(dirPath)) {
|
if (!fs.existsSync(dirPath)) {
|
||||||
fs.mkdirSync(dirPath, { recursive: true });
|
fs.mkdirSync(dirPath, { recursive: true });
|
||||||
}
|
}
|
||||||
const uuidStr = uuid();
|
|
||||||
const name = `${moment().format('YYYYMMDD')}/${
|
const targetPath = path.join(dirPath, safeFileName);
|
||||||
fileName ? fileName : uuidStr + extend
|
// 验证最终路径
|
||||||
}`;
|
this.validateTargetPath(targetPath, basePath);
|
||||||
fs.writeFileSync(
|
|
||||||
`${dirPath}/${fileName ? fileName : uuid() + extend}`,
|
fs.writeFileSync(targetPath, data);
|
||||||
data
|
return `${domain}/upload/${dateDir}/${safeFileName}`;
|
||||||
);
|
|
||||||
return `${domain}/upload/${name}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,21 +124,28 @@ export class CoolPlugin extends BasePluginHook implements BaseUpload {
|
|||||||
*/
|
*/
|
||||||
async uploadWithKey(filePath: any, key: any) {
|
async uploadWithKey(filePath: any, key: any) {
|
||||||
const { domain } = this.pluginInfo.config;
|
const { domain } = this.pluginInfo.config;
|
||||||
|
const basePath = pUploadPath();
|
||||||
|
const dateDir = moment().format('YYYYMMDD');
|
||||||
|
|
||||||
|
// 验证key安全性
|
||||||
|
const safeKey = this.sanitizePath(key);
|
||||||
|
|
||||||
const data = fs.readFileSync(filePath);
|
const data = fs.readFileSync(filePath);
|
||||||
|
|
||||||
|
// 构建目标路径
|
||||||
|
const targetPath = path.join(basePath, dateDir, safeKey);
|
||||||
|
const dirPath = path.dirname(targetPath);
|
||||||
|
|
||||||
|
// 验证最终路径
|
||||||
|
this.validateTargetPath(targetPath, basePath);
|
||||||
|
|
||||||
// 如果文件夹不存在则创建
|
// 如果文件夹不存在则创建
|
||||||
const dirPath = path.join(
|
|
||||||
pUploadPath(),
|
|
||||||
moment().format('YYYYMMDD'),
|
|
||||||
path.dirname(key)
|
|
||||||
);
|
|
||||||
if (!fs.existsSync(dirPath)) {
|
if (!fs.existsSync(dirPath)) {
|
||||||
fs.mkdirSync(dirPath, { recursive: true });
|
fs.mkdirSync(dirPath, { recursive: true });
|
||||||
}
|
}
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(pUploadPath(), moment().format('YYYYMMDD'), key),
|
fs.writeFileSync(targetPath, data);
|
||||||
data
|
return `${domain}/upload/${dateDir}/${safeKey}`;
|
||||||
);
|
|
||||||
return `${domain}/upload/${moment().format('YYYYMMDD')}/${key}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,35 +157,45 @@ export class CoolPlugin extends BasePluginHook implements BaseUpload {
|
|||||||
const { domain } = this.pluginInfo.config;
|
const { domain } = this.pluginInfo.config;
|
||||||
try {
|
try {
|
||||||
const { key } = ctx.fields;
|
const { key } = ctx.fields;
|
||||||
if (
|
const basePath = pUploadPath();
|
||||||
key &&
|
const dateDir = moment().format('YYYYMMDD');
|
||||||
(key.includes('..') ||
|
|
||||||
key.includes('./') ||
|
// 验证key安全性
|
||||||
key.includes('\\') ||
|
let safeKey: string | undefined;
|
||||||
key.includes('//'))
|
if (key) {
|
||||||
) {
|
safeKey = this.sanitizePath(key);
|
||||||
throw new CoolCommException('非法的key值');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.isEmpty(ctx.files)) {
|
if (_.isEmpty(ctx.files)) {
|
||||||
throw new CoolCommException('上传文件为空');
|
throw new CoolCommException('上传文件为空');
|
||||||
}
|
}
|
||||||
const basePath = pUploadPath();
|
|
||||||
|
|
||||||
const file = ctx.files[0];
|
const file = ctx.files[0];
|
||||||
const extension = file.filename.split('.').pop();
|
// 安全处理原始文件名
|
||||||
const name =
|
const originalFileName = path.basename(file.filename);
|
||||||
moment().format('YYYYMMDD') + '/' + (key || `${uuid()}.${extension}`);
|
const extension = originalFileName.split('.').pop();
|
||||||
|
|
||||||
|
const finalName = safeKey || `${uuid()}.${extension}`;
|
||||||
|
const name = `${dateDir}/${finalName}`;
|
||||||
const target = path.join(basePath, name);
|
const target = path.join(basePath, name);
|
||||||
const dirPath = path.join(basePath, moment().format('YYYYMMDD'));
|
|
||||||
|
// 验证最终路径
|
||||||
|
this.validateTargetPath(target, basePath);
|
||||||
|
|
||||||
|
const dirPath = path.join(basePath, dateDir);
|
||||||
if (!fs.existsSync(dirPath)) {
|
if (!fs.existsSync(dirPath)) {
|
||||||
fs.mkdirSync(dirPath);
|
fs.mkdirSync(dirPath, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = fs.readFileSync(file.data);
|
const data = fs.readFileSync(file.data);
|
||||||
fs.writeFileSync(target, data);
|
fs.writeFileSync(target, data);
|
||||||
return domain + '/upload/' + name;
|
return domain + '/upload/' + name;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
throw new CoolCommException('上传失败' + err.message);
|
if (err instanceof CoolCommException) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
throw new CoolCommException('上传失败: ' + err.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user