From 792b893ed414301c060391ed8a00368d68688236 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 21 Oct 2016 11:20:14 +0200 Subject: [PATCH] Server: add npm run check to check CORS, bittorrent tracker... --- package.json | 6 +- scripts/check.js | 174 +++++++++++++++++++++++++++++ scripts/help.sh | 1 + server/controllers/api/v1/index.js | 5 + 4 files changed, 185 insertions(+), 1 deletion(-) create mode 100755 scripts/check.js diff --git a/package.json b/package.json index 1111c7a6d..8e2163bb2 100644 --- a/package.json +++ b/package.json @@ -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 index 000000000..5e9e4cabf --- /dev/null +++ b/scripts/check.js @@ -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 +} diff --git a/scripts/help.sh b/scripts/help.sh index 6e124c276..fdccabbf0 100755 --- a/scripts/help.sh +++ b/scripts/help.sh @@ -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" diff --git a/server/controllers/api/v1/index.js b/server/controllers/api/v1/index.js index 2e4fb2dab..4cb65ed55 100644 --- a/server/controllers/api/v1/index.js +++ b/server/controllers/api/v1/index.js @@ -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() } -- 2.25.1