Commit 4c3b570f authored by anton's avatar anton
Browse files

Sanitize asset file paths, add ASSETS_TYPES_WHITELIST env var, update CHANGELOG.md

parent 9f5928b0
Pipeline #112171 passed with stages
in 44 seconds
......@@ -7,9 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- `ASSETS_TYPES_WHITELIST` env variable to only allow certain
asset extensions to be accepted (e.g. `jpg,gif,mp4`).
### Fixed
- Broken handling of non-ASCII asset paths
- Uploaded asset paths break for certain characters
## [2.2.2] - 2021-03-16
......
......@@ -19,7 +19,8 @@
"accessKey": "ASSETS_ACCESS_KEY",
"secretKey": "ASSETS_SECRET_KEY"
},
"archivesBucket": "ASSETS_ARCHIVES_BUCKET"
"archivesBucket": "ASSETS_ARCHIVES_BUCKET",
"typesWhitelist": "ASSETS_TYPES_WHITELIST"
},
"resources": {
"mongodb": {
......
......@@ -19,7 +19,8 @@
"accessKey": null,
"secretKey": null
},
"archivesBucket": "piecemaker-archives"
"archivesBucket": "piecemaker-archives",
"typesWhitelist": null
},
"resources": {
"mongodb": {
......
......@@ -4464,6 +4464,14 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sanitize-filename": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
"integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==",
"requires": {
"truncate-utf8-bytes": "^1.0.0"
}
},
"saslprep": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
......@@ -5091,6 +5099,14 @@
"matchit": "^1.0.0"
}
},
"truncate-utf8-bytes": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
"integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=",
"requires": {
"utf8-byte-length": "^1.0.1"
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
......@@ -5192,6 +5208,11 @@
"punycode": "^2.1.0"
}
},
"utf8-byte-length": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
"integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
......
const
sanitizeFilename = require('sanitize-filename'),
getTokenFromHeaders = require('mbjs-generic-api/src/util/get-token-from-headers'),
getTokenFromQuery = require('mbjs-generic-api/src/util/get-token-from-query'),
Service = require('mbjs-generic-api/src/lib/service')
......@@ -131,7 +132,6 @@ class Assets extends Service {
_this = this,
os = require('os'),
path = require('path'),
{ ObjectUtil } = require('mbjs-utils'),
multer = require('multer'),
upload = multer({ dest: os.tmpdir() })
......@@ -141,6 +141,28 @@ class Assets extends Service {
/** Only allow if user bucket and owner */
if (req.params.bucket !== `user-${req.user.uuid}`) return this._errorResponse(res, 403)
/** Validation */
const
extname = path.extname(req.file.originalname),
sanitized = sanitizeFilename(path.basename(req.file.originalname, extname))
if (this.config.assets.typesWhitelist) {
const typesWhitelist = this.config.assets.typesWhitelist.split(',')
if (!typesWhitelist.includes(extname.toLowerCase().substr(1))) {
return _this._errorResponse(res, 400)
}
}
/** Sanitize input */
let filename = `${sanitized}${extname.toLowerCase()}`
if (req.body.basePath) {
const basePath = req.body.basePath.split('/')
.map(dir => sanitizeFilename(dir))
.filter(dir => dir && !!dir.length)
.join('/')
filename = path.join(basePath, filename)
}
/** Check if bucket exists */
const exists = await _this.minio.bucketExists(req.params.bucket)
......@@ -155,18 +177,6 @@ class Assets extends Service {
}
}
const
extname = path.extname(req.file.originalname),
slug = ObjectUtil.slug(path.basename(req.file.originalname, extname))
let filename = `${slug}${extname.toLowerCase()}`
if (req.body.basePath) {
const basePath = req.body.basePath.split('/')
.map(dir => ObjectUtil.slug(dir))
.join('/')
filename = path.join(basePath, filename)
}
/** Put object */
await _this.minio.fPutObject(
req.params.bucket,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment