@midwayjs/upload 3.10.16 → 3.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.d.ts +22 -0
- package/dist/constants.js +25 -1
- package/dist/error.d.ts +3 -0
- package/dist/error.js +8 -2
- package/dist/interface.d.ts +32 -1
- package/dist/middleware.d.ts +13 -3
- package/dist/middleware.js +74 -21
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +21 -1
- package/package.json +9 -9
package/dist/constants.d.ts
CHANGED
|
@@ -1,2 +1,24 @@
|
|
|
1
1
|
export declare const uploadWhiteList: string[];
|
|
2
|
+
export declare const DefaultUploadFileMimeType: {
|
|
3
|
+
'.jpg': string;
|
|
4
|
+
'.jpeg': string;
|
|
5
|
+
'.png': string;
|
|
6
|
+
'.gif': string;
|
|
7
|
+
'.bmp': string;
|
|
8
|
+
'.wbmp': string;
|
|
9
|
+
'.webp': string;
|
|
10
|
+
'.tif': string;
|
|
11
|
+
'.tiff': string;
|
|
12
|
+
'.psd': string;
|
|
13
|
+
'.svg': string;
|
|
14
|
+
'.xml': string;
|
|
15
|
+
'.pdf': string;
|
|
16
|
+
'.zip': string;
|
|
17
|
+
'.gz': string;
|
|
18
|
+
'.gzip': string;
|
|
19
|
+
'.mp3': string;
|
|
20
|
+
'.mp4': string;
|
|
21
|
+
'.avi': string;
|
|
22
|
+
};
|
|
23
|
+
export declare const EXT_KEY: unique symbol;
|
|
2
24
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.uploadWhiteList = void 0;
|
|
3
|
+
exports.EXT_KEY = exports.DefaultUploadFileMimeType = exports.uploadWhiteList = void 0;
|
|
4
4
|
exports.uploadWhiteList = [
|
|
5
5
|
// images
|
|
6
6
|
'.jpg',
|
|
@@ -11,6 +11,7 @@ exports.uploadWhiteList = [
|
|
|
11
11
|
'.wbmp',
|
|
12
12
|
'.webp',
|
|
13
13
|
'.tif',
|
|
14
|
+
'.tiff',
|
|
14
15
|
'.psd',
|
|
15
16
|
// text
|
|
16
17
|
'.svg',
|
|
@@ -33,4 +34,27 @@ exports.uploadWhiteList = [
|
|
|
33
34
|
'.mp4',
|
|
34
35
|
'.avi',
|
|
35
36
|
];
|
|
37
|
+
// https://mimetype.io/
|
|
38
|
+
exports.DefaultUploadFileMimeType = {
|
|
39
|
+
'.jpg': 'image/jpeg',
|
|
40
|
+
'.jpeg': 'image/jpeg',
|
|
41
|
+
'.png': 'image/png',
|
|
42
|
+
'.gif': 'image/gif',
|
|
43
|
+
'.bmp': 'image/bmp',
|
|
44
|
+
'.wbmp': 'image/vnd.wap.wbmp',
|
|
45
|
+
'.webp': 'image/webp',
|
|
46
|
+
'.tif': 'image/tiff',
|
|
47
|
+
'.tiff': 'image/tiff',
|
|
48
|
+
'.psd': 'image/vnd.adobe.photoshop',
|
|
49
|
+
'.svg': 'image/svg+xml',
|
|
50
|
+
'.xml': 'application/xml',
|
|
51
|
+
'.pdf': 'application/pdf',
|
|
52
|
+
'.zip': 'application/zip',
|
|
53
|
+
'.gz': 'application/gzip',
|
|
54
|
+
'.gzip': 'application/gzip',
|
|
55
|
+
'.mp3': 'audio/mpeg',
|
|
56
|
+
'.mp4': 'video/mp4',
|
|
57
|
+
'.avi': 'video/x-msvideo',
|
|
58
|
+
};
|
|
59
|
+
exports.EXT_KEY = Symbol('_ext');
|
|
36
60
|
//# sourceMappingURL=constants.js.map
|
package/dist/error.d.ts
CHANGED
|
@@ -2,4 +2,7 @@ import { httpError } from '@midwayjs/core';
|
|
|
2
2
|
export declare class MultipartInvalidFilenameError extends httpError.BadRequestError {
|
|
3
3
|
constructor(filename: string);
|
|
4
4
|
}
|
|
5
|
+
export declare class MultipartInvalidFileTypeError extends httpError.BadRequestError {
|
|
6
|
+
constructor(filename: string, currentType: string, type: string);
|
|
7
|
+
}
|
|
5
8
|
//# sourceMappingURL=error.d.ts.map
|
package/dist/error.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MultipartInvalidFilenameError = void 0;
|
|
3
|
+
exports.MultipartInvalidFileTypeError = exports.MultipartInvalidFilenameError = void 0;
|
|
4
4
|
const core_1 = require("@midwayjs/core");
|
|
5
5
|
class MultipartInvalidFilenameError extends core_1.httpError.BadRequestError {
|
|
6
6
|
constructor(filename) {
|
|
7
|
-
super(`Invalid
|
|
7
|
+
super(`Invalid upload file name ${filename}, please check it`);
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
exports.MultipartInvalidFilenameError = MultipartInvalidFilenameError;
|
|
11
|
+
class MultipartInvalidFileTypeError extends core_1.httpError.BadRequestError {
|
|
12
|
+
constructor(filename, currentType, type) {
|
|
13
|
+
super(`Invalid upload file type, ${filename} type(${currentType || 'unknown'}) is not ${type} , please check it`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.MultipartInvalidFileTypeError = MultipartInvalidFileTypeError;
|
|
11
17
|
//# sourceMappingURL=error.js.map
|
package/dist/interface.d.ts
CHANGED
|
@@ -1,13 +1,44 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { Readable } from
|
|
2
|
+
import { Readable } from 'stream';
|
|
3
|
+
import { IgnoreMatcher } from '@midwayjs/core';
|
|
3
4
|
export type UploadMode = 'stream' | 'file';
|
|
4
5
|
export interface UploadOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Upload mode, default is `file`
|
|
8
|
+
*/
|
|
5
9
|
mode?: UploadMode;
|
|
10
|
+
/**
|
|
11
|
+
* Max file size (in bytes), default is `10mb`
|
|
12
|
+
*/
|
|
6
13
|
fileSize?: string;
|
|
14
|
+
/**
|
|
15
|
+
* The white ext file names
|
|
16
|
+
*/
|
|
7
17
|
whitelist?: string[] | null;
|
|
18
|
+
/**
|
|
19
|
+
* Temporary file directory
|
|
20
|
+
*/
|
|
8
21
|
tmpdir?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Temporary file automatic cleanup time, default is 5 minutes
|
|
24
|
+
*/
|
|
9
25
|
cleanTimeout?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Whether the uploaded body is base64, for example, apigw of Tencent Cloud
|
|
28
|
+
*/
|
|
10
29
|
base64?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Which paths to ignore
|
|
32
|
+
*/
|
|
33
|
+
ignore?: IgnoreMatcher<any> | IgnoreMatcher<any>[];
|
|
34
|
+
/**
|
|
35
|
+
* Match those paths with higher priority than ignore
|
|
36
|
+
*/
|
|
37
|
+
match?: IgnoreMatcher<any> | IgnoreMatcher<any>[];
|
|
38
|
+
/**
|
|
39
|
+
* Mime type white list
|
|
40
|
+
*/
|
|
41
|
+
mimeTypeWhiteList?: Record<string, string | string[]>;
|
|
11
42
|
}
|
|
12
43
|
export interface UploadFileInfo<T> {
|
|
13
44
|
filename: string;
|
package/dist/middleware.d.ts
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { IMiddleware, IMidwayLogger, IgnoreMatcher } from '@midwayjs/core';
|
|
2
3
|
import { UploadOptions } from '.';
|
|
3
4
|
export declare class UploadMiddleware implements IMiddleware<any, any> {
|
|
4
|
-
|
|
5
|
+
uploadConfig: UploadOptions;
|
|
5
6
|
logger: IMidwayLogger;
|
|
6
7
|
private uploadWhiteListMap;
|
|
8
|
+
private uploadFileMimeTypeMap;
|
|
9
|
+
match: IgnoreMatcher<any>[];
|
|
10
|
+
ignore: IgnoreMatcher<any>[];
|
|
11
|
+
init(): Promise<void>;
|
|
7
12
|
resolve(app: any): (req: any, res: any, next: any) => Promise<any>;
|
|
8
13
|
execUpload(ctx: any, req: any, res: any, next: any, isExpress: any): Promise<any>;
|
|
9
14
|
getUploadBoundary(request: any): false | string;
|
|
10
15
|
isReadableStream(req: any, isExpress: any): boolean;
|
|
11
|
-
|
|
16
|
+
checkAndGetExt(filename: any): string | boolean;
|
|
17
|
+
checkFileType(ext: string, data: Buffer): Promise<{
|
|
18
|
+
passed: boolean;
|
|
19
|
+
mime?: string;
|
|
20
|
+
current?: string;
|
|
21
|
+
}>;
|
|
12
22
|
static getName(): string;
|
|
13
23
|
}
|
|
14
24
|
//# sourceMappingURL=middleware.d.ts.map
|
package/dist/middleware.js
CHANGED
|
@@ -17,15 +17,32 @@ const stream_1 = require("stream");
|
|
|
17
17
|
const _1 = require(".");
|
|
18
18
|
const parse_1 = require("./parse");
|
|
19
19
|
const getRawBody = require("raw-body");
|
|
20
|
+
const file_type_1 = require("file-type");
|
|
21
|
+
const utils_1 = require("./utils");
|
|
20
22
|
const { unlink, writeFile } = fs_1.promises;
|
|
21
23
|
let UploadMiddleware = class UploadMiddleware {
|
|
22
24
|
constructor() {
|
|
23
|
-
this.uploadWhiteListMap =
|
|
25
|
+
this.uploadWhiteListMap = new Map();
|
|
26
|
+
this.uploadFileMimeTypeMap = new Map();
|
|
27
|
+
}
|
|
28
|
+
async init() {
|
|
29
|
+
if (this.uploadConfig.match) {
|
|
30
|
+
this.match = [].concat(this.uploadConfig.match || []);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
this.ignore = [].concat(this.uploadConfig.ignore || []);
|
|
34
|
+
}
|
|
24
35
|
}
|
|
25
36
|
resolve(app) {
|
|
26
|
-
if (Array.isArray(this.
|
|
27
|
-
for (const whiteExt of this.
|
|
28
|
-
this.uploadWhiteListMap
|
|
37
|
+
if (Array.isArray(this.uploadConfig.whitelist)) {
|
|
38
|
+
for (const whiteExt of this.uploadConfig.whitelist) {
|
|
39
|
+
this.uploadWhiteListMap.set(whiteExt, whiteExt);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (this.uploadConfig.mimeTypeWhiteList) {
|
|
43
|
+
for (const ext in this.uploadConfig.mimeTypeWhiteList) {
|
|
44
|
+
const mime = [].concat(this.uploadConfig.mimeTypeWhiteList[ext]);
|
|
45
|
+
this.uploadFileMimeTypeMap.set(ext, mime);
|
|
29
46
|
}
|
|
30
47
|
}
|
|
31
48
|
if (app.getFrameworkType() === core_1.MidwayFrameworkType.WEB_EXPRESS) {
|
|
@@ -43,7 +60,7 @@ let UploadMiddleware = class UploadMiddleware {
|
|
|
43
60
|
}
|
|
44
61
|
async execUpload(ctx, req, res, next, isExpress) {
|
|
45
62
|
var _a;
|
|
46
|
-
const { mode, tmpdir, fileSize } = this.
|
|
63
|
+
const { mode, tmpdir, fileSize } = this.uploadConfig;
|
|
47
64
|
const boundary = this.getUploadBoundary(req);
|
|
48
65
|
if (!boundary) {
|
|
49
66
|
return next();
|
|
@@ -72,12 +89,12 @@ let UploadMiddleware = class UploadMiddleware {
|
|
|
72
89
|
if (this.isReadableStream(req, isExpress)) {
|
|
73
90
|
if (mode === 'stream') {
|
|
74
91
|
const { fields, fileInfo } = await (0, parse_1.parseFromReadableStream)(req, boundary);
|
|
75
|
-
const ext = this.
|
|
92
|
+
const ext = this.checkAndGetExt(fileInfo.filename);
|
|
76
93
|
if (!ext) {
|
|
77
94
|
throw new _1.MultipartInvalidFilenameError(fileInfo.filename);
|
|
78
95
|
}
|
|
79
96
|
else {
|
|
80
|
-
fileInfo[
|
|
97
|
+
fileInfo[_1.EXT_KEY] = ext;
|
|
81
98
|
ctx.fields = fields;
|
|
82
99
|
ctx.files = [fileInfo];
|
|
83
100
|
return next();
|
|
@@ -95,27 +112,28 @@ let UploadMiddleware = class UploadMiddleware {
|
|
|
95
112
|
else {
|
|
96
113
|
body = req.body;
|
|
97
114
|
}
|
|
98
|
-
const data = await (0, parse_1.parseMultipart)(body, boundary, this.
|
|
115
|
+
const data = await (0, parse_1.parseMultipart)(body, boundary, this.uploadConfig);
|
|
99
116
|
if (!data) {
|
|
100
117
|
return next();
|
|
101
118
|
}
|
|
102
119
|
ctx.fields = data.fields;
|
|
103
120
|
const requireId = `upload_${Date.now()}.${Math.random()}`;
|
|
104
121
|
const files = data.files;
|
|
105
|
-
const
|
|
106
|
-
const ext = this.
|
|
122
|
+
for (const fileInfo of files) {
|
|
123
|
+
const ext = this.checkAndGetExt(fileInfo.filename);
|
|
107
124
|
if (!ext) {
|
|
108
|
-
|
|
125
|
+
throw new _1.MultipartInvalidFilenameError(fileInfo.filename);
|
|
109
126
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
127
|
+
const { passed, mime, current } = await this.checkFileType(ext, fileInfo.data);
|
|
128
|
+
if (!passed) {
|
|
129
|
+
throw new _1.MultipartInvalidFileTypeError(fileInfo.filename, current, mime);
|
|
130
|
+
}
|
|
131
|
+
fileInfo[_1.EXT_KEY] = ext;
|
|
114
132
|
}
|
|
115
133
|
ctx.files = await Promise.all(files.map(async (file, index) => {
|
|
116
|
-
const { data
|
|
134
|
+
const { data } = file;
|
|
117
135
|
if (mode === 'file') {
|
|
118
|
-
const ext = file[
|
|
136
|
+
const ext = file[_1.EXT_KEY];
|
|
119
137
|
const tmpFileName = (0, path_1.resolve)(tmpdir, `${requireId}.${index}${ext}`);
|
|
120
138
|
await writeFile(tmpFileName, data, 'binary');
|
|
121
139
|
file.data = tmpFileName;
|
|
@@ -167,17 +185,46 @@ let UploadMiddleware = class UploadMiddleware {
|
|
|
167
185
|
}
|
|
168
186
|
return false;
|
|
169
187
|
}
|
|
170
|
-
|
|
188
|
+
// check extentions
|
|
189
|
+
checkAndGetExt(filename) {
|
|
171
190
|
const lowerCaseFileNameList = filename.toLowerCase().split('.');
|
|
172
191
|
while (lowerCaseFileNameList.length) {
|
|
173
192
|
lowerCaseFileNameList.shift();
|
|
174
193
|
const curExt = `.${lowerCaseFileNameList.join('.')}`;
|
|
175
|
-
if (this.
|
|
176
|
-
return curExt;
|
|
194
|
+
if (this.uploadConfig.whitelist === null) {
|
|
195
|
+
return (0, utils_1.formatExt)(curExt);
|
|
196
|
+
}
|
|
197
|
+
if (this.uploadWhiteListMap.has(curExt)) {
|
|
198
|
+
// Avoid the presence of hidden characters and return extensions in the white list.
|
|
199
|
+
return this.uploadWhiteListMap.get(curExt);
|
|
177
200
|
}
|
|
178
201
|
}
|
|
179
202
|
return false;
|
|
180
203
|
}
|
|
204
|
+
// check file-type
|
|
205
|
+
async checkFileType(ext, data) {
|
|
206
|
+
// fileType == null, pass check
|
|
207
|
+
if (!this.uploadConfig.mimeTypeWhiteList) {
|
|
208
|
+
return { passed: true };
|
|
209
|
+
}
|
|
210
|
+
const mime = this.uploadFileMimeTypeMap.get(ext);
|
|
211
|
+
if (!mime) {
|
|
212
|
+
return { passed: false, mime: ext };
|
|
213
|
+
}
|
|
214
|
+
if (!mime.length) {
|
|
215
|
+
return { passed: true };
|
|
216
|
+
}
|
|
217
|
+
const typeInfo = await (0, file_type_1.fromBuffer)(data);
|
|
218
|
+
if (!typeInfo) {
|
|
219
|
+
return { passed: false, mime: mime.join('、') };
|
|
220
|
+
}
|
|
221
|
+
const findMime = mime.find(mimeItem => mimeItem === typeInfo.mime);
|
|
222
|
+
return {
|
|
223
|
+
passed: !!findMime,
|
|
224
|
+
mime: mime.join('、'),
|
|
225
|
+
current: typeInfo.mime,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
181
228
|
static getName() {
|
|
182
229
|
return 'upload';
|
|
183
230
|
}
|
|
@@ -185,11 +232,17 @@ let UploadMiddleware = class UploadMiddleware {
|
|
|
185
232
|
__decorate([
|
|
186
233
|
(0, core_1.Config)('upload'),
|
|
187
234
|
__metadata("design:type", Object)
|
|
188
|
-
], UploadMiddleware.prototype, "
|
|
235
|
+
], UploadMiddleware.prototype, "uploadConfig", void 0);
|
|
189
236
|
__decorate([
|
|
190
237
|
(0, core_1.Logger)(),
|
|
191
238
|
__metadata("design:type", Object)
|
|
192
239
|
], UploadMiddleware.prototype, "logger", void 0);
|
|
240
|
+
__decorate([
|
|
241
|
+
(0, core_1.Init)(),
|
|
242
|
+
__metadata("design:type", Function),
|
|
243
|
+
__metadata("design:paramtypes", []),
|
|
244
|
+
__metadata("design:returntype", Promise)
|
|
245
|
+
], UploadMiddleware.prototype, "init", null);
|
|
193
246
|
UploadMiddleware = __decorate([
|
|
194
247
|
(0, core_1.Middleware)()
|
|
195
248
|
], UploadMiddleware);
|
package/dist/utils.d.ts
CHANGED
|
@@ -2,4 +2,5 @@ export declare const autoRemoveUploadTmpFile: (tmpDir: string, cleanTimeout: num
|
|
|
2
2
|
export declare const stopAutoRemoveUploadTmpFile: () => Promise<void>;
|
|
3
3
|
export declare const checkExists: (path: string) => Promise<boolean>;
|
|
4
4
|
export declare const ensureDir: (dirPath: string) => Promise<boolean>;
|
|
5
|
+
export declare const formatExt: (ext: string) => string;
|
|
5
6
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ensureDir = exports.checkExists = exports.stopAutoRemoveUploadTmpFile = exports.autoRemoveUploadTmpFile = void 0;
|
|
3
|
+
exports.formatExt = exports.ensureDir = exports.checkExists = exports.stopAutoRemoveUploadTmpFile = exports.autoRemoveUploadTmpFile = void 0;
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
const { readdir, access, stat, unlink, mkdir } = fs_1.promises;
|
|
@@ -68,4 +68,24 @@ const ensureDir = async (dirPath) => {
|
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
70
|
exports.ensureDir = ensureDir;
|
|
71
|
+
const formatExt = (ext) => {
|
|
72
|
+
return Buffer.from(ext.toLowerCase())
|
|
73
|
+
.filter(ext => {
|
|
74
|
+
// .
|
|
75
|
+
if (ext === 0x2e) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
// 0-9
|
|
79
|
+
if (ext >= 0x30 && ext <= 0x39) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
// a-z
|
|
83
|
+
if (ext >= 0x61 && ext <= 0x7a) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
})
|
|
88
|
+
.toString();
|
|
89
|
+
};
|
|
90
|
+
exports.formatExt = formatExt;
|
|
71
91
|
//# sourceMappingURL=utils.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midwayjs/upload",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.1",
|
|
4
4
|
"description": "Midway Component for upload",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
},
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
+
"file-type": "16.5.4",
|
|
25
26
|
"raw-body": "2.5.2"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
|
-
"@midwayjs/core": "^3.
|
|
29
|
-
"@midwayjs/express": "^3.
|
|
30
|
-
"@midwayjs/faas": "^3.
|
|
31
|
-
"@midwayjs/koa": "^3.
|
|
32
|
-
"@midwayjs/mock": "^3.
|
|
33
|
-
"@midwayjs/
|
|
34
|
-
"@midwayjs/web": "^3.10.16"
|
|
29
|
+
"@midwayjs/core": "^3.11.1",
|
|
30
|
+
"@midwayjs/express": "^3.11.1",
|
|
31
|
+
"@midwayjs/faas": "^3.11.1",
|
|
32
|
+
"@midwayjs/koa": "^3.11.1",
|
|
33
|
+
"@midwayjs/mock": "^3.11.1",
|
|
34
|
+
"@midwayjs/web": "^3.11.1"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "bd9375874eb8cfaa49fbcfaa0497021cea06a394"
|
|
37
37
|
}
|