Skip to content
Snippets Groups Projects
Select Git revision
  • d477b075037b1c1703c0d2deeb09860b3a3b43b6
  • main default protected
  • develop
  • 2.3.1
  • 2.3.0
  • 2.2.3
  • 2.2.2
7 results

index.test.js

Blame
  • 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)
    }