mirror of
https://github.com/certd/certd.git
synced 2026-04-14 20:40:53 +08:00
88 lines
3.0 KiB
TypeScript
88 lines
3.0 KiB
TypeScript
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
|
import dayjs from 'dayjs';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import { cache, logger, utils } from '@certd/pipeline';
|
|
import { NotFoundException, ParamException, PermissionException } from '../../../basic/index.js';
|
|
|
|
export type UploadFileItem = {
|
|
filename: string;
|
|
tmpFilePath: string;
|
|
};
|
|
const uploadRootDir = './data/upload';
|
|
export const uploadTmpFileCacheKey = 'tmpfile_key_';
|
|
/**
|
|
*/
|
|
@Provide()
|
|
@Scope(ScopeEnum.Singleton)
|
|
export class FileService {
|
|
async saveFile(userId: number, tmpCacheKey: any, permission: 'public' | 'private') {
|
|
if (tmpCacheKey.startsWith(`/${permission}`)) {
|
|
//已经保存过,不需要再次保存
|
|
return tmpCacheKey;
|
|
}
|
|
let fileName = '';
|
|
let tmpFilePath = tmpCacheKey;
|
|
if (uploadTmpFileCacheKey && tmpCacheKey.startsWith(uploadTmpFileCacheKey)) {
|
|
const tmpFile: UploadFileItem = cache.get(tmpCacheKey);
|
|
if (!tmpFile) {
|
|
throw new ParamException('文件已过期,请重新上传');
|
|
}
|
|
tmpFilePath = tmpFile.tmpFilePath;
|
|
fileName = tmpFile.filename || path.basename(tmpFilePath);
|
|
}
|
|
if (!tmpFilePath || !fs.existsSync(tmpFilePath)) {
|
|
throw new Error('文件不存在,请重新上传');
|
|
}
|
|
const date = dayjs().format('YYYY_MM_DD');
|
|
const random = Math.random().toString(36).substring(7);
|
|
const userIdMd5 = Buffer.from(Buffer.from(userId + '').toString('base64')).toString('hex');
|
|
const key = `/${permission}/${userIdMd5}/${date}/${random}_${fileName}`;
|
|
let savePath = path.join(uploadRootDir, key);
|
|
savePath = path.resolve(savePath);
|
|
const parentDir = path.dirname(savePath);
|
|
if (!fs.existsSync(parentDir)) {
|
|
fs.mkdirSync(parentDir, { recursive: true });
|
|
}
|
|
// eslint-disable-next-line node/no-unsupported-features/node-builtins
|
|
const copyFile = utils.promises.promisify(fs.copyFile);
|
|
await copyFile(tmpFilePath, savePath);
|
|
try {
|
|
fs.unlinkSync(tmpFilePath);
|
|
} catch (e) {
|
|
logger.error(e);
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
getFile(key: string, userId?: number) {
|
|
if (!key) {
|
|
throw new ParamException('参数错误');
|
|
}
|
|
if (key.indexOf('..') >= 0) {
|
|
//安全性判断
|
|
throw new ParamException('参数错误');
|
|
}
|
|
if (!key.startsWith('/')) {
|
|
throw new ParamException('参数错误');
|
|
}
|
|
const keyArr = key.split('/');
|
|
const permission = keyArr[1];
|
|
const userIdMd5 = keyArr[2];
|
|
if (permission !== 'public') {
|
|
//非公开文件需要验证用户
|
|
const userIdStr = Buffer.from(Buffer.from(userIdMd5, 'hex').toString('base64')).toString();
|
|
const userIdInt: number = parseInt(userIdStr, 10);
|
|
if (userId == null || userIdInt !== userId) {
|
|
throw new PermissionException('无访问权限');
|
|
}
|
|
}
|
|
const filePath = path.join(uploadRootDir, key);
|
|
if (!fs.existsSync(filePath)) {
|
|
throw new NotFoundException('文件不存在');
|
|
}
|
|
return filePath;
|
|
}
|
|
}
|