T3MP3ST public launch build
This commit is contained in:
1 parent
972247b881
commit
184c7d4e59
1589 files changed
+57150
-506
No files matched your search
@@ -0,0 +1,180 @@
|
||||
--- lib/index.js
|
||||
@@ -15,8 +15,8 @@ const internals = {};
|
||||
parameter = token "=" ( token / quoted-string )
|
||||
*/
|
||||
|
||||
-// 1: type/subtype 2: params
|
||||
-internals.contentTypeRegex = /^([^\/\s]+\/[^\s;]+)([ \t;][^\r\n]*)?$/;
|
||||
+// 1: type/subtype 2: params
|
||||
+internals.contentTypeRegex = /^([A-Za-z0-9!#$%&'*+.^_`|~-]+\/[A-Za-z0-9!#$%&'*+.^_`|~-]+)([ \t;][^\r\n]*)?$/;
|
||||
|
||||
// 1: "b" 2: b
|
||||
internals.charsetParamRegex = /;\s*charset=(?:"([^"]+)"|([^;"\s]+))/i;
|
||||
@@ -45,6 +45,10 @@ exports.type = function (header) {
|
||||
const param = params.match(internals.charsetParamRegex);
|
||||
if (param) {
|
||||
result.charset = (param[1] || param[2]).toLowerCase();
|
||||
+
|
||||
+ if (internals.charsetParamRegex.test(params.slice(param.index + param[0].length))) {
|
||||
+ throw Boom.badRequest('Invalid content-type header: duplicate parameter');
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +57,10 @@ exports.type = function (header) {
|
||||
const param = params.match(internals.boundaryParamRegex);
|
||||
if (param) {
|
||||
result.boundary = param[1] || param[2];
|
||||
+
|
||||
+ if (internals.boundaryParamRegex.test(params.slice(param.index + param[0].length))) {
|
||||
+ throw Boom.badRequest('Invalid content-type header: duplicate parameter');
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,12 +112,30 @@ exports.disposition = function (header) {
|
||||
}
|
||||
|
||||
const result = {};
|
||||
+ const extKeys = new Set();
|
||||
parameters.replace(internals.contentDispositionParamRegex, ($0, $1, $2, $3, $4, $5) => {
|
||||
|
||||
if ($1 === '__proto__') {
|
||||
throw Boom.badRequest('Invalid content-disposition header format includes invalid parameters');
|
||||
}
|
||||
|
||||
+ if (result[$1] !== undefined) {
|
||||
+ if ($2 && !extKeys.has($1)) {
|
||||
+ // ext-value overriding regular value - allowed per RFC 6266 Section 4.3
|
||||
+ }
|
||||
+ else if (!$2 && extKeys.has($1)) {
|
||||
+ // Regular value after ext-value - ignore (keep ext-value)
|
||||
+ return;
|
||||
+ }
|
||||
+ else {
|
||||
+ throw Boom.badRequest('Invalid content-disposition header format includes invalid parameters');
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if ($2) {
|
||||
+ extKeys.add($1);
|
||||
+ }
|
||||
+
|
||||
let value;
|
||||
|
||||
if ($2) {
|
||||
@@ -118,7 +144,7 @@ exports.disposition = function (header) {
|
||||
}
|
||||
|
||||
try {
|
||||
- value = decodeURIComponent($3.split('\'')[2]);
|
||||
+ value = decodeURIComponent($3.slice($3.indexOf('\'', $3.indexOf('\'') + 1) + 1));
|
||||
}
|
||||
catch (err) {
|
||||
throw Boom.badRequest('Invalid content-disposition header format includes invalid parameters');
|
||||
|
||||
--- test/index.js
|
||||
@@ -117,15 +117,15 @@ describe('type()', () => {
|
||||
|
||||
const header = `multipart/form-data ${new Array(80000).join(';boundary=#')}`;
|
||||
const now = Date.now();
|
||||
- Content.type(header);
|
||||
+ expect(() => Content.type(header)).to.throw('Invalid content-type header: duplicate parameter');
|
||||
expect(Date.now() - now).to.be.below(100);
|
||||
});
|
||||
|
||||
it('handles multiple charset params', () => {
|
||||
|
||||
const header = `text/plain ${new Array(80000).join(';charset=utf-8')}`;
|
||||
const now = Date.now();
|
||||
- Content.type(header);
|
||||
+ expect(() => Content.type(header)).to.throw('Invalid content-type header: duplicate parameter');
|
||||
expect(Date.now() - now).to.be.below(100);
|
||||
});
|
||||
|
||||
@@ -141,6 +141,26 @@ describe('type()', () => {
|
||||
|
||||
expect(() => Content.type('application/json\n; charset=utf-8')).to.throw('Invalid content-type header');
|
||||
});
|
||||
+
|
||||
+ it('errors on duplicate charset parameter', () => {
|
||||
+
|
||||
+ expect(() => Content.type('text/plain; charset=utf-8; charset=ascii')).to.throw('Invalid content-type header: duplicate parameter');
|
||||
+ });
|
||||
+
|
||||
+ it('errors on duplicate boundary parameter', () => {
|
||||
+
|
||||
+ expect(() => Content.type('multipart/form-data; boundary=abc; boundary=def')).to.throw('Invalid content-type header: duplicate parameter');
|
||||
+ });
|
||||
+
|
||||
+ it('errors on invalid token characters in type', () => {
|
||||
+
|
||||
+ expect(() => Content.type('text/html\x00')).to.throw('Invalid content-type header');
|
||||
+ });
|
||||
+
|
||||
+ it('errors on invalid token characters in subtype', () => {
|
||||
+
|
||||
+ expect(() => Content.type('text/<html>')).to.throw('Invalid content-type header');
|
||||
+ });
|
||||
});
|
||||
|
||||
describe('disposition()', () => {
|
||||
@@ -351,4 +371,58 @@ describe('disposition()', () => {
|
||||
const header = 'form-data; name="file"; filename="test.jpg" ';
|
||||
expect(Content.disposition(header)).to.equal({ name: 'file', filename: 'test.jpg' });
|
||||
});
|
||||
+
|
||||
+ it('errors on constructor param', () => {
|
||||
+
|
||||
+ const header = 'form-data; name="file"; constructor=test';
|
||||
+ expect(() => Content.disposition(header)).to.throw('Invalid content-disposition header format includes invalid parameters');
|
||||
+ });
|
||||
+
|
||||
+ it('errors on toString param', () => {
|
||||
+
|
||||
+ const header = 'form-data; name="file"; toString=test';
|
||||
+ expect(() => Content.disposition(header)).to.throw('Invalid content-disposition header format includes invalid parameters');
|
||||
+ });
|
||||
+
|
||||
+ it('handles single quote in ext-value', () => {
|
||||
+
|
||||
+ const header = 'form-data; name="file"; filename*=utf-8\'en\'it\'s%20here.php';
|
||||
+ expect(Content.disposition(header)).to.equal({ name: 'file', filename: 'it\'s here.php' });
|
||||
+ });
|
||||
+
|
||||
+ it('errors on duplicate parameter names', () => {
|
||||
+
|
||||
+ const header = 'form-data; name="file"; filename="safe.txt"; filename="shell.php"';
|
||||
+ expect(() => Content.disposition(header)).to.throw('Invalid content-disposition header format includes invalid parameters');
|
||||
+ });
|
||||
+
|
||||
+ it('allows ext-value to override filename parameter', () => {
|
||||
+
|
||||
+ const header = 'form-data; name="file"; filename="fallback.jpg"; filename*=utf-8\'\'extended.jpg';
|
||||
+ expect(Content.disposition(header)).to.equal({ name: 'file', filename: 'extended.jpg' });
|
||||
+ });
|
||||
+
|
||||
+ it('keeps ext-value when filename parameter follows', () => {
|
||||
+
|
||||
+ const header = 'form-data; name="file"; filename*=utf-8\'\'extended.jpg; filename="fallback.jpg"';
|
||||
+ expect(Content.disposition(header)).to.equal({ name: 'file', filename: 'extended.jpg' });
|
||||
+ });
|
||||
+
|
||||
+ it('errors on duplicate ext-value parameters', () => {
|
||||
+
|
||||
+ const header = 'form-data; name="file"; filename*=utf-8\'\'a.jpg; filename*=utf-8\'\'b.jpg';
|
||||
+ expect(() => Content.disposition(header)).to.throw('Invalid content-disposition header format includes invalid parameters');
|
||||
+ });
|
||||
+
|
||||
+ it('errors on duplicate even when ext-value override is present', () => {
|
||||
+
|
||||
+ const header = 'form-data; name="avatar"; name*=utf-8\'\'admin; filename="safe.txt"; filename="shell.php"';
|
||||
+ expect(() => Content.disposition(header)).to.throw('Invalid content-disposition header format includes invalid parameters');
|
||||
+ });
|
||||
+
|
||||
+ it('errors on duplicate name parameters', () => {
|
||||
+
|
||||
+ const header = 'form-data; name="avatar"; name="admin"';
|
||||
+ expect(() => Content.disposition(header)).to.throw('Invalid content-disposition header format includes invalid parameters');
|
||||
+ });
|
||||
});
|
||||
Reference in new issue
Block a user