/** * TraCINg-Server - Gathering and visualizing cyber incidents on the world * * Copyright 2013 Matthias Gazzari, Annemarie Mattmann, André Wolski * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * This module defines a http server with a static webroot and a https server * cappable of receiving POST data. Additionally a socket.io listener provides * realtime connection between server and clients. */ // load node modules var http = require("http"); var https = require("https"); var statics = require("node-static"); // requires 'npm install node-static' var db = require("./db/database.js"); var utils = require("./utils.js"); var Router = require('router'); var url = require('url'); function handleError(code, message, response){ response.statusCode = code; response.setHeader('Content-Type', 'text/plain; charset=utf-8'); response.end(message + "\n"); } function start(postHandle, ioListener, config, options) { var fileServer, postReceiver, io, router, httpsRouter; router = Router(); router.get('/api/get_attacks', function(req, res){ var filter = {}; if(req.query.hasOwnProperty("country")){ filter["countries"] = [req.query.country]; } if(req.query.hasOwnProperty("latitude") && req.query.hasOwnProperty("longitude")){ filter["location"] = [parseFloat(req.query.longitude), parseFloat(req.query.latitude)]; if(req.query.hasOwnProperty("distance")){ filter["distance"] = parseInt(req.query.distance, 10); } } if(req.query.hasOwnProperty("start")){ filter["start"] = req.query.start; } if(req.query.hasOwnProperty("end")){ filter["end"] = req.query.end; } if(req.query.hasOwnProperty("page")){ filter["page"] = req.query.page; } res.setHeader('Content-Type', 'application/json; charset=utf-8'); db.requestAttacks(filter, function(err, data){ if(err){ res.statusCode = 404; res.end(); } else { res.end(JSON.stringify(data)); } }, {type: 'response', response: res}); }); // http request function onRequestHttp(request, response) { console.log("http request received."); request.query = url.parse(request.url, true).query; router(request, response, function(){ // try to serve files if nothing was matched fileServer.serve(request, response); }); } // https request (POST only, no routing) function onRequestHttps(request, response) { var postData = ""; //console.log("https request received."); var request_ip = request.headers['x-forwarded-for'] || request.connection.remoteAddress || request.socket.remoteAddress || request.connection.socket.remoteAddress; var authorized = request.client.authorized; var sensor = {}; var clientCert = request.connection.getPeerCertificate(); if(clientCert && clientCert.subject){ sensor["name"] = clientCert.subject.CN; sensor["type"] = clientCert.subject.O; if(clientCert.subject.OU){ sensor["type"] += " " + clientCert.subject.OU; } console.log("Sensor information retrieved from client certificate: ", sensor); } // receive POST data request.on("data", function(chunk) { postData += chunk; // prohibit too large POST data if(postData.length > 1e6) { response.writeHead(413, {"Content-Type": "text/plain"}); response.write("Request Entity Too Large"); response.end(); request.connection.destroy(); } }); // process received Data request.on("end", function() { if(request.url === "/sync"){ if (postData) { try { var data = JSON.parse(postData); db.getEntriesFromSyncInfo(data, function(error, data){ response.setHeader('Content-Type', 'application/json; charset=utf-8'); response.statusCode = 200; response.end(JSON.stringify(data)); }); } catch(e) { handleError(400, "Invalid json-data given", response); } } else { handleError(400, "No content given", response); } return; } postHandle(response, postData, authorized, sensor, io, request_ip); }); } db.connect(function() { // http Server var server = http.createServer(onRequestHttp).listen(config.httpPort); // file Server serving files from a specific folder fileServer = new (statics.Server)(config.webroot, {cache: 10, gzip: true}); // TODO remove cache time - test purpose // https Server postReceiver = https.createServer(options, onRequestHttps).listen(config.httpsPort); // io sockets listener (listens on same port as the http server) io = ioListener.listen(server); console.log("Server has started."); }); } exports.start = start;