Skip to content
This repository was archived by the owner on Mar 4, 2025. It is now read-only.

Commit 48f274c

Browse files
committed
Merge pull request #764 from appirio-tech/refactor-file-validation
Test file extension and mime types and add tests
2 parents 8cc8ad7 + da5e182 commit 48f274c

File tree

4 files changed

+102
-15
lines changed

4 files changed

+102
-15
lines changed

app/directives/tc-file-input/tc-file-input.directive.js

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import _ from 'lodash'
44
(function() {
55
'use strict'
66

7-
angular.module('tcUIComponents').directive('tcFileInput', ['$timeout', tcFileInput])
7+
angular.module('tcUIComponents').directive('tcFileInput', ['$timeout', 'Helpers', 'logger', tcFileInput])
88

9-
function tcFileInput($timeout) {
9+
function tcFileInput($timeout, Helpers, logger) {
1010
return {
1111
restrict: 'E',
1212
require: '^form',
@@ -26,14 +26,6 @@ import _ from 'lodash'
2626
scope.selectFile = selectFile
2727
var fileTypes = scope.fileType.split(',')
2828

29-
// Add extra checks for Windows zip file types
30-
var hasZip = _.some(fileTypes, _.matches('zip'))
31-
32-
if (hasZip) {
33-
fileTypes = angular.copy(fileTypes)
34-
fileTypes.push('x-zip', 'x-zip-compressed')
35-
}
36-
3729
// fieldId is not set on element at this point, so grabbing with class .none
3830
// which exists on the element right away
3931
var fileInput = $(element[0]).find('.none')
@@ -49,10 +41,16 @@ import _ from 'lodash'
4941
}
5042

5143
var fileSize = file.size
52-
var isAllowedFileSize = fileSize < '524288000'
44+
var fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
5345

54-
var selectedFileType = file.type.slice(file.type.lastIndexOf('/') + 1)
55-
var isAllowedFileFormat = _.some(fileTypes, _.matches(selectedFileType))
46+
var isAllowedFileSize = fileSize < '524288000'
47+
var isAllowedFileExt = _.some(fileTypes, _.matches(fileExtension))
48+
var isAllowedMIMEType = Helpers.isValidMIMEType(file.type, fileExtension)
49+
var isAllowedFileFormat = isAllowedFileExt && isAllowedMIMEType
50+
51+
if (file && !isAllowedFileFormat) {
52+
logger.error(`Invalid file. Allowed extensions: ${scope.fileType}. Recieved file extension ${fileExtension} with MIME type ${file.type} and file size ${fileSize}`)
53+
}
5654

5755
// Timeout needed for fixing IE bug ($apply already in progress)
5856
$timeout(function() {

app/directives/tc-file-input/tc-file-input.spec.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,28 @@ describe('Topcoder File Input Directive', function() {
161161
})
162162
})
163163

164+
describe('with a file extension that is not in the list of fileTypes given to the directive', function() {
165+
beforeEach(function() {
166+
fileList[0].name = 'submission.zip.jpg'
167+
168+
$(fileInput).triggerHandler({
169+
type: 'change',
170+
target: { files: fileList }
171+
})
172+
173+
$timeout.flush()
174+
})
175+
176+
it('does not call setFileReference', function() {
177+
expect(mockSetFileReference).not.calledOnce
178+
})
179+
180+
it('has ng-touched and ng-invalid-required classes', function() {
181+
expect($(fileInput).hasClass('ng-invalid-required')).to.be.true
182+
expect($(fileInput).hasClass('ng-touched')).to.be.true
183+
})
184+
})
185+
164186
describe('with a file that\'s greater than 500MB', function() {
165187
beforeEach(function() {
166188
fileList[0].size = 524288001

app/services/helpers.service.js

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import angular from 'angular'
2+
import _ from 'lodash'
23

34
(function() {
45
'use strict'
@@ -21,8 +22,8 @@ import angular from 'angular'
2122
redirectPostLogin: redirectPostLogin,
2223
getSocialUserData: getSocialUserData,
2324
setupLoginEventMetrics: setupLoginEventMetrics,
24-
npad: npad
25-
25+
npad: npad,
26+
isValidMIMEType: isValidMIMEType
2627
}
2728
return service
2829

@@ -297,5 +298,50 @@ import angular from 'angular'
297298
function npad(toPad, n) {
298299
return $filter('npad')(toPad, n)
299300
}
301+
302+
function isValidMIMEType(mimeType, fileExt) {
303+
var areStrings = _.isString(mimeType) && _.isString(fileExt)
304+
305+
if (!areStrings) {
306+
return false
307+
}
308+
309+
var mimeTypesByExtension = {
310+
zip: [
311+
'application/zip',
312+
'application/x-zip',
313+
'application/x-zip-compressed',
314+
'application/octet-stream',
315+
'application/x-compress',
316+
'application/x-compressed',
317+
'multipart/x-zip'
318+
],
319+
jpeg: [
320+
'image/jpeg',
321+
'image/jpg',
322+
'image/jpe_',
323+
'image/pjpeg',
324+
'image/vnd.swiftview-jpeg'
325+
],
326+
jpg: [
327+
'image/jpeg',
328+
'image/jpg',
329+
'image/jp_',
330+
'application/jpg',
331+
'application/x-jpg',
332+
'image/pjpeg',
333+
'image/pipeg',
334+
'image/vnd.swiftview-jpeg',
335+
'image/x-xbitmap'
336+
],
337+
png: [
338+
'image/png',
339+
'application/png',
340+
'application/x-png'
341+
]
342+
}
343+
344+
return _.some(mimeTypesByExtension[fileExt], _.matches(mimeType))
345+
}
300346
}
301347
})()

app/services/helpers.service.spec.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,4 +390,25 @@ describe('Helper Service', function() {
390390
expect($window._kmq[0][1]).to.exist.to.equal('mockuser')
391391
})
392392
})
393+
394+
describe('isValidMIMEType', function() {
395+
it('should return false for for non string arguments', function() {
396+
expect(Helpers.isValidMIMEType()).to.be.false
397+
expect(Helpers.isValidMIMEType(1, 'jpg')).to.be.false
398+
expect(Helpers.isValidMIMEType('application/zip', {})).to.be.false
399+
})
400+
401+
it('should return false for an unsupported file extension', function() {
402+
expect(Helpers.isValidMIMEType('application/zip', 'zip314')).to.be.false
403+
})
404+
405+
it('should return false for an unsupported MIME type', function() {
406+
expect(Helpers.isValidMIMEType('application/zip314', 'zip')).to.be.false
407+
})
408+
409+
it('should return true for valid MIME types and file extensions', function() {
410+
expect(Helpers.isValidMIMEType('application/zip', 'zip')).to.be.true
411+
expect(Helpers.isValidMIMEType('image/png', 'png')).to.be.true
412+
})
413+
})
393414
})

0 commit comments

Comments
 (0)