[EDIT] FILE: express-fileupload.zip
PK ��M[A�.e e test/fileFactory.spec.jsnu ȯ�� '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('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(); }); }); }); }); PK ��M[����� � test/fileLimitUploads.spec.jsnu ȯ�� '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('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(done); }); }); 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){ if (err) 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(); }); }); }); }); PK ��M[St%LM9 M9 test/utilities.spec.jsnu ȯ�� '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, saveBufferToFile, parseFileName, uriDecodeFileName, isSafeFromPollution } = require('../lib/utilities'); const mockFile = 'basketball.png'; const mockBuffer = fs.readFileSync(path.join(fileDir, mockFile)); const mockHash = md5(mockBuffer); describe('Test of the utilities functions', function() { beforeEach(function() { server.clearUploadsDir(); }); //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', () => { assert.equal(debugLog({debug: false}, testMessage), false); }); it('debugLog returns true if option debug is true', () => { assert.equal(debugLog({debug: true}, testMessage), true); }); }); //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' }; const sourceAddon = { option3: '3'}; const expected = { option1: '1', option2: '2' }; const expectedAddon = { option1: '1', option2: '2', option3: '3'}; it('buildOptions returns and equal object to the object which was paased', () => { 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 argumets', () => { let result = buildOptions(source, sourceAddon); assert.deepStrictEqual(result, expectedAddon); }); }); //buildFields tests describe('Test buildOptions 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); }); }); //saveBufferToFile tests describe('Test saveBufferToFile function', function(){ beforeEach(function() { 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(function() { 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)=>{ if (err){ return done(); } //error if a file still exist done(err); }); }); }); }); }); }); describe('Test copyFile function', function(){ beforeEach(function() { 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(err); }); }); }); 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'} ]; // 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); }); }); }); }); PK ��M[�鿔 � test/processNested.spec.jsnu ȯ�� 'use strict'; const assert = require('assert'); const processNested = require('../lib/processNested'); describe('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); }); }); PK ��M[���>K[ K[ test/files/basket.ball.bpnu ȯ�� �PNG IHDR � � �WG� IDATx��w�Ź��wf�N��ӻ�jz't�i��M~77�7!�@ƴ� ��)� ����p/ǧ7�ݙ���VҮ�j�y^��#m�]�v���3�KP�B��1 x�t��6�/ �q$ �� �B��۽Z'h<6)��P��U~���uǍi �ʹl0�p�810 ��$���>Fĉ��8@f���@D��R ��R� ���R@�Ag@��Df@'ghѰ5d4&E�0�ScX��5Q�źㆡ�"�ʁ���'/�o.�|��t���`;�8�g?7�/��W� *�Z�:*T��;���2xe-�T�<#�=r�6�N�lia� i¿�_۾��iu!V�#�Ա���>F� �Eu�h�D>� � �(�L�x� %��} � @"���-@ ��,K��x��]��1pf-��W���ą�!�� D$�c]F�1)�]vs�U5�\�C�=f�Fbl��MbŊ~_�˾ށ��<����{����M�\=o�P`�B� �*T�P1!�����&��̈́�~An�[p��]�4�o���f�p#�]#� �!& �r�F���14 ��R!]��"���N $0��,�˔��e܄)}��{�~�&��6�i�KHIrh�$p'���D��q��̀�� fHRh${lchk�=�˥U�/��K�guմ���:����Ŀ�(�V�B�h*T�(��O;� VO����BgX��O��%��P��ab�g{}T?���Rnπ�.�� p��+�@+CH@� d�w&A ��1|-�%�D�,`M�a��o �){<��}��D���g:�K@B$@� HI$� H3y�Y�w�4.��%3�a]"c�7lPOK�}����q�aB5�/��C]�,�&r'enk�Ȁk*T�P �B� w���+��ւ��y�(_hc���]�:@rw�䄰.����a]L�p� ` P�%O�� ���,�d eDh�_ ��<S�Bd�9�s:��gW ��d۰�1�^'�A�IJh�9����s�5N����Ym)CJTi�ū�/y�}%�O�\ �`�l �)G_�`�|�����<��Q�B�h*T���͝ 4�s�_����l���)��HcW������q0I19�c ��c@�f�&cҜM7 !`$��҂d00K'@v�D�L.�(�H��R�����s�v<���s(#�]�1I $$!�y �$hV��~�n~�vwr�Dz��* +��c K� :]P�^����m� ����Z� �U�P1�C�`o| :d&�ze �CG��T���K0f���>qC�Wk����YjBT�:\Kf $� j̚�WI�D��3en�����ֹ�s�1e��]�����}Ys.%��>y�K��e}` ּ���l$`��N��~y��ՋW�}y��ȐvH�p%Xۗ��3!�,PU�P� Z� � ��Z �'����@z��ƙ�q�#�׀�{H)���V�Y2ZDti:W`�&�q��x�'C�yS#�b'�̖6do�5C[<{�:��Dy�g��p����ܰ�1`J��3�ބg׆�&J�dV��Ҋ�gU����+�Gtz7J�럆�+.x�su�uyX�_��n��Z� �U�P1�q+���4s5���0�&����A�^7�� �0���N;s.y�%4�_1Ȥ�ґ-�EA�����w]u�j�]������2Z���3��X8��5!�'�G=�uƓ�'���Oi�z�}�T>!D�Ӳ/����j�>��2�襎����}ps_�%��H��)�V�B�h*TT8$@7�~�4��@^��a~�I�#rpg]�a�������U� �BJDt �' @� b���Fa�Ki��9{�P�cJ{�a�� ��$���tF�D'�z��A��q���>]2@ �(�3�A ���Hl���;R�wb�x�������Үk��V�B�h*T���J��V�.�gvQ�'Nj����$� 9Wr6chf�#�D<�ƀ0!�1Gu� ���$���fI;�Qx�68Cx���;lx�X��|������"��z]���*�O����{R��$�_��w���:4�0�,�H��D�|��L��H\@�h7��8a &_��3���/�mP@�B� �*T�(:nؾW���rS����Ϙ8��?� �oD�~����c�3 &$b7L)�L9`����-\& ��������vLq̪�p��~�qs$�h Xr�d48�b"1Qګ�Ha @L���c]bP=��� ��}�|c����tw��e��s���ˇ *@�P�������s`|x� y�q�@\�q��0}�Æ�0 $���A��=%g�Yi��A�x�ί�1��8�EH`�z �y��>�� �@��O?k��Tui�h�k�DE)���XH3�.�%���؛R����zu`�;�E4����6<