Select Git revision
index.test.js
index.test.js 11.02 KiB
const security = require('./index')
const express = require('express')
const superagent = require("superagent")
let app
let server
const mockReq = {
originalUrl: '/',
_setUrl: function (url) {
this.originalUrl = url
},
method: 'GET',
_setMethod: function(method) {
this.method = method
},
app: {
_router: {
stack: [{
route: {
path: '/'
}
}]
}
}
}
const mockRes = {
_headers: {
'X-Powered-By': 'my-server'
},
set: function(header, value) {
this._headers[header] = value
},
removeHeader: function(header) {
delete this._headers[header]
},
_status: 200,
status: function(status) {
this._status = status
return this
},
end: function() {
return undefined
}
}
describe('Unit Tests', () => {
beforeEach(() => {
mockRes._headers = { 'X-Powered-By': 'my-server'}
mockRes._status = 200
mockReq.originalUrl = '/'
mockReq.method = 'GET'
})
headerUnitTest('Cache-Control', 'CacheControl', 'no-cache, no-store, must-revalidate')
headerUnitTest('Pragma', 'Pragma', 'no-cache')
headerUnitTest('Expires', 'Expires', '0')
headerUnitTest('Content-Security-Policy', 'ContentSecurityPolicy', 'default-src \'self\'; frame-ancestors \'none\'')
headerUnitTest('X-XSS-Protection', 'XXSSProtection', '1; mode=block')
headerUnitTest('X-DNS-Prefetch-Control', 'XDNSPrefetchControl', 'off')
headerUnitTest('Expect-CT', 'ExpectCT', 'enforce; max-age=30; report-uri="/_report"')
headerUnitTest('X-Frame-Options', 'XFrameOptions', 'deny')
describe('Header: X-Powered-By', () => {
it('should remove Header if not defined', (done) => {
let sec = security()
sec(mockReq, mockRes, () => {
expect(mockRes._headers['X-Powered-By']).toBeUndefined()
done()
})
})
it('should not remove Header if set to false', (done) => {
let options = {}
options.XPoweredBy = false
let sec = security(options)
sec(mockReq, mockRes, () => {
expect(mockRes._headers['X-Powered-By']).toBeDefined()
done()
})
})
})
headerUnitTest('Strict-Transport-Security', 'StrictTransportSecurity', 'max-age=30')
headerUnitTest('X-Download-Options', 'XDownloadOptions', 'noopen')
headerUnitTest('X-Content-Type-Options', 'XContentTypeOptions', 'nosniff')
headerUnitTest('X-Permitted-Cross-Domain-Policies', 'XPermittedCrossDomainPolicies', 'none')
headerUnitTest('Referrer-Policy', 'ReferrerPolicy', 'no-referrer')
describe('Allowed Methods', () => {
it('should only allow GET, POST, PUT, DELETE on default', (done) => {
let sec = security()
mockReq._setMethod('GET')
sec(mockReq, mockRes, () => {
expect(mockRes._status).toBe(200)
mockReq._setMethod('HEAD')
sec(mockReq, mockRes, () => {
expect(mockRes._status).toBe(405)
done()
})
})
})
it('should allow given Methods', (done) => {
let sec = security({
allowedMethods: ['POST']
})
mockReq._setMethod('POST')
sec(mockReq, mockRes, () => {
expect(mockRes._status).toBe(200)
mockReq._setMethod('GET')
sec(mockReq, mockRes, () => {
expect(mockRes._status).toBe(405)
done()
})
})
})
})
describe('Defined Routes', () => {
it('should allow all routes by default', (done) => {
let sec = security()
mockReq._setUrl('/')
sec(mockReq, mockRes, () => {
expect(mockRes._status).toBe(200)
mockReq._setUrl('/test')
sec(mockReq, mockRes, () => {
expect(mockRes._status).toBe(200)
done()
})
})
})
it('should only allow defined routes if set to true', (done) => {
let sec = security({
onlyDefinedRoutes: true,
definedRoutes: ['/']
})
mockReq._setUrl('/')
sec(mockReq, mockRes, () => {
expect(mockRes._status).toBe(200)
mockReq._setUrl('/test')
sec(mockReq, mockRes, () => {
expect(mockRes._status).toBe(405)
done()
})
})
})
})
})
describe('Integration Tests', () => {
afterEach(() => {
server.close()
})
headerIntegrationTest('Cache-Control', 'CacheControl', 'no-cache, no-store, must-revalidate')
headerIntegrationTest('Pragma', 'Pragma', 'no-cache')
headerIntegrationTest('Expires', 'Expires', '0')
headerIntegrationTest('Content-Security-Policy', 'ContentSecurityPolicy', 'default-src \'self\'; frame-ancestors \'none\'')
headerIntegrationTest('X-XSS-Protection', 'XXSSProtection', '1; mode=block')
headerIntegrationTest('X-DNS-Prefetch-Control', 'XDNSPrefetchControl', 'off')
headerIntegrationTest('Expect-CT', 'ExpectCT', 'enforce; max-age=30; report-uri="/_report"')
headerIntegrationTest('X-Frame-Options', 'XFrameOptions', 'deny')
describe('Header: X-Powered-By', () => {
it('should remove Header if not defined', (done) => {
startUpServer({})
superagent
.get('http://127.0.0.1:7777')
.then(res => {
expect(res.status).toBe(200)
expect(res.headers['x-powered-by']).toBeUndefined()
done()
})
})
it('should not remove Header if set to false', (done) => {
startUpServer({
XPoweredBy: false
})
superagent
.get('http://127.0.0.1:7777')
.then(res => {
expect(res.status).toBe(200)
expect(res.headers['x-powered-by']).toBeDefined()
done()
})
})
})
headerIntegrationTest('Strict-Transport-Security', 'StrictTransportSecurity', 'max-age=30')
headerIntegrationTest('X-Download-Options', 'XDownloadOptions', 'noopen')
headerIntegrationTest('X-Content-Type-Options', 'XContentTypeOptions', 'nosniff')
headerIntegrationTest('X-Permitted-Cross-Domain-Policies', 'XPermittedCrossDomainPolicies', 'none')
headerIntegrationTest('Referrer-Policy', 'ReferrerPolicy', 'no-referrer')
describe('Allowed Methods', () => {
it('should only allow GET, POST, PUT, DELETE on default', (done) => {
startUpServer({})
superagent
.get('http://127.0.0.1:7777')
.then(res => {
expect(res.status).toBe(200)
superagent
.head('http://127.0.0.1:7777')
.then(res2 => {})
.catch((error) => {
expect(error.status).toBe(405)
done()
})
})
})
it('should allow given Methods', async () => {
startUpServer({
allowedMethods: ['POST']
})
const res = await superagent.post('http://127.0.0.1:7777').send({});
expect(res.status).toBe(200)
try {
const res2 = await superagent.get('http://127.0.0.1:7777');
} catch (error) {
expect(error.status).toBe(405)
}
})
})
describe('Defined Routes', () => {
it('should allow all routes by default', (done) => {
startUpServer({})
superagent
.get('http://127.0.0.1:7777')
.then(res => {
expect(res.status).toBe(200)
superagent
.get('http://127.0.0.1:7777/test')
.then(res2 => {
expect(res2.status).toBe(200)
done()
})
})
})
it('should only allow defined routes if set to true', (done) => {
startUpServer({
onlyDefinedRoutes: true,
definedRoutes: ['/']
})
superagent
.get('http://127.0.0.1:7777')
.then(res => {
expect(res.status).toBe(200)
superagent
.get('http://127.0.0.1:7777/test')
.then(res2 => {})
.catch((error) => {
expect(error.status).toBe(405)
done()
})
})
})
it('should not allow any routes if set to true but no routes given', (done) => {
startUpServer({
onlyDefinedRoutes: true
})
superagent
.get('http://127.0.0.1:7777')
.then(res => {
})
.catch((error) => {
expect(error.status).toBe(405)
done()
})
})
it('should allow regex route if set', (done) => {
startUpServer({
onlyDefinedRoutes: true,
definedRoutes: ['/', 'REGEX:\\/test\\/\\d{1,}']
})
superagent
.get('http://127.0.0.1:7777')
.then(res => {
expect(res.status).toBe(200)
superagent
.get('http://127.0.0.1:7777/test')
.then(res2 => {})
.catch((error) => {
expect(error.status).toBe(405)
superagent
.get('http://127.0.0.1:7777/test/123')
.then(res3 => {
expect(res3.status).toBe(200)
done()
})
})
})
})
})
})
function headerUnitTest (header, headerOption, defaultValue) {
describe('Header: ' + header, () => {
it('should set "' + defaultValue + '" if not defined', (done) => {
let sec = security()
sec(mockReq, mockRes, () => {
expect(mockRes._headers[header]).toBe(defaultValue)
done()
})
})
it('should not set Header if set to false', (done) => {
let options = {}
options[headerOption] = false
let sec = security(options)
sec(mockReq, mockRes, () => {
expect(mockRes._headers[header]).toBeUndefined()
done()
})
})
it('should set given values', (done) => {
let options = {}
options[headerOption] = 'somevalue'
let sec = security(options)
sec(mockReq, mockRes, () => {
expect(mockRes._headers[header]).toBe('somevalue')
done()
})
})
})
}
function headerIntegrationTest (header, headerOption, defaultValue) {
describe('Header: ' + header, () => {
it('should set "' + defaultValue + '" if not defined', (done) => {
startUpServer({})
superagent
.get('http://127.0.0.1:7777')
.then(res => {
expect(res.status).toBe(200)
expect(res.headers[header.toLowerCase()]).toBe(defaultValue)
done()
})
})
it('should not set Header if set to false', (done) => {
let options = {}
options[headerOption] = false
startUpServer(options)
superagent
.get('http://127.0.0.1:7777')
.then(res => {
expect(res.status).toBe(200)
expect(res.headers[header.toLowerCase()]).toBeUndefined()
done()
})
})
it('should set given values', (done) => {
let options = {}
options[headerOption] = 'somevalue'
startUpServer(options)
superagent
.get('http://127.0.0.1:7777')
.then(res => {
expect(res.status).toBe(200)
expect(res.headers[header.toLowerCase()]).toBe('somevalue')
done()
})
})
})
}
function startUpServer(options) {
app = express()
app.use(security(options))
app.get('/', function (req, res) {
res.send('Hello World!')
})
app.post('/', function (req, res) {
res.send('Some post')
})
app.get('/test', function (req, res) {
res.send('Hello Test!')
})
app.get('/test/123', function (req, res) {
res.send('Hello 123!')
})
server = app.listen(7777)
}