Skip to content

Commit 96468ed

Browse files
committed
Add security cases.
1 parent b284f13 commit 96468ed

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

lib/handlers/resource-mapper.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ class ResourceMapper {
1717
const urlExtension = /(\.[^/.]+)?$/.exec(pathname)[0]
1818
const urlPath = pathname.substr(0, pathname.length - urlExtension.length)
1919

20+
// Sanity checks
21+
if (urlPath.indexOf('/..') >= 0) {
22+
throw new Error('Disallowed /.. segment in URL')
23+
}
24+
2025
// Map to the filename on disk, appending the extension of different from the URL
2126
const contentType = contentTypes && contentTypes[0] || ''
2227
const extension = contentType in extensions ? `.${extensions[contentType][0]}` : ''

test/unit/resource-mapper-test.js

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
const ResourceMapper = require('../../lib/handlers/resource-mapper')
2-
const { expect } = require('chai')
2+
const chai = require('chai')
3+
const { expect } = chai
4+
chai.use(require('chai-as-promised'))
35

46
describe('ResourceMapper', () => {
57
describe('A ResourceMapper instance for a single-user setup', () => {
@@ -31,12 +33,35 @@ describe('ResourceMapper', () => {
3133
createIfNotExists: true
3234
},
3335
{ path: `${rootPath}space/foo.exe$.html` })
36+
37+
// Security cases
38+
39+
itMapsUrl(mapper, 'a URL with an unknown content type',
40+
{
41+
url: 'http://localhost/space/foo.html',
42+
contentTypes: ['text/unknown'],
43+
createIfNotExists: true
44+
},
45+
{ path: `${rootPath}space/foo.html$` })
46+
47+
itMapsUrl(mapper, 'a URL with a /.. path segment',
48+
{
49+
url: 'http://localhost/space/../bar'
50+
},
51+
new Error('Disallowed /.. segment in URL'))
3452
})
3553
})
3654

3755
function itMapsUrl (mapper, label, options, expected) {
38-
it(`maps ${label}`, async () => {
39-
const actual = await mapper.mapUrlToFile(options)
40-
expect(actual).to.deep.equal(expected)
41-
})
56+
if (!(expected instanceof Error)) {
57+
it(`maps ${label}`, async () => {
58+
const actual = await mapper.mapUrlToFile(options)
59+
expect(actual).to.deep.equal(expected)
60+
})
61+
} else {
62+
it(`does not map ${label}`, async () => {
63+
const actual = mapper.mapUrlToFile(options)
64+
await expect(actual).to.be.rejectedWith(expected.message)
65+
})
66+
}
4267
}

0 commit comments

Comments
 (0)