dev
This commit is contained in:
78
node_modules/express-fileupload/test/fileFactory.spec.js
generated
vendored
Normal file
78
node_modules/express-fileupload/test/fileFactory.spec.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const md5 = require('md5');
|
||||
const path = require('path');
|
||||
const assert = require('assert');
|
||||
const server = require('./server');
|
||||
const {isFunc} = require('../lib/utilities');
|
||||
const fileFactory = require('../lib/fileFactory');
|
||||
|
||||
const mockFileName = 'basketball.png';
|
||||
const mockFile = path.join(server.fileDir, mockFileName);
|
||||
const mockBuffer = fs.readFileSync(mockFile);
|
||||
const mockMd5 = md5(mockBuffer);
|
||||
|
||||
const mockFileOpts = {
|
||||
name: mockFileName,
|
||||
buffer: mockBuffer,
|
||||
encoding: 'utf-8',
|
||||
mimetype: 'image/png',
|
||||
hash: mockMd5,
|
||||
tempFilePath: mockFile
|
||||
};
|
||||
|
||||
describe('fileFactory: Test of the fileFactory factory', function() {
|
||||
beforeEach(() => server.clearUploadsDir());
|
||||
|
||||
it('return a file object', () => assert.ok(fileFactory(mockFileOpts)));
|
||||
|
||||
describe('Properties', function() {
|
||||
it('contains the name property', () => {
|
||||
assert.equal(fileFactory(mockFileOpts).name, mockFileName);
|
||||
});
|
||||
it('contains the data property', () => assert.ok(fileFactory(mockFileOpts).data));
|
||||
it('contains the encoding property', () => {
|
||||
assert.equal(fileFactory(mockFileOpts).encoding, 'utf-8');
|
||||
});
|
||||
it('contains the mimetype property', () => {
|
||||
assert.equal(fileFactory(mockFileOpts).mimetype, 'image/png');
|
||||
});
|
||||
it('contains the md5 property', () => assert.equal(fileFactory(mockFileOpts).md5, mockMd5));
|
||||
it('contains the mv method', () => assert.equal(isFunc(fileFactory(mockFileOpts).mv), true));
|
||||
});
|
||||
|
||||
describe('File object behavior for in memory upload', function() {
|
||||
const file = fileFactory(mockFileOpts);
|
||||
it('move the file to the specified folder', (done) => {
|
||||
file.mv(path.join(server.uploadDir, mockFileName), (err) => {
|
||||
assert.ifError(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('reject the mv if the destination does not exists', (done) => {
|
||||
file.mv(path.join(server.uploadDir, 'unknown', mockFileName), (err) => {
|
||||
assert.ok(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('File object behavior for upload into temporary file', function() {
|
||||
const file = fileFactory(mockFileOpts, { useTempFiles: true });
|
||||
it('move the file to the specified folder', (done) => {
|
||||
file.mv(path.join(server.uploadDir, mockFileName), (err) => {
|
||||
assert.ifError(err);
|
||||
// Place back moved file.
|
||||
fs.renameSync(path.join(server.uploadDir, mockFileName), mockFile);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('reject the mv if the destination does not exists', (done) => {
|
||||
file.mv(path.join(server.uploadDir, 'unknown', mockFileName), (err) => {
|
||||
assert.ok(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
99
node_modules/express-fileupload/test/fileLimitUploads.spec.js
generated
vendored
Normal file
99
node_modules/express-fileupload/test/fileLimitUploads.spec.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const request = require('supertest');
|
||||
const assert = require('assert');
|
||||
const server = require('./server');
|
||||
const clearUploadsDir = server.clearUploadsDir;
|
||||
const fileDir = server.fileDir;
|
||||
|
||||
describe('fileLimitUloads: Test Single File Upload With File Size Limit', function() {
|
||||
let app, limitHandlerRun;
|
||||
|
||||
beforeEach(function() {
|
||||
clearUploadsDir();
|
||||
});
|
||||
|
||||
describe('abort connection on limit reached', function() {
|
||||
before(function() {
|
||||
app = server.setup({
|
||||
limits: {fileSize: 200 * 1024}, // set 200kb upload limit
|
||||
abortOnLimit: true
|
||||
});
|
||||
});
|
||||
|
||||
it(`upload 'basketball.png' (~154kb) with 200kb size limit`, function(done) {
|
||||
let filePath = path.join(fileDir, 'basketball.png');
|
||||
|
||||
request(app)
|
||||
.post('/upload/single/truncated')
|
||||
.attach('testFile', filePath)
|
||||
.expect(200)
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it(`fail when uploading 'car.png' (~269kb) with 200kb size limit`, function(done) {
|
||||
let filePath = path.join(fileDir, 'car.png');
|
||||
|
||||
request(app)
|
||||
.post('/upload/single/truncated')
|
||||
.attach('testFile', filePath)
|
||||
.expect(413)
|
||||
.end((err) => {
|
||||
// err.code === 'ECONNRESET' that means upload has been aborted.
|
||||
done(err && err.code !== 'ECONNRESET' ? err : null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Run limitHandler on limit reached.', function(){
|
||||
before(function() {
|
||||
app = server.setup({
|
||||
limits: {fileSize: 200 * 1024}, // set 200kb upload limit
|
||||
limitHandler: (req, res) => { // set limit handler
|
||||
res.writeHead(500, { Connection: 'close', 'Content-Type': 'application/json'});
|
||||
res.end(JSON.stringify({response: 'Limit reached!'}));
|
||||
limitHandlerRun = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it(`Run limit handler when uploading 'car.png' (~269kb) with 200kb size limit`, function(done) {
|
||||
let filePath = path.join(fileDir, 'car.png');
|
||||
limitHandlerRun = false;
|
||||
|
||||
request(app)
|
||||
.post('/upload/single/truncated')
|
||||
.attach('testFile', filePath)
|
||||
.expect(500, {response: 'Limit reached!'})
|
||||
.end(function(err) {
|
||||
// err.code === 'ECONNRESET' that means upload has been aborted.
|
||||
if (err && err.code !== 'ECONNRESET') return done(err);
|
||||
if (!limitHandlerRun) return done('handler did not run');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('pass truncated file to the next handler', function() {
|
||||
before(function() {
|
||||
app = server.setup({
|
||||
limits: {fileSize: 200 * 1024} // set 200kb upload limit
|
||||
});
|
||||
});
|
||||
|
||||
it(`fail when uploading 'car.png' (~269kb) with 200kb size limit`, function(done) {
|
||||
let filePath = path.join(fileDir, 'car.png');
|
||||
|
||||
request(app)
|
||||
.post('/upload/single/truncated')
|
||||
.attach('testFile', filePath)
|
||||
.expect(400)
|
||||
.end(function(err, res) {
|
||||
assert.ok(res.error.text === 'File too big');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
128
node_modules/express-fileupload/test/isEligibleRequest.spec.js
generated
vendored
Normal file
128
node_modules/express-fileupload/test/isEligibleRequest.spec.js
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const isEligibleRequest = require('../lib/isEligibleRequest');
|
||||
|
||||
describe('isEligibleRequest function tests', () => {
|
||||
it('should return true if the request method is POST & headers set', () => {
|
||||
const req = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-length': '768751',
|
||||
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryz2D47BnVMA7w5N36'
|
||||
}
|
||||
};
|
||||
const result = isEligibleRequest(req);
|
||||
assert.equal(result, true);
|
||||
});
|
||||
it('should return true if the request method is PUT & headers set', () => {
|
||||
const req = {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'content-length': '768751',
|
||||
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryz2D47BnVMA7w5N36'
|
||||
}
|
||||
};
|
||||
const result = isEligibleRequest(req);
|
||||
assert.equal(result, true);
|
||||
});
|
||||
it('should return true if the request method is PATCH & headers set', () => {
|
||||
const req = {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'content-length': '768751',
|
||||
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryz2D47BnVMA7w5N36'
|
||||
}
|
||||
};
|
||||
const result = isEligibleRequest(req);
|
||||
assert.equal(result, true);
|
||||
});
|
||||
it('should return false if the request method is POST & content length 0', () => {
|
||||
const req = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-length': '0',
|
||||
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryz2D47BnVMA7w5N36'
|
||||
}
|
||||
};
|
||||
const result = isEligibleRequest(req);
|
||||
assert.equal(result, false);
|
||||
});
|
||||
it('should return false if the request method is POST & no content-length', () => {
|
||||
const req = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryz2D47BnVMA7w5N36'
|
||||
}
|
||||
};
|
||||
const result = isEligibleRequest(req);
|
||||
assert.equal(result, false);
|
||||
});
|
||||
it('should return false if the request method is POST & no boundary', () => {
|
||||
const req = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-length': '768751',
|
||||
'content-type': 'multipart/form-data; ----WebKitFormBoundaryz2D47BnVMA7w5N36'
|
||||
}
|
||||
};
|
||||
const result = isEligibleRequest(req);
|
||||
assert.equal(result, false);
|
||||
});
|
||||
it('should return false if the request method is not POST, PUT or PATCH', () => {
|
||||
const req = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'content-length': '768751',
|
||||
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryz2D47BnVMA7w5N36'
|
||||
}
|
||||
};
|
||||
const result = isEligibleRequest(req);
|
||||
assert.equal(result, false);
|
||||
});
|
||||
it('should return false if the request method is not POST, PUT or PATCH', () => {
|
||||
const req = {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'content-length': '768751',
|
||||
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryz2D47BnVMA7w5N36'
|
||||
}
|
||||
};
|
||||
const result = isEligibleRequest(req);
|
||||
assert.equal(result, false);
|
||||
});
|
||||
it('should return false if the request method is not POST, PUT or PATCH', () => {
|
||||
const req = {
|
||||
method: 'OPTIONS',
|
||||
headers: {
|
||||
'content-length': '768751',
|
||||
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryz2D47BnVMA7w5N36'
|
||||
}
|
||||
};
|
||||
const result = isEligibleRequest(req);
|
||||
assert.equal(result, false);
|
||||
});
|
||||
it('should return false if the request method is not POST, PUT or PATCH', () => {
|
||||
const req = {
|
||||
method: 'HEAD',
|
||||
headers: {
|
||||
'content-length': '768751',
|
||||
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryz2D47BnVMA7w5N36'
|
||||
}
|
||||
};
|
||||
const result = isEligibleRequest(req);
|
||||
assert.equal(result, false);
|
||||
});
|
||||
it('should return false if the request is empty or not provided', () => {
|
||||
const result = isEligibleRequest();
|
||||
assert.equal(result, false);
|
||||
});
|
||||
it('should return false if content-type is not specified.', () => {
|
||||
const req = {
|
||||
method: 'POST',
|
||||
headers: { 'content-length': '768751' }
|
||||
};
|
||||
const result = isEligibleRequest(req);
|
||||
assert.equal(result, false);
|
||||
});
|
||||
});
|
||||
85
node_modules/express-fileupload/test/multipartFields.spec.js
generated
vendored
Normal file
85
node_modules/express-fileupload/test/multipartFields.spec.js
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
'use strict';
|
||||
|
||||
const request = require('supertest');
|
||||
const server = require('./server');
|
||||
const app = server.setup();
|
||||
|
||||
let mockUser = {
|
||||
firstName: 'Joe',
|
||||
lastName: 'Schmo',
|
||||
email: 'joe@mailinator.com'
|
||||
};
|
||||
|
||||
let mockCars = [
|
||||
'rsx',
|
||||
'tsx',
|
||||
'civic',
|
||||
'integra'
|
||||
];
|
||||
|
||||
describe('multipartFields: Test Multipart Form Single Field Submissions', function() {
|
||||
it('submit multipart user data with POST', function(done) {
|
||||
request(app)
|
||||
.post('/fields/user')
|
||||
.field('firstName', mockUser.firstName)
|
||||
.field('lastName', mockUser.lastName)
|
||||
.field('email', mockUser.email)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, {
|
||||
firstName: mockUser.firstName,
|
||||
lastName: mockUser.lastName,
|
||||
email: mockUser.email
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('submit multipart user data with PUT', function(done) {
|
||||
request(app)
|
||||
.post('/fields/user')
|
||||
.field('firstName', mockUser.firstName)
|
||||
.field('lastName', mockUser.lastName)
|
||||
.field('email', mockUser.email)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, {
|
||||
firstName: mockUser.firstName,
|
||||
lastName: mockUser.lastName,
|
||||
email: mockUser.email
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('fail when user data submitted without multipart', function(done) {
|
||||
request(app)
|
||||
.post('/fields/user')
|
||||
.send(mockUser)
|
||||
.expect(400)
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('fail when user data not submitted', function(done) {
|
||||
request(app)
|
||||
.post('/fields/user')
|
||||
.expect(400)
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('multipartFields: Test Multipart Form Array Field Submissions', function() {
|
||||
it('submit array of data with POST', function(done) {
|
||||
let req = request(app).post('/fields/array');
|
||||
|
||||
for (let i = 0; i < mockCars.length; i++) {
|
||||
req.field('testField', mockCars[i]);
|
||||
}
|
||||
|
||||
req
|
||||
.expect(200)
|
||||
.end(function(err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
let responseMatchesRequest = res.body.join(',') === mockCars.join(',');
|
||||
|
||||
done(responseMatchesRequest ? null : 'Data was returned as expected.');
|
||||
});
|
||||
});
|
||||
});
|
||||
475
node_modules/express-fileupload/test/multipartUploads.spec.js
generated
vendored
Normal file
475
node_modules/express-fileupload/test/multipartUploads.spec.js
generated
vendored
Normal file
@@ -0,0 +1,475 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const md5 = require('md5');
|
||||
const path = require('path');
|
||||
const request = require('supertest');
|
||||
const server = require('./server');
|
||||
|
||||
const fileDir = server.fileDir;
|
||||
const tempDir = server.tempDir;
|
||||
const uploadDir = server.uploadDir;
|
||||
const clearTempDir = server.clearTempDir;
|
||||
const clearUploadsDir = server.clearUploadsDir;
|
||||
|
||||
const mockFiles = ['car.png', 'tree.png', 'basketball.png', 'emptyfile.txt'];
|
||||
|
||||
const mockUser = {
|
||||
firstName: 'Joe',
|
||||
lastName: 'Schmo',
|
||||
email: 'joe@mailinator.com'
|
||||
};
|
||||
|
||||
// Reset response body.uploadDir/uploadPath for testing.
|
||||
const resetBodyUploadData = (res) => {
|
||||
res.body.uploadDir = '';
|
||||
res.body.uploadPath = '';
|
||||
};
|
||||
|
||||
const genUploadResult = (fileName, filePath) => {
|
||||
const fileStat = fs.statSync(filePath);
|
||||
const fileBuffer = fs.readFileSync(filePath);
|
||||
return {
|
||||
name: fileName,
|
||||
md5: md5(fileBuffer),
|
||||
size: fileStat.size,
|
||||
uploadDir: '',
|
||||
uploadPath: ''
|
||||
};
|
||||
};
|
||||
|
||||
describe('multipartUploads: Test Directory Cleaning Method', function() {
|
||||
it('emptied "uploads" directory', function(done) {
|
||||
clearUploadsDir();
|
||||
const filesFound = fs.readdirSync(uploadDir).length;
|
||||
done(filesFound ? `Directory not empty. Found ${filesFound} files.` : null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('multipartUploads: Test Single File Upload', function() {
|
||||
const app = server.setup();
|
||||
|
||||
mockFiles.forEach((fileName) => {
|
||||
const filePath = path.join(fileDir, fileName);
|
||||
const uploadedFilePath = path.join(uploadDir, fileName);
|
||||
const result = genUploadResult(fileName, filePath);
|
||||
|
||||
it(`upload ${fileName} with POST`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single')
|
||||
.attach('testFile', filePath)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
|
||||
it(`upload ${fileName} with PUT`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single')
|
||||
.attach('testFile', filePath)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
});
|
||||
|
||||
it('fail when no files were attached', function(done) {
|
||||
request(app)
|
||||
.post('/upload/single')
|
||||
.expect(400)
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('fail when using GET', function(done) {
|
||||
request(app)
|
||||
.get('/upload/single')
|
||||
.attach('testFile', path.join(fileDir, mockFiles[0]))
|
||||
.expect(400)
|
||||
.end((err) => {
|
||||
// err.code === 'ECONNRESET' that means upload has been aborted.
|
||||
done(err && err.code !== 'ECONNRESET' ? err : null);
|
||||
});
|
||||
});
|
||||
|
||||
it('fail when using HEAD', function(done) {
|
||||
request(app)
|
||||
.head('/upload/single')
|
||||
.attach('testFile', path.join(fileDir, mockFiles[0]))
|
||||
.expect(400)
|
||||
.end((err) => {
|
||||
// err.code === 'ECONNRESET' that means upload has been aborted.
|
||||
done(err && err.code !== 'ECONNRESET' ? err : null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multipartUploads: Test Single File Upload w/ .mv()', function() {
|
||||
const app = server.setup();
|
||||
|
||||
mockFiles.forEach((fileName) => {
|
||||
const filePath = path.join(fileDir, fileName);
|
||||
const uploadedFilePath = path.join(uploadDir, fileName);
|
||||
const result = genUploadResult(fileName, filePath);
|
||||
|
||||
it(`upload ${fileName} with POST w/ .mv()`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single')
|
||||
.attach('testFile', filePath)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
|
||||
it(`upload ${fileName} with PUT w/ .mv()`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single')
|
||||
.attach('testFile', filePath)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multipartUploads: Test Single File Upload w/ useTempFiles option.', function() {
|
||||
const app = server.setup({ useTempFiles: true, tempFileDir: tempDir });
|
||||
|
||||
mockFiles.forEach((fileName) => {
|
||||
const filePath = path.join(fileDir, fileName);
|
||||
const uploadedFilePath = path.join(uploadDir, fileName);
|
||||
const result = genUploadResult(fileName, filePath);
|
||||
|
||||
it(`upload ${fileName} with POST`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single')
|
||||
.attach('testFile', filePath)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
|
||||
it(`upload ${fileName} with PUT`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single')
|
||||
.attach('testFile', filePath)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
});
|
||||
|
||||
it('fail when no files were attached', function(done) {
|
||||
request(app)
|
||||
.post('/upload/single')
|
||||
.expect(400)
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('fail when using GET', function(done) {
|
||||
request(app)
|
||||
.get('/upload/single')
|
||||
.attach('testFile', path.join(fileDir, mockFiles[0]))
|
||||
.expect(400)
|
||||
.end((err) => {
|
||||
// err.code === 'ECONNRESET' that means upload has been aborted.
|
||||
done(err && err.code !== 'ECONNRESET' ? err : null);
|
||||
});
|
||||
});
|
||||
|
||||
it('fail when using HEAD', function(done) {
|
||||
request(app)
|
||||
.head('/upload/single')
|
||||
.attach('testFile', path.join(fileDir, mockFiles[0]))
|
||||
.expect(400)
|
||||
.end((err) => {
|
||||
// err.code === 'ECONNRESET' that means upload has been aborted.
|
||||
done(err && err.code !== 'ECONNRESET' ? err : null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multipartUploads: Single File Upload w/ useTempFiles & empty tempFileDir.', function() {
|
||||
const app = server.setup({ useTempFiles: true, tempFileDir: '' });
|
||||
|
||||
mockFiles.forEach((fileName) => {
|
||||
const filePath = path.join(fileDir, fileName);
|
||||
const uploadedFilePath = path.join(uploadDir, fileName);
|
||||
const result = genUploadResult(fileName, filePath);
|
||||
|
||||
it(`upload ${fileName} with POST`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single')
|
||||
.attach('testFile', filePath)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multipartUploads: Test Single File Upload w/ .mv() Promise', function() {
|
||||
const app = server.setup();
|
||||
|
||||
mockFiles.forEach((fileName) => {
|
||||
const filePath = path.join(fileDir, fileName);
|
||||
const uploadedFilePath = path.join(uploadDir, fileName);
|
||||
const result = genUploadResult(fileName, filePath);
|
||||
|
||||
it(`upload ${fileName} with POST w/ .mv() Promise`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single/promise')
|
||||
.attach('testFile', filePath)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
|
||||
it(`upload ${fileName} with PUT w/ .mv() Promise`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single/promise')
|
||||
.attach('testFile', filePath)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
});
|
||||
|
||||
it('fail when no files were attached', function(done) {
|
||||
request(app)
|
||||
.post('/upload/single')
|
||||
.expect(400)
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('fail when using GET', function(done) {
|
||||
request(app)
|
||||
.get('/upload/single')
|
||||
.attach('testFile', path.join(fileDir, mockFiles[0]))
|
||||
.expect(400)
|
||||
.end((err) => {
|
||||
// err.code === 'ECONNRESET' that means upload has been aborted.
|
||||
done(err && err.code !== 'ECONNRESET' ? err : null);
|
||||
});
|
||||
});
|
||||
|
||||
it('fail when using HEAD', function(done) {
|
||||
request(app)
|
||||
.head('/upload/single')
|
||||
.attach('testFile', path.join(fileDir, mockFiles[0]))
|
||||
.expect(400)
|
||||
.end((err) => {
|
||||
// err.code === 'ECONNRESET' that means upload has been aborted.
|
||||
done(err && err.code !== 'ECONNRESET' ? err : null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multipartUploads: Test Single File Upload w/ .mv() Promise & useTempFiles', function() {
|
||||
const app = server.setup({ useTempFiles: true, tempFileDir: tempDir });
|
||||
|
||||
mockFiles.forEach((fileName) => {
|
||||
const filePath = path.join(fileDir, fileName);
|
||||
const uploadedFilePath = path.join(uploadDir, fileName);
|
||||
const result = genUploadResult(fileName, filePath);
|
||||
|
||||
it(`upload ${fileName} with POST w/ .mv() Promise`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single/promise')
|
||||
.attach('testFile', filePath)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
|
||||
it(`upload ${fileName} with PUT w/ .mv() Promise`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single/promise')
|
||||
.attach('testFile', filePath)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
});
|
||||
|
||||
it('fail when no files were attached', (done) => {
|
||||
request(app)
|
||||
.post('/upload/single')
|
||||
.expect(400)
|
||||
.end(done);
|
||||
});
|
||||
|
||||
it('fail when using GET', (done) => {
|
||||
request(app)
|
||||
.get('/upload/single')
|
||||
.attach('testFile', path.join(fileDir, mockFiles[0]))
|
||||
.expect(400)
|
||||
.end((err) => {
|
||||
// err.code === 'ECONNRESET' that means upload has been aborted.
|
||||
done(err && err.code !== 'ECONNRESET' ? err : null);
|
||||
});
|
||||
});
|
||||
|
||||
it('fail when using HEAD', (done) => {
|
||||
request(app)
|
||||
.head('/upload/single')
|
||||
.attach('testFile', path.join(fileDir, mockFiles[0]))
|
||||
.expect(400)
|
||||
.end((err) => {
|
||||
// err.code === 'ECONNRESET' that means upload has been aborted.
|
||||
done(err && err.code !== 'ECONNRESET' ? err : null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multipartUploads: Test Multi-File Upload', function() {
|
||||
const app = server.setup();
|
||||
|
||||
it('upload multiple files with POST', (done) => {
|
||||
clearUploadsDir();
|
||||
const req = request(app).post('/upload/multiple');
|
||||
const expectedResult = [];
|
||||
const expectedResultSorted = [];
|
||||
const uploadedFilesPath = [];
|
||||
mockFiles.forEach((fileName, index) => {
|
||||
const filePath = path.join(fileDir, fileName);
|
||||
req.attach(`testFile${index + 1}`, filePath);
|
||||
uploadedFilesPath.push(path.join(uploadDir, fileName));
|
||||
expectedResult.push(genUploadResult(fileName, filePath));
|
||||
});
|
||||
|
||||
req
|
||||
.expect((res) => {
|
||||
res.body.forEach((fileInfo) => {
|
||||
fileInfo.uploadDir = '';
|
||||
fileInfo.uploadPath = '';
|
||||
const index = mockFiles.indexOf(fileInfo.name);
|
||||
expectedResultSorted.push(expectedResult[index]);
|
||||
});
|
||||
})
|
||||
.expect(200, expectedResultSorted)
|
||||
.end((err) => {
|
||||
if (err) return done(err);
|
||||
fs.stat(uploadedFilesPath[0], (err) => {
|
||||
if (err) return done(err);
|
||||
fs.stat(uploadedFilesPath[1], (err) => {
|
||||
if (err) return done(err);
|
||||
fs.stat(uploadedFilesPath[2], done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multipartUploads: Test File Array Upload', function() {
|
||||
const app = server.setup();
|
||||
|
||||
it('upload array of files with POST', (done) => {
|
||||
clearUploadsDir();
|
||||
const req = request(app).post('/upload/array');
|
||||
const expectedResult = [];
|
||||
const expectedResultSorted = [];
|
||||
const uploadedFilesPath = [];
|
||||
mockFiles.forEach((fileName) => {
|
||||
const filePath = path.join(fileDir, fileName);
|
||||
uploadedFilesPath.push(path.join(uploadDir, fileName));
|
||||
expectedResult.push(genUploadResult(fileName, filePath));
|
||||
req.attach('testFiles', filePath);
|
||||
});
|
||||
|
||||
req
|
||||
.expect((res)=>{
|
||||
res.body.forEach((fileInfo) => {
|
||||
fileInfo.uploadDir = '';
|
||||
fileInfo.uploadPath = '';
|
||||
const index = mockFiles.indexOf(fileInfo.name);
|
||||
expectedResultSorted.push(expectedResult[index]);
|
||||
});
|
||||
})
|
||||
.expect(200, expectedResultSorted)
|
||||
.end((err) => {
|
||||
if (err) return done(err);
|
||||
uploadedFilesPath.forEach((uploadedFilePath) => {
|
||||
fs.statSync(uploadedFilePath);
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multipartUploads: Test Upload With Fields', function() {
|
||||
const app = server.setup();
|
||||
mockFiles.forEach((fileName) => {
|
||||
const filePath = path.join(fileDir, fileName);
|
||||
const uploadedFilePath = path.join(uploadDir, fileName);
|
||||
// Expected results
|
||||
const result = genUploadResult(fileName, filePath);
|
||||
result.firstName = mockUser.firstName;
|
||||
result.lastName = mockUser.lastName;
|
||||
result.email = mockUser.email;
|
||||
|
||||
it(`upload ${fileName} and submit fields at the same time with POST`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.post('/upload/single/withfields')
|
||||
.attach('testFile', filePath)
|
||||
.field('firstName', mockUser.firstName)
|
||||
.field('lastName', mockUser.lastName)
|
||||
.field('email', mockUser.email)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
|
||||
it(`upload ${fileName} and submit fields at the same time with PUT`, function(done) {
|
||||
clearUploadsDir();
|
||||
request(app)
|
||||
.put('/upload/single/withfields')
|
||||
.attach('testFile', filePath)
|
||||
.field('firstName', mockUser.firstName)
|
||||
.field('lastName', mockUser.lastName)
|
||||
.field('email', mockUser.email)
|
||||
.expect(resetBodyUploadData)
|
||||
.expect(200, result, err => (err ? done(err) : fs.stat(uploadedFilePath, done)));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multipartUploads: Test Aborting/Canceling during upload', function() {
|
||||
this.timeout(4000); // Set timeout for async tests.
|
||||
const uploadTimeout = 1000;
|
||||
|
||||
const app = server.setup({
|
||||
useTempFiles: true,
|
||||
tempFileDir: tempDir,
|
||||
debug: true,
|
||||
uploadTimeout
|
||||
});
|
||||
|
||||
clearTempDir();
|
||||
clearUploadsDir();
|
||||
mockFiles.forEach((fileName) => {
|
||||
const filePath = path.join(fileDir, fileName);
|
||||
|
||||
it(`Delete temp file if ${fileName} upload was aborted`, (done) => {
|
||||
const req = request(app)
|
||||
.post('/upload/single')
|
||||
.attach('testFile', filePath)
|
||||
.on('progress', (e) => {
|
||||
const progress = (e.loaded * 100) / e.total;
|
||||
// Aborting request, use req.req since it is original superagent request.
|
||||
if (progress > 50) req.req.abort();
|
||||
})
|
||||
.end((err) => {
|
||||
if (!err) return done(`Connection hasn't been aborted!`);
|
||||
if (err.code !== 'ECONNRESET') return done(err);
|
||||
// err.code === 'ECONNRESET' that means upload has been aborted.
|
||||
// Checking temp directory after upload timeout.
|
||||
setTimeout(() => {
|
||||
fs.readdir(tempDir, (err, files) => {
|
||||
if (err) return done(err);
|
||||
return files.length ? done(`Temporary directory contains files!`) : done();
|
||||
});
|
||||
}, uploadTimeout * 2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
219
node_modules/express-fileupload/test/options.spec.js
generated
vendored
Normal file
219
node_modules/express-fileupload/test/options.spec.js
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const request = require('supertest');
|
||||
const server = require('./server');
|
||||
const clearUploadsDir = server.clearUploadsDir;
|
||||
const fileDir = server.fileDir;
|
||||
const uploadDir = server.uploadDir;
|
||||
|
||||
describe('options: File Upload Options Tests', function() {
|
||||
afterEach(function(done) {
|
||||
clearUploadsDir();
|
||||
done();
|
||||
});
|
||||
|
||||
/**
|
||||
* Upload the file for testing and verify the expected filename.
|
||||
* @param {object} options The expressFileUpload options.
|
||||
* @param {string} actualFileNameToUpload The name of the file to upload.
|
||||
* @param {string} expectedFileNameOnFileSystem The name of the file after upload.
|
||||
* @param {function} done The mocha continuation function.
|
||||
*/
|
||||
function executeFileUploadTestWalk(options,
|
||||
actualFileNameToUpload,
|
||||
expectedFileNameOnFileSystem,
|
||||
done) {
|
||||
request(server.setup(options))
|
||||
.post('/upload/single')
|
||||
.attach('testFile', path.join(fileDir, actualFileNameToUpload))
|
||||
.expect(200)
|
||||
.end(function(err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
const uploadedFilePath = path.join(uploadDir, expectedFileNameOnFileSystem);
|
||||
|
||||
fs.stat(uploadedFilePath, done);
|
||||
});
|
||||
}
|
||||
|
||||
describe('Testing [safeFileNames] option to ensure:', function() {
|
||||
it('Does nothing to your filename when disabled.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: false};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'my$Invalid#fileName.png123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Is disabled by default.',
|
||||
function(done) {
|
||||
const fileUploadOptions = null;
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'my$Invalid#fileName.png123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Strips away all non-alphanumeric characters (excluding hyphens/underscores) when enabled.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileNamepng123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Accepts a regex for stripping (decidedly) "invalid" characters from filename.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: /[$#]/g};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileName.png123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Testing [preserveExtension] option to ensure:', function() {
|
||||
it('Does not preserve the extension of your filename when disabled.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true, preserveExtension: false};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileNamepng123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Is disabled by default.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileNamepng123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Shortens your extension to the default(3) when enabled, if the extension found is larger.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true, preserveExtension: true};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileNamepng.123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Leaves your extension alone when enabled, if the extension found is <= default(3) length',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true, preserveExtension: true};
|
||||
const actualFileName = 'car.png';
|
||||
const expectedFileName = 'car.png';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Can be configured for an extension length > default(3).',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true, preserveExtension: 7};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileName.png123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Can be configured for an extension length < default(3).',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true, preserveExtension: 2};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileNamepng1.23';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Will use the absolute value of your extension length when negative.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true, preserveExtension: -5};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileNamep.ng123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Will leave no extension when the extension length == 0.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true, preserveExtension: 0};
|
||||
const actualFileName = 'car.png';
|
||||
const expectedFileName = 'car';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Will accept numbers as strings, if they can be resolved with parseInt.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true, preserveExtension: '3'};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileNamepng.123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Will be evaluated for truthy-ness if it cannot be parsed as an int.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true, preserveExtension: 'not-a-#-but-truthy'};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileNamepng.123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Will ignore any decimal amount when evaluating for extension length.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true, preserveExtension: 4.98};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileNamepn.g123';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
|
||||
it('Only considers the last dotted part as the extension.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {safeFileNames: true, preserveExtension: true};
|
||||
const actualFileName = 'basket.ball.bp';
|
||||
const expectedFileName = 'basketball.bp';
|
||||
|
||||
executeFileUploadTestWalk(fileUploadOptions, actualFileName, expectedFileName, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Testing [parseNested] option to ensure:', function() {
|
||||
it('When [parseNested] is enabled result are nested', function(done){
|
||||
const app = server.setup({parseNested: true});
|
||||
request(app)
|
||||
.post('/fields/nested')
|
||||
.field('name', 'John')
|
||||
.field('hobbies[0]', 'Cinema')
|
||||
.field('hobbies[1]', 'Bike')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, {
|
||||
name: 'John',
|
||||
hobbies: ['Cinema', 'Bike']
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('When [parseNested] is disabled are flattened', function(done){
|
||||
const app = server.setup({parseNested: false});
|
||||
request(app)
|
||||
.post('/fields/flattened')
|
||||
.field('name', 'John')
|
||||
.field('hobbies[0]', 'Cinema')
|
||||
.field('hobbies[1]', 'Bike')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200, {
|
||||
name: 'John',
|
||||
'hobbies[0]': 'Cinema',
|
||||
'hobbies[1]': 'Bike'
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
5
node_modules/express-fileupload/test/posttests.js
generated
vendored
Normal file
5
node_modules/express-fileupload/test/posttests.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
const { clearFileDir } = require('./server');
|
||||
|
||||
console.log('clearing test files...');
|
||||
clearFileDir();
|
||||
console.log('done');
|
||||
5
node_modules/express-fileupload/test/pretests.js
generated
vendored
Normal file
5
node_modules/express-fileupload/test/pretests.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
const { createTestFiles } = require('./server');
|
||||
|
||||
console.log('creating test files...');
|
||||
createTestFiles()
|
||||
.then(() => console.log('done'));
|
||||
59
node_modules/express-fileupload/test/processNested.spec.js
generated
vendored
Normal file
59
node_modules/express-fileupload/test/processNested.spec.js
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const processNested = require('../lib/processNested');
|
||||
|
||||
describe('processNested: Test Convert Flatten object to Nested object', function() {
|
||||
it('With no nested data', () => {
|
||||
const data = {
|
||||
'firstname': 'John',
|
||||
'lastname': 'Doe',
|
||||
'age': 22
|
||||
},
|
||||
excerpt = { firstname: 'John', lastname: 'Doe', age: 22 },
|
||||
processed = processNested(data);
|
||||
|
||||
assert.deepEqual(processed, excerpt);
|
||||
});
|
||||
|
||||
it('With nested data', () => {
|
||||
const data = {
|
||||
'firstname': 'John',
|
||||
'lastname': 'Doe',
|
||||
'age': 22,
|
||||
'hobbies[0]': 'Cinema',
|
||||
'hobbies[1]': 'Bike',
|
||||
'address[line]': '78 Lynch Street',
|
||||
'address[city]': 'Milwaukee',
|
||||
'friends[0][name]': 'Jane',
|
||||
'friends[0][lastname]': 'Doe',
|
||||
'friends[1][name]': 'Joe',
|
||||
'friends[1][lastname]': 'Doe'
|
||||
},
|
||||
excerpt = {
|
||||
firstname: 'John',
|
||||
lastname: 'Doe',
|
||||
age: 22,
|
||||
hobbies: [ 'Cinema', 'Bike' ],
|
||||
address: { line: '78 Lynch Street', city: 'Milwaukee' },
|
||||
friends: [
|
||||
{ name: 'Jane', lastname: 'Doe' },
|
||||
{ name: 'Joe', lastname: 'Doe' }
|
||||
]
|
||||
},
|
||||
processed = processNested(data);
|
||||
|
||||
assert.deepEqual(processed, excerpt);
|
||||
});
|
||||
|
||||
it('Do not allow prototype pollution', () => {
|
||||
const pollutionOb1 = JSON.parse(`{"__proto__.POLLUTED1": "FOOBAR"}`);
|
||||
const pollutionOb2 = JSON.parse(`{"constructor.prototype.POLLUTED2": "FOOBAR"}`);
|
||||
|
||||
processNested(pollutionOb1);
|
||||
processNested(pollutionOb2);
|
||||
|
||||
assert.equal(global.POLLUTED1, undefined);
|
||||
assert.equal(global.POLLUTED2, undefined);
|
||||
});
|
||||
});
|
||||
295
node_modules/express-fileupload/test/server.js
generated
vendored
Normal file
295
node_modules/express-fileupload/test/server.js
generated
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const rimraf = require('rimraf');
|
||||
const randomFile = require('rnd-file');
|
||||
|
||||
const fileDir = path.join(__dirname, 'files');
|
||||
const tempDir = path.join(__dirname, 'temp');
|
||||
const uploadDir = path.join(__dirname, 'uploads');
|
||||
|
||||
const mockFiles = [
|
||||
{ name: 'emptyfile.txt', size: 0 },
|
||||
{ name: 'basket.ball.bp', size: 151 * 1024 },
|
||||
{ name: 'basketball.png', size: 151 * 1024 },
|
||||
{ name: 'car.png', size: 263 * 1024 },
|
||||
{ name: 'my$Invalid#fileName.png123', size: 263 * 1024 },
|
||||
{ name: 'tree.png', size: 266 * 1024 }
|
||||
];
|
||||
|
||||
const clearDir = (dir) => {
|
||||
try {
|
||||
try {
|
||||
const stats = fs.statSync(dir);
|
||||
if (stats.isDirectory()) rimraf.sync(dir);
|
||||
} catch (statsErr) {
|
||||
if (statsErr.code !== 'ENOENT') {
|
||||
throw statsErr;
|
||||
}
|
||||
}
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
} catch (err) {
|
||||
console.error(err); // eslint-disable-line
|
||||
}
|
||||
};
|
||||
|
||||
const createTestFiles = () => Promise.all(mockFiles.map((file) => {
|
||||
return randomFile({ filePath: fileDir, fileName: file.name, fileSize: file.size });
|
||||
}));
|
||||
|
||||
const getUploadedFileData = (file) => ({
|
||||
md5: file.md5,
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
uploadPath: path.join(uploadDir, file.name),
|
||||
uploadDir: uploadDir
|
||||
});
|
||||
|
||||
const setup = (fileUploadOptions) => {
|
||||
const express = require('express');
|
||||
const expressFileupload = require('../lib/index');
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(expressFileupload(fileUploadOptions || {}));
|
||||
|
||||
app.all('/upload/single', (req, res) => {
|
||||
if (!req.files) {
|
||||
return res.status(400).send('No files were uploaded.');
|
||||
}
|
||||
|
||||
const testFile = req.files.testFile;
|
||||
const fileData = getUploadedFileData(testFile);
|
||||
|
||||
testFile.mv(fileData.uploadPath, (err) => {
|
||||
if (err) {
|
||||
console.log('ERR', err); // eslint-disable-line
|
||||
return res.status(500).send(err);
|
||||
}
|
||||
res.json(fileData);
|
||||
});
|
||||
});
|
||||
|
||||
app.all('/upload/single/promise', (req, res) => {
|
||||
if (!req.files) {
|
||||
return res.status(400).send('No files were uploaded.');
|
||||
}
|
||||
|
||||
const testFile = req.files.testFile;
|
||||
const fileData = getUploadedFileData(testFile);
|
||||
|
||||
testFile
|
||||
.mv(fileData.uploadPath)
|
||||
.then(() => {
|
||||
res.json(fileData);
|
||||
})
|
||||
.catch(err => {
|
||||
res.status(500).send(err);
|
||||
});
|
||||
});
|
||||
|
||||
app.all('/upload/single/withfields', (req, res) => {
|
||||
if (!req.files) {
|
||||
return res.status(400).send('No files were uploaded.');
|
||||
}
|
||||
|
||||
if (!req.body) {
|
||||
return res.status(400).send('No request body found');
|
||||
}
|
||||
|
||||
const fields = ['firstName', 'lastName', 'email'];
|
||||
for (let i = 0; i < fields.length; i += 1) {
|
||||
if (!req.body[fields[i]] || !req.body[fields[i]].trim()) {
|
||||
return res.status(400).send(`Invalid field: ${fields[i]}`);
|
||||
}
|
||||
}
|
||||
|
||||
const testFile = req.files.testFile;
|
||||
const fileData = getUploadedFileData(testFile);
|
||||
fields.forEach((field) => { fileData[field] = req.body[field]; });
|
||||
|
||||
testFile.mv(fileData.uploadPath, (err) => {
|
||||
if (err) {
|
||||
return res.status(500).send(err);
|
||||
}
|
||||
res.json(fileData);
|
||||
});
|
||||
});
|
||||
|
||||
app.all('/upload/single/truncated', (req, res) => {
|
||||
if (!req.files) {
|
||||
return res.status(400).send('No files were uploaded.');
|
||||
}
|
||||
|
||||
// status 400 to differentiate from ending the request in the on limit
|
||||
return req.files.testFile.truncated
|
||||
? res.status(400).send(`File too big`)
|
||||
: res.status(200).send('Upload succeed');
|
||||
});
|
||||
|
||||
app.all('/upload/multiple', function(req, res) {
|
||||
if (!req.files) {
|
||||
return res.status(400).send('No files were uploaded.');
|
||||
}
|
||||
|
||||
const fileNames = ['testFile1', 'testFile2', 'testFile3'];
|
||||
|
||||
const testFiles = fileNames.map(file => req.files[file]);
|
||||
for (let i = 0; i < testFiles.length; i += 1) {
|
||||
if (!testFiles[i]) {
|
||||
return res.status(400).send(`${fileNames[i]} was not uploaded!`);
|
||||
}
|
||||
}
|
||||
|
||||
const filesData = testFiles.map(file => getUploadedFileData(file));
|
||||
|
||||
testFiles[0].mv(filesData[0].uploadPath, (err) => {
|
||||
if (err) {
|
||||
return res.status(500).send(err);
|
||||
}
|
||||
|
||||
testFiles[1].mv(filesData[1].uploadPath, (err) => {
|
||||
if (err) {
|
||||
return res.status(500).send(err);
|
||||
}
|
||||
|
||||
testFiles[2].mv(filesData[2].uploadPath, (err) => {
|
||||
if (err) {
|
||||
return res.status(500).send(err);
|
||||
}
|
||||
|
||||
res.json(filesData);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.all('/upload/array', function(req, res) {
|
||||
if (!req.files) {
|
||||
return res.status(400).send('No files were uploaded.');
|
||||
}
|
||||
|
||||
const testFiles = req.files.testFiles;
|
||||
|
||||
if (!testFiles) {
|
||||
return res.status(400).send('No files were uploaded');
|
||||
}
|
||||
|
||||
if (!Array.isArray(testFiles)) {
|
||||
return res.status(400).send('Files were not uploaded as an array');
|
||||
}
|
||||
|
||||
if (!testFiles.length) {
|
||||
return res.status(400).send('Files array is empty');
|
||||
}
|
||||
|
||||
const filesData = testFiles.map(file => getUploadedFileData(file));
|
||||
|
||||
let uploadCount = 0;
|
||||
for (let i = 0; i < testFiles.length; i += 1) {
|
||||
|
||||
testFiles[i].mv(filesData[i].uploadPath, (err) => {
|
||||
if (err) {
|
||||
return res.status(500).send(err);
|
||||
}
|
||||
|
||||
uploadCount += 1;
|
||||
if (uploadCount === testFiles.length) {
|
||||
res.json(filesData);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.all('/fields/user', function(req, res) {
|
||||
if (!req.body) {
|
||||
return res.status(400).send('No request body found');
|
||||
}
|
||||
|
||||
const fields = ['firstName', 'lastName', 'email'];
|
||||
for (let i = 0; i < fields.length; i += 1) {
|
||||
if (!req.body[fields[i]] || !req.body[fields[i]].trim()) {
|
||||
return res.status(400).send(`Invalid field: ${fields[i]}`);
|
||||
}
|
||||
}
|
||||
|
||||
res.json({
|
||||
firstName: req.body.firstName,
|
||||
lastName: req.body.lastName,
|
||||
email: req.body.email
|
||||
});
|
||||
});
|
||||
|
||||
app.all('/fields/nested', function(req, res) {
|
||||
if (!req.body) {
|
||||
return res.status(400).send('No request body found');
|
||||
}
|
||||
|
||||
if (!req.body.name || !req.body.name.trim()) {
|
||||
return res.status(400).send('Invalid name');
|
||||
}
|
||||
|
||||
if (!req.body.hobbies || !req.body.hobbies.length == 2) {
|
||||
return res.status(400).send('Invalid hobbies');
|
||||
}
|
||||
|
||||
res.json({
|
||||
name: req.body.name,
|
||||
hobbies: req.body.hobbies
|
||||
});
|
||||
});
|
||||
|
||||
app.all('/fields/flattened', function(req, res) {
|
||||
if (!req.body) {
|
||||
return res.status(400).send('No request body found');
|
||||
}
|
||||
|
||||
if (!req.body.name || !req.body.name.trim()) {
|
||||
return res.status(400).send('Invalid name');
|
||||
}
|
||||
|
||||
if (!req.body['hobbies[0]'] || !req.body['hobbies[0]'].trim()) {
|
||||
return res.status(400).send('Invalid hobbies[0]');
|
||||
}
|
||||
|
||||
if (!req.body['hobbies[1]'] || !req.body['hobbies[1]'].trim()) {
|
||||
return res.status(400).send('Invalid hobbies[1]');
|
||||
}
|
||||
|
||||
res.json({
|
||||
name: req.body.name,
|
||||
'hobbies[0]': req.body['hobbies[0]'],
|
||||
'hobbies[1]': req.body['hobbies[1]']
|
||||
});
|
||||
});
|
||||
|
||||
app.all('/fields/array', function(req, res) {
|
||||
if (!req.body) {
|
||||
return res.status(400).send('No request body found');
|
||||
}
|
||||
|
||||
if (!req.body.testField) {
|
||||
return res.status(400).send('Invalid field');
|
||||
}
|
||||
|
||||
if (!Array.isArray(req.body.testField)) {
|
||||
return res.status(400).send('Field is not an array');
|
||||
}
|
||||
|
||||
res.json(req.body.testField);
|
||||
});
|
||||
|
||||
return app;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
setup,
|
||||
fileDir,
|
||||
tempDir,
|
||||
uploadDir,
|
||||
clearFileDir: () => clearDir(fileDir),
|
||||
clearTempDir: () => clearDir(tempDir),
|
||||
clearUploadsDir: () => clearDir(uploadDir),
|
||||
createTestFiles
|
||||
};
|
||||
189
node_modules/express-fileupload/test/tempFile.spec.js
generated
vendored
Normal file
189
node_modules/express-fileupload/test/tempFile.spec.js
generated
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
const fs = require('fs');
|
||||
const md5 = require('md5');
|
||||
const path = require('path');
|
||||
const request = require('supertest');
|
||||
const server = require('./server');
|
||||
const assert = require('assert');
|
||||
const process = require('process');
|
||||
|
||||
const clearUploadsDir = server.clearUploadsDir;
|
||||
const fileDir = server.fileDir;
|
||||
const uploadDir = server.uploadDir;
|
||||
|
||||
const tempFileDir = '/tmp/';
|
||||
|
||||
/** Default permissions different for win32 and linux systems */
|
||||
const defaultFilePermissions = process.platform === 'win32' ? 0o666 : 0o644;
|
||||
|
||||
describe('tempFile: Test fileupload w/ useTempFiles.', function() {
|
||||
afterEach(function(done) {
|
||||
clearUploadsDir();
|
||||
done();
|
||||
});
|
||||
/**
|
||||
* Upload the file for testing and verify the expected filename.
|
||||
* @param {object} options The expressFileUpload options.
|
||||
* @param {string} actualFileNameToUpload The name of the file to upload.
|
||||
* @param {string} expectedFileNameOnFileSystem The name of the file after upload.
|
||||
* @param {function} done The mocha continuation function.
|
||||
*/
|
||||
function executeFileUploadTestWalk(
|
||||
options,
|
||||
actualFileNameToUpload,
|
||||
expectedFileNameOnFileSystem,
|
||||
done,
|
||||
expectedFilePermissions = defaultFilePermissions
|
||||
) {
|
||||
|
||||
let filePath = path.join(fileDir, actualFileNameToUpload);
|
||||
let fileBuffer = fs.readFileSync(filePath);
|
||||
let fileHash = md5(fileBuffer);
|
||||
let fileStat = fs.statSync(filePath);
|
||||
let uploadedFilePath = path.join(uploadDir, expectedFileNameOnFileSystem);
|
||||
|
||||
request(
|
||||
server.setup(options)
|
||||
)
|
||||
.post('/upload/single')
|
||||
.attach('testFile', filePath)
|
||||
.expect((res)=>{
|
||||
res.body.uploadDir = '';
|
||||
res.body.uploadPath = '';
|
||||
})
|
||||
.expect(200, {
|
||||
name: expectedFileNameOnFileSystem,
|
||||
md5: fileHash,
|
||||
size: fileStat.size,
|
||||
uploadDir: '',
|
||||
uploadPath: ''
|
||||
})
|
||||
.end(function(err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
fs.stat(uploadedFilePath, function(err, stats) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
assert.equal(stats.mode & 0o777, expectedFilePermissions);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
describe('Testing [safeFileNames w/ useTempFiles] option to ensure:', function() {
|
||||
it('Does nothing to your filename when disabled.', function(done) {
|
||||
const fileUploadOptions = {
|
||||
safeFileNames: false,
|
||||
useTempFiles: true,
|
||||
tempFileDir
|
||||
};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'my$Invalid#fileName.png123';
|
||||
executeFileUploadTestWalk(
|
||||
fileUploadOptions,
|
||||
actualFileName,
|
||||
expectedFileName,
|
||||
done
|
||||
);
|
||||
});
|
||||
it('Is disabled by default.', function(done) {
|
||||
const fileUploadOptions = {
|
||||
useTempFiles: true,
|
||||
tempFileDir
|
||||
};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'my$Invalid#fileName.png123';
|
||||
executeFileUploadTestWalk(
|
||||
fileUploadOptions,
|
||||
actualFileName,
|
||||
expectedFileName,
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it(
|
||||
'Strips away all non-alphanumeric characters (excluding hyphens/underscores) when enabled.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {
|
||||
safeFileNames: true,
|
||||
useTempFiles: true,
|
||||
tempFileDir
|
||||
};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileNamepng123';
|
||||
executeFileUploadTestWalk(
|
||||
fileUploadOptions,
|
||||
actualFileName,
|
||||
expectedFileName,
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it(
|
||||
'Accepts a regex for stripping (decidedly) "invalid" characters from filename.',
|
||||
function(done) {
|
||||
const fileUploadOptions = {
|
||||
safeFileNames: /[$#]/g,
|
||||
useTempFiles: true,
|
||||
tempFileDir
|
||||
};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'myInvalidfileName.png123';
|
||||
executeFileUploadTestWalk(
|
||||
fileUploadOptions,
|
||||
actualFileName,
|
||||
expectedFileName,
|
||||
done
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('Testing [tempFilePermissions w/ useTempFiles] option to ensure:', function() {
|
||||
it('Does nothing to your filename when disabled.', function(done) {
|
||||
const fileUploadOptions = {
|
||||
safeFileNames: false,
|
||||
useTempFiles: true,
|
||||
tempFileDir,
|
||||
tempFilePermissions: 0o666
|
||||
};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'my$Invalid#fileName.png123';
|
||||
executeFileUploadTestWalk(
|
||||
fileUploadOptions,
|
||||
actualFileName,
|
||||
expectedFileName,
|
||||
done
|
||||
);
|
||||
});
|
||||
it('Respects option boundaries when provided.', function(done) {
|
||||
const fileUploadOptions = {
|
||||
useTempFiles: true,
|
||||
tempFileDir,
|
||||
tempFilePermissions: 0o7777
|
||||
};
|
||||
const expressFileupload = require('../lib/index');
|
||||
assert.throws(function() {
|
||||
expressFileupload(fileUploadOptions);
|
||||
}, Error, 'File permissions out of bounds');
|
||||
done();
|
||||
});
|
||||
it('Applies permissions in filesystem.', function(done) {
|
||||
const fileUploadOptions = {
|
||||
useTempFiles: true,
|
||||
tempFileDir,
|
||||
tempFilePermissions: 0o600
|
||||
};
|
||||
const actualFileName = 'my$Invalid#fileName.png123';
|
||||
const expectedFileName = 'my$Invalid#fileName.png123';
|
||||
// Expected file perms after moving it to the destination folder depends on the platform.
|
||||
const expectedFilePermissions = process.platform === 'win32' ? 0o666 : 0o600;
|
||||
|
||||
executeFileUploadTestWalk(
|
||||
fileUploadOptions,
|
||||
actualFileName,
|
||||
expectedFileName,
|
||||
done,
|
||||
expectedFilePermissions
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
41
node_modules/express-fileupload/test/uploadtimer.spec.js
generated
vendored
Normal file
41
node_modules/express-fileupload/test/uploadtimer.spec.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const UploadTimer = require('../lib/uploadtimer');
|
||||
|
||||
describe('uploadTimer: Test UploadTimer class', () => {
|
||||
|
||||
it('It runs a callback function after specified timeout.', (done) => {
|
||||
const uploadTimer = new UploadTimer(500, done);
|
||||
uploadTimer.set();
|
||||
});
|
||||
|
||||
it('set method returns true if timeout specified.', () => {
|
||||
const uploadTimer = new UploadTimer(500);
|
||||
assert.equal(uploadTimer.set(), true);
|
||||
uploadTimer.clear();
|
||||
});
|
||||
|
||||
it('set method returns false if timeout has not specified.', () => {
|
||||
const uploadTimer = new UploadTimer();
|
||||
assert.equal(uploadTimer.set(), false);
|
||||
});
|
||||
|
||||
it('set method returns false if zero timeout has specified.', () => {
|
||||
const uploadTimer = new UploadTimer(0);
|
||||
assert.equal(uploadTimer.set(), false);
|
||||
});
|
||||
|
||||
it('set method returns false if timer allready set.', () => {
|
||||
const uploadTimer = new UploadTimer(500);
|
||||
uploadTimer.set();
|
||||
assert.equal(uploadTimer.set(), false);
|
||||
uploadTimer.clear();
|
||||
});
|
||||
|
||||
it('refresh method returns false if timer has not been set/initialized.', () => {
|
||||
const uploadTimer = new UploadTimer(500);
|
||||
assert.equal(uploadTimer.refresh(), false);
|
||||
});
|
||||
|
||||
});
|
||||
510
node_modules/express-fileupload/test/utilities.spec.js
generated
vendored
Normal file
510
node_modules/express-fileupload/test/utilities.spec.js
generated
vendored
Normal file
@@ -0,0 +1,510 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const md5 = require('md5');
|
||||
const server = require('./server');
|
||||
const fileDir = server.fileDir;
|
||||
const uploadDir = server.uploadDir;
|
||||
const {
|
||||
debugLog,
|
||||
isFunc,
|
||||
errorFunc,
|
||||
getTempFilename,
|
||||
buildOptions,
|
||||
buildFields,
|
||||
checkAndMakeDir,
|
||||
deleteFile,
|
||||
copyFile,
|
||||
moveFile,
|
||||
saveBufferToFile,
|
||||
parseFileName,
|
||||
uriDecodeFileName,
|
||||
isSafeFromPollution
|
||||
} = require('../lib/utilities');
|
||||
|
||||
const mockFile = 'basketball.png';
|
||||
const mockBuffer = fs.readFileSync(path.join(fileDir, mockFile));
|
||||
const mockHash = md5(mockBuffer);
|
||||
|
||||
const mockFileMove = 'car.png';
|
||||
const mockBufferMove = fs.readFileSync(path.join(fileDir, mockFileMove));
|
||||
const mockHashMove = md5(mockBufferMove);
|
||||
|
||||
describe('utilities: Test of the utilities functions', function() {
|
||||
//debugLog tests
|
||||
describe('Test debugLog function', () => {
|
||||
|
||||
let testMessage = 'Test message';
|
||||
|
||||
it('debugLog returns false if no options passed', () => {
|
||||
assert.equal(debugLog(null, testMessage), false);
|
||||
});
|
||||
|
||||
it('debugLog returns false if option debug is false or logger is not set', () => {
|
||||
assert.equal(debugLog({debug: false}, testMessage), false);
|
||||
assert.equal(debugLog({debug: true, logger: undefined}, testMessage), false);
|
||||
assert.equal(debugLog({debug: true, logger: {}}, testMessage), false);
|
||||
});
|
||||
|
||||
it('debugLog returns true if option debug is true and logger is set', () => {
|
||||
assert.equal(debugLog({debug: true, logger: console}, testMessage), true);
|
||||
});
|
||||
|
||||
it('supports a custom logger', () => {
|
||||
const calls = [];
|
||||
const logger = {
|
||||
log: (...args) => calls.push(args)
|
||||
};
|
||||
debugLog({debug: true, logger}, testMessage);
|
||||
assert.equal(calls.length, 1);
|
||||
assert.deepEqual(calls[0], [`Express-file-upload: ${testMessage}`]);
|
||||
});
|
||||
|
||||
});
|
||||
//isFunc tests
|
||||
describe('Test isFunc function', () => {
|
||||
|
||||
it('isFunc returns true if function passed', () => assert.equal(isFunc(()=>{}), true));
|
||||
|
||||
it('isFunc returns false if null passed', function() {
|
||||
assert.equal(isFunc(null), false);
|
||||
});
|
||||
|
||||
it('isFunc returns false if undefined passed', function() {
|
||||
assert.equal(isFunc(undefined), false);
|
||||
});
|
||||
|
||||
it('isFunc returns false if object passed', function() {
|
||||
assert.equal(isFunc({}), false);
|
||||
});
|
||||
|
||||
it('isFunc returns false if array passed', function() {
|
||||
assert.equal(isFunc([]), false);
|
||||
});
|
||||
});
|
||||
//errorFunc tests
|
||||
describe('Test errorFunc function', () => {
|
||||
|
||||
const resolve = () => 'success';
|
||||
const reject = () => 'error';
|
||||
|
||||
it('errorFunc returns resolve if reject function has not been passed', () => {
|
||||
let result = errorFunc(resolve);
|
||||
assert.equal(result(), 'success');
|
||||
});
|
||||
|
||||
it('errorFunc returns reject if reject function has been passed', () => {
|
||||
let result = errorFunc(resolve, reject);
|
||||
assert.equal(result(), 'error');
|
||||
});
|
||||
|
||||
});
|
||||
//getTempFilename tests
|
||||
describe('Test getTempFilename function', () => {
|
||||
|
||||
const nameRegexp = /tmp-\d{1,5}-\d{1,}/;
|
||||
|
||||
it('getTempFilename result matches regexp /tmp-d{1,5}-d{1,}/', () => {
|
||||
|
||||
let errCounter = 0;
|
||||
let tempName = '';
|
||||
for (var i = 0; i < 65537; i++) {
|
||||
tempName = getTempFilename();
|
||||
if (!nameRegexp.test(tempName)) errCounter ++;
|
||||
}
|
||||
|
||||
assert.equal(errCounter, 0);
|
||||
});
|
||||
|
||||
it('getTempFilename current and previous results are not equal', () => {
|
||||
|
||||
let errCounter = 0;
|
||||
let tempName = '';
|
||||
let previousName = '';
|
||||
for (var i = 0; i < 65537; i++) {
|
||||
previousName = tempName;
|
||||
tempName = getTempFilename();
|
||||
if (previousName === tempName) errCounter ++;
|
||||
}
|
||||
|
||||
assert.equal(errCounter, 0);
|
||||
});
|
||||
|
||||
});
|
||||
//parseFileName
|
||||
describe('Test parseFileName function', () => {
|
||||
|
||||
it('Does nothing to your filename when disabled.', () => {
|
||||
const opts = {safeFileNames: false};
|
||||
const name = 'my$Invalid#fileName.png123';
|
||||
const expected = 'my$Invalid#fileName.png123';
|
||||
let result = parseFileName(opts, name);
|
||||
assert.equal(result, expected);
|
||||
});
|
||||
|
||||
it('Cuts of file name length if it more then 255 chars.', () => {
|
||||
const name = 'a'.repeat(300);
|
||||
const result = parseFileName({}, name);
|
||||
assert.equal(result.length, 255);
|
||||
});
|
||||
|
||||
it(
|
||||
'Strips away all non-alphanumeric characters (excluding hyphens/underscores) when enabled.',
|
||||
() => {
|
||||
const opts = {safeFileNames: true};
|
||||
const name = 'my$Invalid#fileName.png123';
|
||||
const expected = 'myInvalidfileNamepng123';
|
||||
let result = parseFileName(opts, name);
|
||||
assert.equal(result, expected);
|
||||
});
|
||||
|
||||
it(
|
||||
'Strips away all non-alphanumeric chars when preserveExtension: true for a name without dots',
|
||||
() => {
|
||||
const opts = {safeFileNames: true, preserveExtension: true};
|
||||
const name = 'my$Invalid#fileName';
|
||||
const expected = 'myInvalidfileName';
|
||||
let result = parseFileName(opts, name);
|
||||
assert.equal(result, expected);
|
||||
});
|
||||
|
||||
it('Accepts a regex for stripping (decidedly) "invalid" characters from filename.', () => {
|
||||
const opts = {safeFileNames: /[$#]/g};
|
||||
const name = 'my$Invalid#fileName.png123';
|
||||
const expected = 'myInvalidfileName.png123';
|
||||
let result = parseFileName(opts, name);
|
||||
assert.equal(result, expected);
|
||||
});
|
||||
|
||||
it(
|
||||
'Returns correct filename if name contains dots characters and preserveExtension: true.',
|
||||
() => {
|
||||
const opts = {safeFileNames: true, preserveExtension: true};
|
||||
const name = 'basket.ball.png';
|
||||
const expected = 'basketball.png';
|
||||
let result = parseFileName(opts, name);
|
||||
assert.equal(result, expected);
|
||||
});
|
||||
|
||||
it('Returns a temporary file name if name argument is empty.', () => {
|
||||
const opts = {safeFileNames: false};
|
||||
const result = parseFileName(opts);
|
||||
assert.equal(typeof result, 'string');
|
||||
});
|
||||
|
||||
});
|
||||
//buildOptions tests
|
||||
describe('Test buildOptions function', () => {
|
||||
|
||||
const source = { option1: '1', option2: '2', hashAlgorithm: 'md5' };
|
||||
const sourceAddon = { option3: '3', hashAlgorithm: 'sha256'};
|
||||
const expected = { option1: '1', option2: '2', hashAlgorithm: 'md5' };
|
||||
const expectedAddon = { option1: '1', option2: '2', option3: '3', hashAlgorithm: 'sha256'};
|
||||
|
||||
it('buildOptions returns an equal object to the object which was passed', () => {
|
||||
let result = buildOptions(source);
|
||||
assert.deepStrictEqual(result, source);
|
||||
});
|
||||
|
||||
it('buildOptions doesnt add non object or null arguments to the result', () => {
|
||||
let result = buildOptions(source, 2, '3', null);
|
||||
assert.deepStrictEqual(result, expected);
|
||||
});
|
||||
|
||||
it('buildOptions adds value to the result from the several source arguments', () => {
|
||||
let result = buildOptions(source, sourceAddon);
|
||||
assert.deepStrictEqual(result, expectedAddon);
|
||||
});
|
||||
|
||||
it('buildOptions throws an error when not provided a supported hashAlgorithm', () => {
|
||||
assert.throws(() => buildOptions({}));
|
||||
});
|
||||
|
||||
it('buildOptions throws an error when given an unsupported hashAlgorithm', () => {
|
||||
assert.throws(() => buildOptions({ hashAlgorithm: 'not-actual-algo' }));
|
||||
});
|
||||
});
|
||||
//buildFields tests
|
||||
describe('Test buildFields function', () => {
|
||||
|
||||
it('buildFields does nothing if null value has been passed', () => {
|
||||
let fields = null;
|
||||
fields = buildFields(fields, 'test', null);
|
||||
assert.equal(fields, null);
|
||||
});
|
||||
|
||||
});
|
||||
//checkAndMakeDir tests
|
||||
describe('Test checkAndMakeDir function', () => {
|
||||
//
|
||||
it('checkAndMakeDir returns false if upload options object was not set', () => {
|
||||
assert.equal(checkAndMakeDir(), false);
|
||||
});
|
||||
//
|
||||
it('checkAndMakeDir returns false if upload option createParentPath was not set', () => {
|
||||
assert.equal(checkAndMakeDir({}), false);
|
||||
});
|
||||
//
|
||||
it('checkAndMakeDir returns false if filePath was not set', () => {
|
||||
assert.equal(checkAndMakeDir({createParentPath: true}), false);
|
||||
});
|
||||
//
|
||||
it('checkAndMakeDir return true if path to the file already exists', ()=>{
|
||||
let dir = path.join(uploadDir, 'testfile');
|
||||
assert.equal(checkAndMakeDir({createParentPath: true}, dir), true);
|
||||
});
|
||||
//
|
||||
it('checkAndMakeDir creates a dir if path to the file not exists', ()=>{
|
||||
let dir = path.join(uploadDir, 'testfolder', 'testfile');
|
||||
assert.equal(checkAndMakeDir({createParentPath: true}, dir), true);
|
||||
});
|
||||
//
|
||||
it('checkAndMakeDir creates a dir recursively if path to the file not exists', ()=>{
|
||||
let dir = path.join(uploadDir, 'testfolder', 'testsubfolder', 'testfile');
|
||||
assert.equal(checkAndMakeDir({createParentPath: true}, dir), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test moveFile function', function() {
|
||||
beforeEach(() => server.clearUploadsDir());
|
||||
|
||||
it('Should rename a file and check a hash', function(done) {
|
||||
const srcPath = path.join(fileDir, mockFileMove);
|
||||
const dstPath = path.join(uploadDir, mockFileMove);
|
||||
|
||||
moveFile(srcPath, dstPath, function(err, renamed) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
fs.stat(dstPath, (err) => {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
// Match source and destination files hash.
|
||||
const fileBuffer = fs.readFileSync(dstPath);
|
||||
const fileHash = md5(fileBuffer);
|
||||
if (fileHash !== mockHashMove) {
|
||||
return done(new Error('Hashes do not match'));
|
||||
}
|
||||
// Check that source file was deleted.
|
||||
fs.stat(srcPath, (err) => {
|
||||
if (err) {
|
||||
return done(renamed ? null : new Error('Source file was not renamed'));
|
||||
}
|
||||
done(new Error('Source file was not deleted'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
//saveBufferToFile tests
|
||||
describe('Test saveBufferToFile function', function(){
|
||||
beforeEach(() => server.clearUploadsDir());
|
||||
|
||||
it('Save buffer to a file', function(done) {
|
||||
let filePath = path.join(uploadDir, mockFile);
|
||||
saveBufferToFile(mockBuffer, filePath, function(err){
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
fs.stat(filePath, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('Failed if not a buffer passed', function(done) {
|
||||
let filePath = path.join(uploadDir, mockFile);
|
||||
saveBufferToFile(undefined, filePath, function(err){
|
||||
if (err) {
|
||||
return done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('Failed if wrong path passed', function(done) {
|
||||
let filePath = '';
|
||||
saveBufferToFile(mockFile, filePath, function(err){
|
||||
if (err) {
|
||||
return done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test deleteFile function', function(){
|
||||
beforeEach(() => server.clearUploadsDir());
|
||||
|
||||
it('Failed if nonexistent file passed', function(done){
|
||||
let filePath = path.join(uploadDir, getTempFilename());
|
||||
|
||||
deleteFile(filePath, function(err){
|
||||
if (err) {
|
||||
return done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('Delete a file', function(done){
|
||||
let srcPath = path.join(fileDir, mockFile);
|
||||
let dstPath = path.join(uploadDir, getTempFilename());
|
||||
// copy a file
|
||||
copyFile(srcPath, dstPath, function(err){
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
fs.stat(dstPath, (err)=>{
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
// delete a file
|
||||
deleteFile(dstPath, function(err){
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
fs.stat(dstPath, (err)=> {
|
||||
return err ? done() : done(new Error('File was not deleted'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Test copyFile function', function() {
|
||||
beforeEach(() => server.clearUploadsDir());
|
||||
|
||||
it('Copy a file and check a hash', function(done) {
|
||||
let srcPath = path.join(fileDir, mockFile);
|
||||
let dstPath = path.join(uploadDir, mockFile);
|
||||
|
||||
copyFile(srcPath, dstPath, function(err){
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
fs.stat(dstPath, (err)=>{
|
||||
if (err){
|
||||
return done(err);
|
||||
}
|
||||
// Match source and destination files hash.
|
||||
let fileBuffer = fs.readFileSync(dstPath);
|
||||
let fileHash = md5(fileBuffer);
|
||||
return fileHash === mockHash ? done() : done(new Error('Hashes do not match'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Failed if wrong source file path passed', function(done){
|
||||
let srcPath = path.join(fileDir, 'unknown');
|
||||
let dstPath = path.join(uploadDir, mockFile);
|
||||
|
||||
copyFile(srcPath, dstPath, function(err){
|
||||
if (err) {
|
||||
return done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('Failed if wrong destination file path passed', function(done){
|
||||
let srcPath = path.join(fileDir, 'unknown');
|
||||
let dstPath = path.join('unknown', 'unknown');
|
||||
|
||||
copyFile(srcPath, dstPath, function(err){
|
||||
if (err) {
|
||||
return done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test uriDecodeFileName function', function() {
|
||||
const testData = [
|
||||
{ enc: 'test%22filename', dec: 'test"filename' },
|
||||
{ enc: 'test%60filename', dec: 'test`filename' },
|
||||
{ enc: '%3Fx%3Dtest%22filename', dec: '?x=test"filename'},
|
||||
{ enc: 'bug_bounty_upload_%91%91and%92.txt', dec: 'bug_bounty_upload_and.txt'}
|
||||
];
|
||||
|
||||
// Test decoding if uriDecodeFileNames: true.
|
||||
testData.forEach((testName) => {
|
||||
const opts = { uriDecodeFileNames: true };
|
||||
it(`Return ${testName.dec} for input ${testName.enc} if uriDecodeFileNames: true`, () => {
|
||||
assert.equal(uriDecodeFileName(opts, testName.enc), testName.dec);
|
||||
});
|
||||
});
|
||||
|
||||
// Test decoding if uriDecodeFileNames: false.
|
||||
testData.forEach((testName) => {
|
||||
const opts = { uriDecodeFileNames: false };
|
||||
it(`Return ${testName.enc} for input ${testName.enc} if uriDecodeFileNames: false`, () => {
|
||||
assert.equal(uriDecodeFileName(opts, testName.enc), testName.enc);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test for no prototype pollution in buildFields', function() {
|
||||
const prototypeFields = [
|
||||
{ name: '__proto__', data: {} },
|
||||
{ name: 'constructor', data: {} },
|
||||
{ name: 'toString', data: {} }
|
||||
];
|
||||
|
||||
const nonPrototypeFields = [
|
||||
{ name: 'a', data: {} },
|
||||
{ name: 'b', data: {} }
|
||||
];
|
||||
|
||||
let fieldObject = undefined;
|
||||
[...prototypeFields, ...nonPrototypeFields].forEach((field) => {
|
||||
fieldObject = buildFields(fieldObject, field.name, field.data);
|
||||
});
|
||||
|
||||
it(`Has ${nonPrototypeFields.length} keys`, () => {
|
||||
assert.equal(Object.keys(fieldObject).length, nonPrototypeFields.length);
|
||||
});
|
||||
|
||||
it(`Has null as its prototype`, () => {
|
||||
assert.equal(Object.getPrototypeOf(fieldObject), null);
|
||||
});
|
||||
|
||||
prototypeFields.forEach((field) => {
|
||||
it(`${field.name} property is not an array`, () => {
|
||||
// Note, Array.isArray is an insufficient test due to it returning false
|
||||
// for Objects with an array prototype.
|
||||
assert.equal(fieldObject[field.name] instanceof Array, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test for correct detection of prototype pollution', function() {
|
||||
const validInsertions = [
|
||||
{ base: {}, key: 'a' },
|
||||
{ base: { a: 1 }, key: 'a' },
|
||||
{ base: { __proto__: { a: 1 } }, key: 'a' },
|
||||
{ base: [1], key: 0 },
|
||||
{ base: { __proto__: [1] }, key: 0 }
|
||||
];
|
||||
|
||||
const invalidInsertions = [
|
||||
{ base: {}, key: '__proto__' },
|
||||
{ base: {}, key: 'constructor' },
|
||||
{ base: [1], key: '__proto__' },
|
||||
{ base: [1], key: 'length' },
|
||||
{ base: { __proto__: [1] }, key: 'length' }
|
||||
];
|
||||
|
||||
validInsertions.forEach((insertion) => {
|
||||
it(`Key ${insertion.key} should be valid for ${JSON.stringify(insertion.base)}`, () => {
|
||||
assert.equal(isSafeFromPollution(insertion.base, insertion.key), true);
|
||||
});
|
||||
});
|
||||
|
||||
invalidInsertions.forEach((insertion) => {
|
||||
it(`Key ${insertion.key} should not be valid for ${JSON.stringify(insertion.base)}`, () => {
|
||||
assert.equal(isSafeFromPollution(insertion.base, insertion.key), false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user