Skip to content

Commit 85cfd3d

Browse files
committed
Finish tests for preserveExtension file upload option
1 parent 5bbf645 commit 85cfd3d

File tree

2 files changed

+156
-119
lines changed

2 files changed

+156
-119
lines changed

lib/index.js

+11-8
Original file line numberDiff line numberDiff line change
@@ -89,28 +89,31 @@ function processMultipart(options, req, res, next) {
8989
return;
9090

9191
if (options.safeFileNames) {
92-
let extensionLength = 3;
92+
let maxExtensionLength = 3;
9393
let extension = '';
9494

9595
if (typeof options.safeFileNames === 'object')
9696
safeFileNameRegex = options.safeFileNames;
9797

98-
if (options.preserveExtension) {
99-
if (typeof options.preserveExtension === 'number')
100-
extensionLength = options.preserveExtension;
98+
maxExtensionLength = parseInt(options.preserveExtension);
99+
if (options.preserveExtension || maxExtensionLength === 0) {
100+
if (isNaN(maxExtensionLength))
101+
maxExtensionLength = 3;
102+
else
103+
maxExtensionLength = Math.abs(maxExtensionLength);
101104

102105
let filenameParts = filename.split('.');
103106
let filenamePartsLen = filenameParts.length;
104107
if (filenamePartsLen > 1) {
105108
extension = filenameParts.pop();
106109

107-
if (extension.length > extensionLength) {
110+
if (extension.length > maxExtensionLength && maxExtensionLength > 0) {
108111
filenameParts[filenameParts.length - 1] +=
109-
'.' + extension.substr(0, extension.length - extensionLength);
110-
extension = extension.substr(-extensionLength);
112+
'.' + extension.substr(0, extension.length - maxExtensionLength);
113+
extension = extension.substr(-maxExtensionLength);
111114
}
112115

113-
extension = '.' + extension.replace(safeFileNameRegex, '');
116+
extension = maxExtensionLength ? '.' + extension.replace(safeFileNameRegex, '') : '';
114117
filename = filenameParts.join('.');
115118
}
116119
}

test/options.spec.js

+145-111
Original file line numberDiff line numberDiff line change
@@ -2,150 +2,184 @@ const fs = require('fs');
22
const path = require('path');
33
const request = require('supertest');
44
const server = require('./server');
5-
// const clearUploadsDir = server.clearUploadsDir;
5+
const clearUploadsDir = server.clearUploadsDir;
66
const fileDir = server.fileDir;
77
const uploadDir = server.uploadDir;
88

9-
describe('SafeFileNames', function() {
10-
it(`Does nothing to your filename when disabled.`, function(done) {
11-
const app = server.setup({safeFileNames: false});
9+
describe('File Upload Options Tests', function() {
10+
afterEach(function(done) {
11+
clearUploadsDir();
12+
done();
13+
});
1214

13-
request(app)
14-
.post('/upload/single')
15-
.attach('testFile', path.join(fileDir, 'my$Invalid#fileName.png123'))
16-
.expect(200)
17-
.end(function(err, res) {
18-
if (err)
19-
return done(err);
15+
describe('Testing [safeFileNames] option to ensure:', function() {
16+
it('Does nothing to your filename when disabled.',
17+
function(done) {
18+
const fileUploadOptions = {safeFileNames: false};
19+
const actualFileName = 'my$Invalid#fileName.png123';
20+
const expectedFileName = 'my$Invalid#fileName.png123';
2021

21-
let uploadedFilePath = path.join(uploadDir, 'my$Invalid#fileName.png123');
22+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
23+
});
2224

23-
fs.stat(uploadedFilePath, done);
25+
it('Is disabled by default.',
26+
function(done) {
27+
const fileUploadOptions = null;
28+
const actualFileName = 'my$Invalid#fileName.png123';
29+
const expectedFileName = 'my$Invalid#fileName.png123';
30+
31+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
2432
});
25-
});
2633

27-
it(`Strips away all illegal characters (including spaces) when enabled.`, function(done) {
28-
const app = server.setup({safeFileNames: true});
34+
it('Strips away all non-alphanumeric characters (excluding hyphens/underscores) when enabled.',
35+
function(done) {
36+
const fileUploadOptions = {safeFileNames: true};
37+
const actualFileName = 'my$Invalid#fileName.png123';
38+
const expectedFileName = 'myInvalidfileNamepng123';
2939

30-
request(app)
31-
.post('/upload/single')
32-
.attach('testFile', path.join(fileDir, 'my$Invalid#fileName.png123'))
33-
.expect(200)
34-
.end(function(err, res) {
35-
if (err)
36-
return done(err);
40+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
41+
});
3742

38-
let uploadedFilePath = path.join(uploadDir, 'myInvalidfileNamepng123');
43+
it('Accepts a regex for stripping (decidedly) "invalid" characters from filename.',
44+
function(done) {
45+
const fileUploadOptions = {safeFileNames: /[\$#]/g};
46+
const actualFileName = 'my$Invalid#fileName.png123';
47+
const expectedFileName = 'myInvalidfileName.png123';
3948

40-
fs.stat(uploadedFilePath, done);
49+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
4150
});
4251
});
4352

44-
it(`Respects a regex for stripping 'invalid' characters from filename.`, function(done) {
45-
const app = server.setup({safeFileNames: /[\$#]/g});
53+
describe('Testing [preserveExtension] option to ensure:', function() {
54+
it('Does not preserve the extension of your filename when disabled.',
55+
function(done) {
56+
const fileUploadOptions = {safeFileNames: true, preserveExtension: false};
57+
const actualFileName = 'my$Invalid#fileName.png123';
58+
const expectedFileName = 'myInvalidfileNamepng123';
4659

47-
request(app)
48-
.post('/upload/single')
49-
.attach('testFile', path.join(fileDir, 'my$Invalid#fileName.png123'))
50-
.expect(200)
51-
.end(function(err, res) {
52-
if (err)
53-
return done(err);
60+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
61+
});
5462

55-
let uploadedFilePath = path.join(uploadDir, 'myInvalidfileName.png123');
63+
it('Is disabled by default.',
64+
function(done) {
65+
const fileUploadOptions = {safeFileNames: true};
66+
const actualFileName = 'my$Invalid#fileName.png123';
67+
const expectedFileName = 'myInvalidfileNamepng123';
5668

57-
fs.stat(uploadedFilePath, done);
69+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
5870
});
59-
});
60-
});
6171

62-
describe(`preserveExtension`, function() {
63-
it(`Does nothing to your filename when disabled.`, function(done) {
64-
const app = server.setup({safeFileNames: true, preserveExtension: false});
72+
it('Shortens your extension to the default(3) when enabled, if the extension found is larger.',
73+
function(done) {
74+
const fileUploadOptions = {safeFileNames: true, preserveExtension: true};
75+
const actualFileName = 'my$Invalid#fileName.png123';
76+
const expectedFileName = 'myInvalidfileNamepng.123';
6577

66-
request(app)
67-
.post('/upload/single')
68-
.attach('testFile', path.join(fileDir, 'my$Invalid#fileName.png123'))
69-
.expect(200)
70-
.end(function(err, res) {
71-
if (err)
72-
return done(err);
78+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
79+
});
7380

74-
let uploadedFilePath = path.join(uploadDir, 'myInvalidfileNamepng123');
81+
it('Leaves your extension alone when enabled, if the extension found is <= default(3) length',
82+
function(done) {
83+
const fileUploadOptions = {safeFileNames: true, preserveExtension: true};
84+
const actualFileName = 'car.png';
85+
const expectedFileName = 'car.png';
7586

76-
fs.stat(uploadedFilePath, done);
87+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
88+
});
89+
90+
it('Can be configured for an extension length > default(3).',
91+
function(done) {
92+
const fileUploadOptions = {safeFileNames: true, preserveExtension: 7};
93+
const actualFileName = 'my$Invalid#fileName.png123';
94+
const expectedFileName = 'myInvalidfileName.png123';
95+
96+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
97+
});
98+
99+
it('Can be configured for an extension length < default(3).',
100+
function(done) {
101+
const fileUploadOptions = {safeFileNames: true, preserveExtension: 2};
102+
const actualFileName = 'my$Invalid#fileName.png123';
103+
const expectedFileName = 'myInvalidfileNamepng1.23';
104+
105+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
106+
});
107+
108+
it('Will use the absolute value of your extension length when negative.',
109+
function(done) {
110+
const fileUploadOptions = {safeFileNames: true, preserveExtension: -5};
111+
const actualFileName = 'my$Invalid#fileName.png123';
112+
const expectedFileName = 'myInvalidfileNamep.ng123';
113+
114+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
115+
});
116+
117+
it('Will leave no extension when the extension length == 0.',
118+
function(done) {
119+
const fileUploadOptions = {safeFileNames: true, preserveExtension: 0};
120+
const actualFileName = 'car.png';
121+
const expectedFileName = 'car';
122+
123+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
124+
});
125+
126+
it('Will accept numbers as strings, if they can be resolved with parseInt.',
127+
function(done) {
128+
const fileUploadOptions = {safeFileNames: true, preserveExtension: '3'};
129+
const actualFileName = 'my$Invalid#fileName.png123';
130+
const expectedFileName = 'myInvalidfileNamepng.123';
131+
132+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
133+
});
134+
135+
it('Will be evaluated for truthy-ness if it cannot be parsed as an int.',
136+
function(done) {
137+
const fileUploadOptions = {safeFileNames: true, preserveExtension: 'not-a-#-but-truthy'};
138+
const actualFileName = 'my$Invalid#fileName.png123';
139+
const expectedFileName = 'myInvalidfileNamepng.123';
140+
141+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
142+
});
143+
144+
it('Will ignore any decimal amount when evaluating for extension length.',
145+
function(done) {
146+
const fileUploadOptions = {safeFileNames: true, preserveExtension: 4.98};
147+
const actualFileName = 'my$Invalid#fileName.png123';
148+
const expectedFileName = 'myInvalidfileNamepn.g123';
149+
150+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
151+
});
152+
153+
it('Only considers the last dotted part as the extension.',
154+
function(done) {
155+
const fileUploadOptions = {safeFileNames: true, preserveExtension: true};
156+
const actualFileName = 'basket.ball.bp';
157+
const expectedFileName = 'basketball.bp';
158+
159+
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
77160
});
78161
});
79162

80-
it(`Shortens your extension to the default(3) when enabled, if the extension found is larger`,
81-
function(done) {
82-
const app = server.setup({safeFileNames: true, preserveExtension: true});
163+
function executeFileUploadTestWalk(options,
164+
actualFileNameToUpload,
165+
expectedFilNameOnFileSystem,
166+
done) {
167+
const argsUnderTest = options;
168+
const app = server.setup(argsUnderTest);
169+
const actualFileName = actualFileNameToUpload;
170+
const expectedFileName = expectedFilNameOnFileSystem;
83171

84172
request(app)
85173
.post('/upload/single')
86-
.attach('testFile', path.join(fileDir, 'my$Invalid#fileName.png123'))
174+
.attach('testFile', path.join(fileDir, actualFileName))
87175
.expect(200)
88-
.end(function(err, res) {
176+
.end(function(err) {
89177
if (err)
90178
return done(err);
91179

92-
let uploadedFilePath = path.join(uploadDir, 'myInvalidfileNamepng.123');
180+
const uploadedFilePath = path.join(uploadDir, expectedFileName);
93181

94182
fs.stat(uploadedFilePath, done);
95183
});
96-
});
97-
98-
it(`Leaves your extension alone when enabled, if the extension found is <= default(3) length`,
99-
function(done) {
100-
const app = server.setup({safeFileNames: true, preserveExtension: true});
101-
102-
request(app)
103-
.post('/upload/single')
104-
.attach('testFile', path.join(fileDir, 'car.png'))
105-
.expect(200)
106-
.end(function(err, res) {
107-
if (err)
108-
return done(err);
109-
110-
let uploadedFilePath = path.join(uploadDir, 'car.png');
111-
112-
fs.stat(uploadedFilePath, done);
113-
});
114-
});
115-
116-
it(`Leaves your extension alone when set to a number >= the extension length.`,
117-
function(done) {
118-
const app = server.setup({safeFileNames: true, preserveExtension: 7});
119-
120-
request(app)
121-
.post('/upload/single')
122-
.attach('testFile', path.join(fileDir, 'my$Invalid#fileName.png123'))
123-
.expect(200)
124-
.end(function(err, res) {
125-
if (err)
126-
return done(err);
127-
128-
let uploadedFilePath = path.join(uploadDir, 'myInvalidfileName.png123');
129-
130-
fs.stat(uploadedFilePath, done);
131-
});
132-
});
133-
134-
it(`Only considers the last dotted part the extension.`,
135-
function(done) {
136-
const app = server.setup({safeFileNames: true, preserveExtension: true});
137-
138-
request(app)
139-
.post('/upload/single')
140-
.attach('testFile', path.join(fileDir, 'basket.ball.bp'))
141-
.expect(200)
142-
.end(function(err, res) {
143-
if (err)
144-
return done(err);
145-
146-
let uploadedFilePath = path.join(uploadDir, 'basketball.bp');
147-
148-
fs.stat(uploadedFilePath, done);
149-
});
150-
});
184+
}
151185
});

0 commit comments

Comments
 (0)