Skip to content

Commit

Permalink
🐛 Fix SVG check for large files (#103)
Browse files Browse the repository at this point in the history
* Svg check for large files

* Big svg files will not have a complete first chunk to check for end tag in the svg, hence it is not possible to use isSvg.
* New test for the more common svg file type. That starts with an xml version and doctype.

* Fix svg file sizes

* Avoid quadratic regex

Co-authored-by: Linus Unnebäck <[email protected]>
  • Loading branch information
AnderbergE and LinusU authored Oct 14, 2021
1 parent 168eb90 commit 59609db
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.svg text eol=lf
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ build/Release
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules

# Generated test files
/test/files/test_generated.svg
28 changes: 21 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var crypto = require('crypto')
var stream = require('stream')
var fileType = require('file-type')
var isSvg = require('is-svg')
var htmlCommentRegex = require('html-comment-regex')
var parallel = require('run-parallel')

function staticValue (value) {
Expand All @@ -20,6 +20,21 @@ var defaultStorageClass = staticValue('STANDARD')
var defaultSSE = staticValue(null)
var defaultSSEKMS = staticValue(null)

// Regular expression to detect svg file content, inspired by: https://github.com/sindresorhus/is-svg/blob/master/index.js
// It is not always possible to check for an end tag if a file is very big. The firstChunk, see below, might not be the entire file.
var svgRegex = /^\s*(?:<\?xml[^>]*>\s*)?(?:<!doctype svg[^>]*>\s*)?<svg[^>]*>/i

function isSvg (svg) {
// Remove DTD entities
svg = svg.replace(/\s*<!Entity\s+\S*\s*(?:"|')[^"]+(?:"|')\s*>/img, '')
// Remove DTD markup declarations
svg = svg.replace(/\[?(?:\s*<![A-Z]+[^>]*>\s*)*\]?/g, '')
// Remove HTML comments
svg = svg.replace(htmlCommentRegex, '')

return svgRegex.test(svg)
}

function defaultKey (req, file, cb) {
crypto.randomBytes(16, function (err, raw) {
cb(err, err ? undefined : raw.toString('hex'))
Expand All @@ -29,14 +44,13 @@ function defaultKey (req, file, cb) {
function autoContentType (req, file, cb) {
file.stream.once('data', function (firstChunk) {
var type = fileType(firstChunk)
var mime
var mime = 'application/octet-stream' // default type

if (type) {
mime = type.mime
} else if (isSvg(firstChunk)) {
// Make sure to check xml-extension for svg files.
if ((!type || type.ext === 'xml') && isSvg(firstChunk.toString())) {
mime = 'image/svg+xml'
} else {
mime = 'application/octet-stream'
} else if (type) {
mime = type.mime
}

var outStream = new stream.PassThrough()
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"homepage": "https://github.com/badunk/multer-s3#readme",
"dependencies": {
"file-type": "^3.3.0",
"is-svg": "^2.1.0",
"html-comment-regex": "^1.1.2",
"run-parallel": "^1.1.6"
},
"devDependencies": {
Expand Down
63 changes: 62 additions & 1 deletion test/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ describe('Multer S3', function () {
})
})

it('uploads SVG file with correct content-type', function (done) {
it('uploads pure SVG file with correct content-type', function (done) {
var s3 = mockS3()
var form = new FormData()
var storage = multerS3({ s3: s3, bucket: 'test', serverSideEncryption: 'aws:kms', contentType: multerS3.AUTO_CONTENT_TYPE })
Expand Down Expand Up @@ -201,4 +201,65 @@ describe('Multer S3', function () {
done()
})
})

it('uploads common SVG file with correct content-type', function (done) {
var s3 = mockS3()
var form = new FormData()
var storage = multerS3({ s3: s3, bucket: 'test', serverSideEncryption: 'aws:kms', contentType: multerS3.AUTO_CONTENT_TYPE })
var upload = multer({ storage: storage })
var parser = upload.single('image')
var image = fs.createReadStream(path.join(__dirname, 'files', 'test2.svg'))

form.append('name', 'Multer')
form.append('image', image)

submitForm(parser, form, function (err, req) {
assert.ifError(err)

assert.equal(req.body.name, 'Multer')

assert.equal(req.file.fieldname, 'image')
assert.equal(req.file.contentType, 'image/svg+xml')
assert.equal(req.file.originalname, 'test2.svg')
assert.equal(req.file.size, 285)
assert.equal(req.file.bucket, 'test')
assert.equal(req.file.etag, 'mock-etag')
assert.equal(req.file.location, 'mock-location')
assert.equal(req.file.serverSideEncryption, 'aws:kms')

done()
})
})

it('uploads SVG file without quadratic regex', function (done) {
this.timeout('10s')

var s3 = mockS3()
var form = new FormData()
var storage = multerS3({ s3: s3, bucket: 'test', serverSideEncryption: 'aws:kms', contentType: multerS3.AUTO_CONTENT_TYPE })
var upload = multer({ storage: storage })
var parser = upload.single('image')
fs.writeFileSync(path.join(__dirname, 'files', 'test_generated.svg'), '<!doctype svg ' + ' '.repeat(34560))
var image = fs.createReadStream(path.join(__dirname, 'files', 'test_generated.svg'))

form.append('name', 'Multer')
form.append('image', image)

submitForm(parser, form, function (err, req) {
assert.ifError(err)

assert.equal(req.body.name, 'Multer')

assert.equal(req.file.fieldname, 'image')
assert.equal(req.file.contentType, 'application/octet-stream')
assert.equal(req.file.originalname, 'test_generated.svg')
assert.equal(req.file.size, 34574)
assert.equal(req.file.bucket, 'test')
assert.equal(req.file.etag, 'mock-etag')
assert.equal(req.file.location, 'mock-location')
assert.equal(req.file.serverSideEncryption, 'aws:kms')

done()
})
})
})
9 changes: 9 additions & 0 deletions test/files/test2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 59609db

Please sign in to comment.