Server: add npm run check to check CORS, bittorrent tracker...
authorChocobozzz <florian.bigard@gmail.com>
Fri, 21 Oct 2016 09:20:14 +0000 (11:20 +0200)
committerChocobozzz <florian.bigard@gmail.com>
Fri, 21 Oct 2016 09:20:14 +0000 (11:20 +0200)
package.json
scripts/check.js [new file with mode: 0755]
scripts/help.sh
server/controllers/api/v1/index.js

index 1111c7a6df3b113e9447772c12803947ec3bb5fa..8e2163bb2f7741c43a1063cc9ac3bc499f27c035 100644 (file)
@@ -5,7 +5,7 @@
   "private": true,
   "licence": "GPLv3",
   "engines": {
-    "node": ">=4.2.0"
+    "node": ">=4.x"
   },
   "author": {
     "name": "Florian Bigard",
@@ -30,6 +30,7 @@
     "play": "scripty",
     "dev": "scripty",
     "start": "node server",
+    "check": "scripty",
     "test": "scripty",
     "help": "scripty",
     "postinstall": "cd client && npm install"
@@ -90,5 +91,8 @@
       "describe",
       "include"
     ]
+  },
+  "scripty": {
+    "silent": true
   }
 }
diff --git a/scripts/check.js b/scripts/check.js
new file mode 100755 (executable)
index 0000000..5e9e4ca
--- /dev/null
@@ -0,0 +1,174 @@
+#!/bin/env node
+
+'use strict'
+
+const series = require('async/series')
+const request = require('request')
+const WebSocket = require('ws')
+
+const constants = require('../server/initializers/constants')
+const requestHeaders = {
+  'Range': '',
+  'Keep-Alive': '',
+  'User-Agent': 'Mozilla',
+  'Cache-Control': 'no-cache',
+  'Content-Type': '',
+  'Host': 'example.com',
+  'Access-Control-Request-Method': 'GET',
+  'Access-Control-Request-Headers': 'range'
+}
+
+series([
+  pingServer,
+  checkCORSTorrent,
+  checkCORSWebSeed,
+  checkTracker
+], function () {
+  process.exit(0)
+})
+
+// ---------------------------------------------------------------------------
+
+function pingServer (callback) {
+  const pingUrl = constants.CONFIG.WEBSERVER.URL + '/api/v1/ping'
+  console.log('Checking server is up (%s)...', pingUrl)
+
+  request(pingUrl, function (err, res, body) {
+    if (!err && res.statusCode === 200 && body === 'pong') {
+      console.log('SUCCESS.')
+    } else {
+      console.log('FAIL.')
+    }
+
+    callback()
+  })
+}
+
+function checkCORSTorrent (callback) {
+  const torrentUrl = constants.CONFIG.WEBSERVER.URL + '/static/torrents/test.torrent'
+  console.log('Checking CORS headers for the torrent (%s)...', torrentUrl)
+
+  request({
+    method: 'OPTIONS',
+    uri: torrentUrl,
+    headers: requestHeaders
+  }, function (err, res) {
+    if (err || isThereValidCORSHeaders(res) === false) {
+      console.error('FAIL.')
+    } else {
+      console.log('SUCCESS.')
+    }
+
+    callback()
+  })
+}
+
+function checkCORSWebSeed (callback) {
+  const webseedUrl = constants.CONFIG.WEBSERVER.URL + '/static/webseed/test.mp4'
+  console.log('Checking CORS headers for the video (%s)...', webseedUrl)
+
+  request({
+    method: 'OPTIONS',
+    uri: webseedUrl,
+    headers: requestHeaders
+  }, function (err, res) {
+    if (err || isThereValidCORSHeaders(res) === false) {
+      console.error('FAIL.')
+    } else {
+      console.log('SUCCESS.')
+    }
+
+    callback()
+  })
+}
+
+function checkTracker (callback) {
+  const trackerUrl = constants.CONFIG.WEBSERVER.WS + '://' +
+                     constants.CONFIG.WEBSERVER.HOST + ':' +
+                     constants.CONFIG.WEBSERVER.PORT + '/tracker/socket'
+  console.log('Checking tracker websocket (%s)...', trackerUrl)
+
+  let ws = null
+  ws = new WebSocket(trackerUrl)
+
+  const timeout = setTimeout(failed, 1000)
+  ws.on('open', onOpen)
+
+  function onOpen () {
+    clearTimeout(timeout)
+    ws.close()
+
+    console.log('SUCCESS.')
+    callback()
+  }
+
+  function failed () {
+    ws.removeListener('open', onOpen)
+    ws.close()
+
+    console.log('FAILED.')
+    callback()
+  }
+}
+
+function isThereValidCORSHeaders (res) {
+  let fail = false
+
+  // Check Access-Control-Allow-Origin
+  const headerAllowOriginKey = 'access-control-allow-origin'
+  const headerAllowOrigin = res.headers[headerAllowOriginKey]
+
+  if (!headerAllowOrigin) {
+    console.error(headerAllowOriginKey + ' is not present.')
+    fail = true
+  } else if (headerAllowOrigin !== '*') {
+    console.error(headerAllowOriginKey + ' does not equal "*".')
+    fail = true
+  }
+
+  // Check Access-Control-Allow-Methods
+  const headerAllowMethodsKey = 'access-control-allow-methods'
+  const headerAllowMethods = res.headers[headerAllowMethodsKey]
+  if (!headerAllowMethods) {
+    console.error(headerAllowMethodsKey + ' is not present.')
+    fail = true
+  } else {
+    const allowMethodsMissed = findPatternNotInString(headerAllowMethods, [ 'get' ])
+    if (allowMethodsMissed !== null) {
+      console.error(headerAllowMethodsKey + ' misses the ' + allowMethodsMissed + ' method.')
+      fail = true
+    }
+  }
+
+  // Check Access-Control-Allow-Headers
+  const headerAllowHeadersKey = 'access-control-allow-headers'
+  const headerAllowHeaders = res.headers[headerAllowHeadersKey]
+  if (!headerAllowHeaders) {
+    console.error(headerAllowHeadersKey + ' is not present.')
+    fail = true
+  } else {
+    const headersThatShouldBePresent = [
+      'Range'
+    ]
+    const allowHeadersMissed = findPatternNotInString(headerAllowHeaders, headersThatShouldBePresent)
+    if (allowHeadersMissed !== null) {
+      console.error(headerAllowHeadersKey + ' misses the ' + allowHeadersMissed + ' header.')
+      fail = true
+    }
+  }
+
+  return !fail
+}
+
+function findPatternNotInString (stringChain, patterns) {
+  let res = null
+  const stringChainLowerCase = stringChain.toLowerCase()
+
+  patterns.forEach(function (pattern) {
+    if (stringChainLowerCase.indexOf(pattern.toLowerCase()) === -1) {
+      res = pattern
+    }
+  })
+
+  return res
+}
index 6e124c276c7760506e15db334ce18beae7274181..fdccabbf016bc22ad3efed49f734670d11f05107 100755 (executable)
@@ -15,5 +15,6 @@ printf "  danger:clean:modules -> /!\ Clean node and typescript modules\n"
 printf "  play                 -> Run 3 fresh nodes so that you can test the communication between them\n"
 printf "  dev                  -> Watch, run the livereload and run the server so that you can develop the application\n"
 printf "  start                -> Run the server\n"
+printf "  check                -> Check the server (according to NODE_ENV)\n"
 printf "  test                 -> Run the tests\n"
 printf "  help                 -> Print this help\n"
index 2e4fb2dab5bebff8f09ce0b94a408c517341d6e0..4cb65ed55d0e7ba5ce297de4f88804a7aa8272c5 100644 (file)
@@ -17,6 +17,7 @@ router.use('/remote', remoteController)
 router.use('/requests', requestsController)
 router.use('/users', usersController)
 router.use('/videos', videosController)
+router.use('/ping', pong)
 router.use('/*', badRequest)
 
 // ---------------------------------------------------------------------------
@@ -25,6 +26,10 @@ module.exports = router
 
 // ---------------------------------------------------------------------------
 
+function pong (req, res, next) {
+  return res.send('pong').status(200).end()
+}
+
 function badRequest (req, res, next) {
   res.type('json').status(400).end()
 }