'use strict'; const fs = require('fs'); const http = require('http'); const https = require('https'); const strftime = require('strftime'); const net = require('net'); const CryptoJS = require('crypto-js'); const mime = require('mime-types'); var WTVNetworkSecurity = require('./wtvsec.js'); var zdebug = true; var pubip = "192.168.11.8"; var port = 1615; var sec_session = new Array(); function getWTVIncarnation(headers, ssid = null) { var incarnation = null; headers.some(function (v) { if (v.substring(0, 15) === "wtv-incarnation") { incarnation = v.split(': ')[1].replace("\r", ""); return incarnation != null; } }); if (ssid != null && incarnation != null) { if (sec_session[ssid] != null) { sec_session[ssid].set_incarnation(incarnation); if (zdebug) console.log(" * Updated wtv-incarnation for " + ssid + " to " + incarnation + " ..."); } } return incarnation; } function getWTVROMType(headers, ssid = null) { var romtype = null; headers.some(function (v) { if (v.substring(0, 19) === "wtv-client-rom-type") { romtype = v.split(': ')[1].replace("\r", ""); return romtype != null; } }); return romtype; } function getPublicIP() { var options = { host: 'www.planeptune.org', path: '/ip.php' } var request = https.get(options, function (res) { var data = ''; res.on('data', function (chunk) { data += chunk; }); res.on('end', function () { return data; }); }); } function doErrorPage(code) { var headers, data = null; switch (code) { case 404: data = "The resource you requested could not be found."; headers = "HTTP/1.1 404 Not Found\r\n"; headers += "Content-Type: text/html\r\n"; break; case 500: data = "An internal server error has occured."; headers = "HTTP/1.1 500 HackTV has ran into a technical problem.\r\n"; headers += "Content-Type: text/html\r\n"; break; default: data = "Hello, stranger!"; headers = "HTTP/1.1 200 OK\r\n"; headers += "Content-Type: text/html\r\n"; break; } return new Array(headers, data); } function processPath(path, initial_headers = new Array(), query = new Array()) { var headers, data = null; var request_is_direct_file = false; try { try { // try to see if the exact request exists if (fs.lstatSync(path).isFile()) { request_is_direct_file = true; } } catch (e) { // do nothing its fine } if (request_is_direct_file) { // file exists, read it and return it console.log(" * Found " + path + " to handle request"); var contype = mime.lookup(path); data = fs.readFileSync(path); headers = "200 OK\r\n" headers += "Content-Type: " + contype; } else if (fs.existsSync(path + ".txt")) { // raw text format, entire payload expected (headers and content) console.log(" * Found " + path + ".txt to handle request"); var fdat = fs.readFileSync(path + ".txt").toString(); headers = fdat.split("\r\n\r\n")[0]; data = fdat.split("\r\n\r\n")[1]; } else if (fs.existsSync(path + ".js")) { // js scripting, process with vars, must set 'headers' and 'data' appropriately. // loaded script will have r/w access to any JavaScript vars this function does. // any query args are in an array named 'query' console.log(" * Found " + path + ".js to handle request"); var fdat = fs.readFileSync(path + ".js").toString(); eval(fdat); } else if (fs.existsSync(path + ".html")) { // Standard HTML with no headers, WTV Style console.log(" * Found " + path + ".html to handle request"); data = fs.readFileSync(path + ".html").toString(); headers = "200 OK\r\n" headers += "Content-Type: text/html" } else { var errpage = doErrorPage(404); headers = errpage[0]; data = errpage[1]; } // 'headers' and 'data' should both be set with content by this point! if (headers != null) { if (typeof headers !== "string") { headers = headers.toString(); } if (headers.indexOf("\r") === -1) { headers = headers.replace("\n", "\r\n"); } } else { var errpage = doErrorPage(500); headers = errpage[0]; data = errpage[1]; } if (data === null) { data = ''; } if (typeof data !== "string") { data = data.toString(); } } catch (e) { var errpage = doErrorPage(500); headers = errpage[0]; data = errpage[1] + "

" + e.toString() + "
"; console.log(e); } if (headers.toLowerCase().indexOf("content-length") === -1) { headers += "\r\nContent-Length: " + data.length; } return new Array(headers, data); } function processURL(initial_headers, socket) { var shortURL, headers, data = ""; var query = new Array(); if (initial_headers['request_url'].indexOf('?') >= 0) { shortURL = initial_headers['request_url'].split('?')[0]; var qraw = initial_headers['request_url'].split('?')[1]; if (qraw.length > 0) { qraw = qraw.split("&"); for (let i = 0; i < qraw.length; i++) { query[qraw[i].split("=")[0]] = qraw[i].split("=")[1]; } if (zdebug) { console.log("URL Request has query arguments:") console.log(query); } } } else { shortURL = initial_headers['request_url']; } if (shortURL.indexOf(':/') >= 0) { var ssid = initial_headers['wtv-client-serial-number']; if (ssid != null) { console.log(" * Request for " + initial_headers['request_url'] + " from WebTV SSID " + ssid); } else { console.log(" * Request for " + initial_headers['request_url']); } // assume webtv since there is a :/ in the GET var urlToPath = __dirname + "/ServiceVault/" + shortURL.split(':/')[0] + "/" + shortURL.split(':/')[1]; if (zdebug) console.log(initial_headers); var result = processPath(urlToPath, initial_headers, query); if (result[0] == null) { var errpage = doErrorPage(404); headers = errpage[0]; data = errpage[1]; } else { headers = result[0]; data = result[1]; } } else { switch (shortURL) { default: var errpage = doErrorPage(200); headers = errpage[0]; data = errpage[1]; break; } } var toClient = headers + "\r\n\r\n" + data; console.log(headers); socket.write(toClient); socket.destroy(); } var server = net.createServer(function (socket) { socket.setEncoding("utf8"); //set data encoding (either 'ascii', 'utf8', or 'base64') socket.on('data', function (data) { var url = ""; var headers = new Array(); if (typeof data === "string") { data.split('\n').forEach(function (d) { if (d != "") { if (d == "SECURE ON") { headers['secure'] = true; } if (d.indexOf(": ") > 0) { headers[d.split(': ')[0]] = (d.split(': ')[1]).replace("\r",""); } else if (/^(GET |PUT |POST)$/.test(d.substring(0, 4))) { headers['request'] = d.replace("\r", ""); headers['request_url'] = (d.split(' ')[1]).replace("\r", ""); } } }); console.log(headers); if (headers['secure'] === true) { // assume we have an ssid if we are this far sec_session[headers['wtv-client-serial-number']].SecureOn(); if (!headers['request_url']) { headers['request_url'] = "wtv-head-waiter:/login-stage-two?"; } } processURL(headers,this); } }); }); server.listen(port, '0.0.0.0'); process.stdout.write("Looking up public IP address... "); //pubip = getPublicIP(); console.log(pubip + " ..."); console.log('Listening on port ' + port + ' for WebTV Units in Scriptless Mode');