import * as series from 'async/series' import * as request from 'request' import * as WebSocket from 'ws' import { CONFIG } from '../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: () => void) { const pingUrl = 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: () => void) { const torrentUrl = 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: () => void) { const webseedUrl = 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: () => void) { const trackerUrl = CONFIG.WEBSERVER.WS + '://' + CONFIG.WEBSERVER.HOST + '/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: request.RequestResponse) { 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: string, patterns: string[]) { let res = null const stringChainLowerCase = stringChain.toLowerCase() patterns.forEach(function (pattern) { if (stringChainLowerCase.indexOf(pattern.toLowerCase()) === -1) { res = pattern } }) return res }