diff --git a/README.md b/README.md index 5ac221f4..da4bd195 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,13 @@ This open source server is in alpha status. Use at your own risk. - Suports `.async.js` service files with asynchronous requests - Supports multiple simultaneous users - WebTV-compatible HTTP Proxy (via minisrv, or using an external proxy for enhanced features (such as [WebOne](https://github.com/atauenis/webone)) +- wtv-flashrom for LC2 and newer boxes (bf0app unsupported, need test unit) +- Can flash anything on [Ultra Willies](https://wtv.zefie.com/willie.php) with optional `use_zefie_server` flag set on `wtv-flashrom` service. ### Current issues: - May not run on non-development Windows machines (VS2019 with nodejs and python) - Power cycling box and re-connecting via ConnectSetup may invalidate encryption until server is restarted - wtv-update:/update does not yet function as intended -- wtv-flashrom features do not yet function as intended - HTTPS Proxying untested, likely needs SSL spoofing with self-signed solution ### Won't fix: @@ -26,7 +27,8 @@ This open source server is in alpha status. Use at your own risk. ### Feature Todo: - ~~(maybe) implement HTTP proxy (needs to be able to defluff most of the web, think retro WAP converter)~~ ***Done*** - ~~(maybe) enable "internet mode" (let user outside of minisrv)~~ ***Done*** -- Flashrom flashing functionality (at least for LC2 and higher) +- ~~Flashrom flashing functionality (at least for LC2 and higher)~~ ***Done*** +- Flashrom flashing for bf0app old classic (need donor unit) - SSID/IP black/whitelisting (including tying SSID to an IP or multiple IPs) - (maybe) Proper wtv-star (generic service outage page) support (maybe useful for allowing a unit to multiple sub-minisrvs). - (maybe) wtvchat stuff diff --git a/ServiceVault.md b/ServiceVault.md new file mode 100644 index 00000000..4b6d806f --- /dev/null +++ b/ServiceVault.md @@ -0,0 +1,33 @@ +## Brief ServiceVault Explanation + +The server will look for a subdirectory under the running directory, called `ServiceVault` (might be user-configurable in the future). + +Within that directory, it looks for a subdirectory named after the wtv-service URL requested. + +The server will then look for files in sequential order when requesting a URL, stopping at the first match. + +Let us use the URL `wtv-1800:/preregister` as an example. This is what the server would look for (in order): + +- `./ServiceVault/wtv-1800/preregister` \[ [Example](zefie_wtvp_minisrv/ServiceVault/wtv-star/images/HackTVLogo.gif) \] + - Exact file name match (*Direct File Mode*) + - Server sends the raw file, with its content-type. No parsing is done on the file. + - You do not need to do anything special with this format. +- `./ServiceVault/wtv-1800/preregister.txt` \[ [Example](zefie_wtvp_minisrv/ServiceVault/wtv-home/splash.txt) \] + - TXT file match (*Raw TXT Mode*) + - Service parses and sends AS-IS. + - You are expected to define headers +- `./ServiceVault/wtv-1800/preregister.js` \[ [Example](zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js) \] + - Synchronous JS match (*JS Interpreter mode*) + - Executes the JavaScript in synchronous mode. + - You are expected to define `headers` and `data` before the end of your script. + - Access Asynchronous mode by setting `request_is_async = true;` + - Client request headers are available as an Array in variable `request_headers`, query arguments are also an Array, in `request_headers.query` + - In Asynchronous mode, you are expected to call `sendToClient(socket,headers,data)` yourself, `socket` is already defined by the time your script runs, so you can just pass it through. +- `./ServiceVault/wtv-1800/preregister.html` \[ [Example](zefie_wtvp_minisrv/ServiceVault/wtv-home/zefie.html) \] + - HTML match (*HTML mode*) + - Like Direct File Mode, but you don't need to append `.html`. + - You do not need to do anything special with this format. + +The server will stop at the first result it finds using the order above. + +So if you have `preregister.txt` and `preregister.js`, it will use `preregister.txt`, but not `preregister.js`. diff --git a/zefie_wtvp_minisrv/.gitignore b/zefie_wtvp_minisrv/.gitignore index 6d6f8150..0dade07a 100644 --- a/zefie_wtvp_minisrv/.gitignore +++ b/zefie_wtvp_minisrv/.gitignore @@ -9,6 +9,7 @@ ServiceLogPost/*_* # Large files not pertaining to the service code ServiceVault/wtv-flashrom/content/* ServiceVault/wtv-music/content/* +ServiceVault/wtv-music/midi/* # User-specific files *.rsuser diff --git a/zefie_wtvp_minisrv/ServiceDeps/LC2/artemis_18004653537.tok b/zefie_wtvp_minisrv/ServiceDeps/premade_tellyscripts/LC2/LC2_HDD_artemis_18004653537.tok similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/LC2/artemis_18004653537.tok rename to zefie_wtvp_minisrv/ServiceDeps/premade_tellyscripts/LC2/LC2_HDD_artemis_18004653537.tok diff --git a/zefie_wtvp_minisrv/ServiceDeps/LC2/artemis_18006138199.tok b/zefie_wtvp_minisrv/ServiceDeps/premade_tellyscripts/LC2/LC2_HDD_artemis_18006138199.tok similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/LC2/artemis_18006138199.tok rename to zefie_wtvp_minisrv/ServiceDeps/premade_tellyscripts/LC2/LC2_HDD_artemis_18006138199.tok diff --git a/zefie_wtvp_minisrv/ServiceDeps/LC2/LC2_OISP_5555732_56k.tok b/zefie_wtvp_minisrv/ServiceDeps/premade_tellyscripts/LC2/LC2_OISP_5555732_56k.tok similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/LC2/LC2_OISP_5555732_56k.tok rename to zefie_wtvp_minisrv/ServiceDeps/premade_tellyscripts/LC2/LC2_OISP_5555732_56k.tok diff --git a/zefie_wtvp_minisrv/ServiceDeps/LC2/LC2_WTV_18006138199_56k.tok b/zefie_wtvp_minisrv/ServiceDeps/premade_tellyscripts/LC2/LC2_WTV_18006138199_56k.tok similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/LC2/LC2_WTV_18006138199_56k.tok rename to zefie_wtvp_minisrv/ServiceDeps/premade_tellyscripts/LC2/LC2_WTV_18006138199_56k.tok diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/finish-prereg.js b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/finish-prereg.js index 67275dd8..6d0706f3 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/finish-prereg.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/finish-prereg.js @@ -1,26 +1,40 @@ if (socket_session_data[socket.id].ssid != null && !getSessionData(socket_session_data[socket.id].ssid, 'wtvsec_login')) { var wtvsec_login = new WTVSec(); wtvsec_login.IssueChallenge(); - wtvsec_login.set_incarnation(request_headers['wtv-incarnation']); + wtvsec_login.set_incarnation(request_headers["wtv-incarnation"]); setSessionData(socket_session_data[socket.id].ssid, 'wtvsec_login', wtvsec_login) } else { var wtvsec_login = getSessionData(socket_session_data[socket.id].ssid, 'wtvsec_login') } -var contype = "text/tellyscript"; - -var skip_tellyscript = false; +var prereg_contype = "text/html"; // if relogin, skip tellyscript -if (query['relogin']) { - contype = "text/html"; // skip tellyscript +if (request_headers.query.relogin) { // skip tellyscript wtvsec_login.ticket_b64 = null; // clear old ticket } +// if relogin, skip tellyscript +var romtype, file_path = null; +if (!request_headers.query.relogin && services_configured.config.send_tellyscripts) { + var romtype = getSessionData(socket_session_data[socket.id].ssid, 'wtv-client-rom-type'); +} + +switch (romtype) { + case "US-LC2-disk-0MB-8MB": + prereg_contype = "text/tellyscript"; + var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/LC2/LC2_OISP_5555732_56k.tok"; + break; + + default: + data = ''; + break; +} + headers = `200 OK Connection: Keep-Alive wtv-initial-key: ` + wtvsec_login.challenge_key.toString(CryptoJS.enc.Base64) + ` -Content-Type: `+ contype + ` +Content-Type: `+ prereg_contype + ` wtv-service: reset ` + getServiceString('wtv-1800') + ` ` + getServiceString('wtv-star') + ` @@ -30,20 +44,16 @@ wtv-boot-url: wtv-1800:/preregister?relogin=true wtv-visit: wtv-head-waiter:/login? wtv-client-time-zone: GMT -0000 wtv-client-time-dst-rule: GMT -wtv-client-date: `+strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString()))+` GMT`; +wtv-client-date: `+ strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString())) + ` GMT`; -// if relogin, skip tellyscript -var romtype = null; -if (!query['relogin'] && skip_tellyscript == false) { - var romtype = getSessionData(socket_session_data[socket.id].ssid, 'wtv-client-rom-type'); -} - -switch (romtype) { - case "US-LC2-disk-0MB-8MB": - data = getFile("LC2/LC2_OISP_5555732_56k.tok", true); - break; - - default: - data = ''; - break; +if (file_path) { + request_is_async = true; + fs.readFile(file_path, null, function (err, file_read_data) { + if (err) { + var errmsg = doErrorCode(400); + headers = errmsg[0]; + file_read_data = errmsg[1] + "\n" + err.toString(); + } + sendToClient(socket, headers, file_read_data); + }); } \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js index bd9909f4..2885e20f 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js @@ -1,8 +1,8 @@ var gourl = "wtv-1800:/finish-prereg?"; -if (query['relogin']) gourl += "relogin=true"; +if (request_headers.query.relogin) gourl += "relogin=true"; -if (request_headers['wtv-ticket']) { +if (request_headers["wtv-ticket"]) { gourl = "wtv-head-waiter:/login-stage-two?"; } diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/ROMCache/HackTVLogoJewel.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/ROMCache/HackTVLogoJewel.gif new file mode 100644 index 00000000..07a0f4b8 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/ROMCache/HackTVLogoJewel.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js new file mode 100644 index 00000000..e9297a37 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js @@ -0,0 +1,74 @@ +request_is_async = true; + +var request_path = unescape(request_headers.query.path); +headers = "200 OK\n" + +if (request_headers.query.raw) { + if ((/\.brom$/).test(request_path)) headers += "Content-Type: binary/x-wtv-bootrom"; // maybe? + else headers += "Content-Type: binary/x-wtv-flashblock"; + if (services_configured.services[service_name].use_zefie_server) { + // get flashrom files from archive.midnightchannel.net + var options = { + host: "archive.midnightchannel.net", + path: "/zefie/files/wtv-flashrom/" + request_path, + timeout: 5000, + method: 'GET' + } + const req = https.request(options, function (res) { + var data_hex = ''; + res.setEncoding('hex'); + + res.on('data', d => { + data_hex += d; + }) + + res.on('end', function () { + if (!zquiet) console.log(` * Zefie's FlashROM Server HTTP Status: ${res.statusCode} ${res.statusMessage}`) + if (res.statusCode == 200) { + data = Buffer.from(data_hex, 'hex'); + } else if (res.statusCode == 404) { + var errpage = doErrorPage(404, "The service could not find the requested ROM on zefie's server.") + headers = errpage[0]; + data = errpage[1]; + } else { + var errpage = doErrorPage(400) + headers = errpage[0]; + data = errpage[1]; + } + sendToClient(socket, headers, data); + }); + }); + req.end(); + } else { + // use local flashrom files); + var flashrom_file_path = service_dir + '/' + request_path; + try { + fs.readFile(flashrom_file_path, null, function (err, data) { + if (err) { + errpage = doErrorPage(400) + headers = errpage[0]; + data = err.toString(); + } + sendToClient(socket, headers, data); + }); + } catch (e) { + var errpage = doErrorPage(404, "The service could not find the requested ROM.") + headers = errpage[0]; + data = errpage[1]; + sendToClient(socket, headers, data); + } + } +} else { + // no support for bf0app yet, but here we send the client to initiate-lc2-download + // to get the rom image + if (request_headers.query.path) { + headers += "Content-type: text/html\n" + headers += "wtv-visit: wtv-flashrom:/initiate-lc2-download?path=" + request_headers.query.path; + data = ''; + } else { + var errpage = doErrorPage(404) + headers = errpage[0]; + data = errpage[1]; + } + sendToClient(socket, headers, data); +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js index 51d7b10f..76250b79 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js @@ -2,11 +2,106 @@ // - ready query param to get flashrom path, check for its existance // - handle last part to redirect to lc2-download-complete // - handle failures +request_is_async = true; -headers = `200 OK +if (!request_headers.query.path) { + var errpage = doErrorPage(400); + headers = errpage[0]; + data = errpage[1]; +} else { + var request_path = unescape(request_headers.query.path); + if (services_configured.services[service_name].use_zefie_server) { + // read first 256 bytes of flashrom file from archive.midnightchannel.net + // to get `flashrom_message` and `numparts` if missing + var options = { + host: "archive.midnightchannel.net", + path: "/zefie/files/wtv-flashrom/" + request_path, + method: 'GET', + timeout: 5000, + headers: { + 'Range': 'bytes=0-256' + } + } + + var chunk; + + const req = https.request(options, function (res) { + var data = ''; + res.setEncoding('hex'); + + res.on('data', function (d) { + data += d; + }); + + res.on('error', function (e) { + console.log(" * Upstream FlashROM Error:", e); + var errpage = doErrorPage(400) + headers = errpage[0]; + data = errpage[1]; + sendToClient(socket, headers, data); + }); + + res.on('end', function () { + if (res.statusCode == 206) { + var flashrom_message = new Buffer.from(data.substring(36 * 2, 68 * 2), 'hex').toString('ascii').replace(/[^0-9a-z\ \.\-]/gi, ""); + processLC2DownloadPage(request_headers.query.path, flashrom_message, (request_headers.query.numparts || null)); + return; + } else if (res.statusCode == 404) { + var errpage = doErrorPage(404, "The service could not find the requested ROM on zefie's server.") + headers = errpage[0]; + data = errpage[1]; + } else { + var errpage = doErrorPage(400) + headers = errpage[0]; + data = errpage[1]; + } + sendToClient(socket, headers, data); + }); + }); + req.end(); + } else { + // use local flashrom files + var flashrom_file_path = service_dir + '/' + request_path; + fs.readFile(flashrom_file_path, null, function (err, data) { + try { + var data_128 = new Buffer.alloc(128); + data.copy(data_128, 0, 0, 128); + var flashrom_message = new Buffer.from(data_128.toString('hex').substring(36 * 2, 68 * 2), 'hex').toString('ascii').replace(/[^0-9a-z\ \.\-]/gi, ""); + processLC2DownloadPage(request_headers.query.path, flashrom_message, (request_headers.query.numparts || null)); + } catch (e) { + var errpage = doErrorPage(404, "The service could not find the requested ROM.") + headers = errpage[0]; + data = errpage[1]; + sendToClient(socket, headers, data); + } + }); + } +} + +async function processLC2DownloadPage(path, flashrom_message, numparts = null) { + if (numparts != null) var flashrom_numparts = parseInt(numparts); + if (!flashrom_numparts) flashrom_numparts = flashrom_message.substring(flashrom_message.length - 4).replace(/\D/g, ''); + var ind = new Array(); + ind[0] = (path.indexOf("part") + 4); + ind[1] = (path.indexOf(".", ind[0]) + 1); + var flashrom_part_num = path.substr(ind[0], (path.length - ind[1])); + var flashrom_lastpart = (flashrom_numparts == (parseInt(flashrom_part_num) + 1)) ? true : false; + var flashrom_rompath = 'wtv-flashrom:/get-by-path?path=' + path + '&raw=true'; + var flashrom_isboot = (/\.brom$/).test(path); + if (flashrom_lastpart) { + flashrom_next_rompath = "wtv-flashrom:/lc2-download-complete?"; + } else { + var flashrom_next_part_num = (parseInt(flashrom_part_num) + 1); + if (flashrom_next_part_num < 10) flashrom_next_part_num = "00" + flashrom_next_part_num; // 1s + else if (flashrom_next_part_num >= 10 && flashrom_next_part_num < 100) flashrom_next_part_num = "0" + flashrom_next_part_num; // 10s + var flashrom_next_rompath = flashrom_rompath.replace("part"+flashrom_part_num, "part"+flashrom_next_part_num).replace('get-by-path', 'get-lc2-page').replace("&raw=true", "&numparts=" + parseInt(flashrom_numparts)); + } + if (!flashrom_part_num || !flashrom_lastpart || !flashrom_rompath || !flashrom_next_rompath || !flashrom_isboot) { + + headers = `200 OK Content-type: text/html` -data = ` + data = ` Updating @@ -18,18 +113,22 @@ hspace=0 vspace=0 fontsize="large"> <table cellspacing=0 cellpadding=0> <tr> <td width=104 height=74 valign=middle align=center bgcolor="3B3A4D"> +<img src="wtv-flashrom:/ROMCache/HackTVLogoJewel.gif" width=87 height=67> <td width=20 valign=top align=left bgcolor="3B3A4D"> +<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=1> <td colspan=10 width=436 valign=middle align=left bgcolor="3B3A4D"> <font color="D6DFD0" size="+2"> <blackface> <shadow> +<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=4> <br> -Updating now... +Updating now </shadow> </blackface> </font> <tr> <td colspan=12 width=560 height=10 valign=top align=left> +<img src="wtv-flashrom:/ROMCache/S40H1.gif" width=560 height=6> <tr> <td width=104 height=10 valign=top align=left> <td width=20 valign=top align=left> @@ -49,38 +148,37 @@ Updating now... <td width=20 valign=middle align=center> <td colspan=9 width=100 height=258 valign=top align=left> <font size=+1> -Your Internet Receiver is being<br>updated automatically. +Your WebTV Unit is being<br>updated automatically. <p> <font size=+1> -This will take a while, and then<br> your unit will reboot.<br><br> +This will take a while, and<br>then you can use your WebTV again. `; - -if (flashrom_isboot && flashrom_part == 16) { -data += `<p> + if (flashrom_isboot && parseInt(flashrom_part_num) == 16) { + data += `<p> The system will pause for about 30 seconds at the end of this update. Please <strong>do not</strong> interrupt the system during this time. ` -} -data += `</font> -</table> -<table width="100%"> -<tr> -<td align="left"><font size="-1" color="#D6DFD0"><small>    Receiving part ${flashrom_part} of ${flashrom_total_parts}</small></font></td> -<td align="right"><font size="-1" color="#D6DFD0"><small>v${flashrom_version} (${flashrom_type})    </small></font></td> -</tr> -</table> -<center> -<upgradeblock width=520 height=15 -${nextrompath} -errorurl="wtv-flashrom:/lc2-download-failed" -blockurl="wtv-flashrom:/${flashrom_rompath} -lastblock=${flashrom_lastpart} -curblock="${flashrom_part}" -totalblocks="${flashrom_total_parts}"></center> + } +data += ` +</font> +<br><br><br><br><br> +<upgradeblock width=280 height=15 +nexturl="${flashrom_next_rompath}" +errorurl="wtv-flashrom:/lc2-download-failed?" +blockurl="${flashrom_rompath}" +lastblock="${flashrom_lastpart}" +curblock="` + (parseInt(flashrom_part_num) + 1) + `" +totalblocks="${flashrom_numparts}"> +<font size="-1" color="#D6DFD0"> +<br> +<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=2 height=10><br> +${flashrom_message} + <br><br> <tr> <td width=104 valign=middle align=center> <td width=20 valign=middle align=center> <td colspan=10 height=2 valign=middle align=center bgcolor="#191919"> +<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=436 height=1> <tr> <td width=104 valign=middle align=center> <td width=20 valign=middle align=center> @@ -89,6 +187,7 @@ totalblocks="${flashrom_total_parts}"></center> <td width=104 valign=middle align=center> <td width=20 valign=middle align=center> <td colspan=10 height=2 valign=top align=left bgcolor="#191919"> +<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=436 height=1> <tr> <td width=104 valign=middle align=center> <td width=20 valign=middle align=center> @@ -109,4 +208,11 @@ totalblocks="${flashrom_total_parts}"></center> <td width=20 valign=middle align=center> </table> </body> -</html>` \ No newline at end of file +</html>`; + } else { + var errpage = doErrorPage(400) + headers = errpage[0]; + data = errpage[1]; + } + sendToClient(socket, headers, data); +} diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js new file mode 100644 index 00000000..dcc51996 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js @@ -0,0 +1,11 @@ +if (request_headers.query.path) { + headers = "300 OK\n"; + headers += "wtv-visit: wtv-flashrom:/get-lc2-page?path=" + request_headers.query.path + "\n"; + headers += "Location: wtv-flashrom:/get-lc2-page?path=" + request_headers.query.path + "\n"; + headers += "Content-type: text/html"; + data = ''; +} else { + var errpage = doErrorPage(400) + headers = errpage[0]; + data = errpage[1]; +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-complete.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-complete.js index 07290fdd..ed082c92 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-complete.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-complete.js @@ -23,7 +23,7 @@ hspace=0 vspace=0 fontsize="large"> <table cellspacing=0 cellpadding=0> <tr> <td width=104 height=74 valign=middle align=center bgcolor="3B3A4D"> -<img src="wtv-flashrom:/ROMCache/MSNLogo.gif" width=87 height=67> +<img src="wtv-flashrom:/ROMCache/HackTVLogoJewel.gif" width=87 height=67> <td width=20 valign=top align=left bgcolor="3B3A4D"> <img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=1> <td colspan=10 width=436 valign=middle align=left bgcolor="3B3A4D"> diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.html b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.html deleted file mode 100644 index 19abc99a..00000000 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.html +++ /dev/null @@ -1,50 +0,0 @@ -<html> -<head> -<title> -Updating failed - - - - - - - - - - + + + + + + +
- - - - - - - - -
-Updated failed -
-
-
-
- -
- - - - - - - - - - - -
-
- - - -Update failed, gomennasai. - - \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.js new file mode 100644 index 00000000..6a5a5c52 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.js @@ -0,0 +1,140 @@ +var error = ''; +if (request_headers.query.error) { + switch (request_headers.query.error) { + case "1": + error = "uncompression failed"; + break; + case "2": + error = "upgrade write failed"; + break; + case "3": + error = "signature verification failed"; + break; + case "4": + error = "cannot upgrade bootstrap"; + break; + case "5": + error = "out of memory"; + break; + case "-7": + error = "response error"; + break; + case "-20": + error = "timed out"; + break; + case "99": + error = "test code"; + break; + default: + error = "unknown error"; + break; + } +} + + +var try_again_url = 'wtv-flashrom:/willie'; +var try_again_url_path = '' +var try_again_url_start_time = parseInt(new Date().toUTCString()) / 1000; + +headers = `200 OK +Content-type: text/html` + + +data = ` + + + Update failed + + + + + + + + + + + + + +
+ + + + + + + + +
+ Updating failed +
+
+
+
+ +
+ + + + + + + + + + + + + + +
+ + + + We ran into a technical problem while updating + your unit. (Error: ${error}) + Choose Try Again to try again now. +

Press the power button to switch off your unit. +

+ + + +
+ + +
+ + + +
+ + +
+ + + + +
+ + + + + + + + + + + + +
+
+
+ +`; \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.async.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.async.js deleted file mode 100644 index aa379a3d..00000000 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.async.js +++ /dev/null @@ -1,35 +0,0 @@ -// willie is just a graphical frontend to a list of ROMs -// the rest of the scripts should work if you manually link to a ROM, and actually have it. - - -var proxy_query = ''; -if (query['flash']) delete query['flash']; -if (query['vflash']) delete query['vflash']; - -for (const [key, value] of Object.entries(query)) { - proxy_query += "&" + key + "=" + value; -} - -console.log(proxy_query); - -var options = { - host: "wtv.zefie.com", - path: "/willie.php?pflash=" + getSessionData(socket_session_data[socket.id].ssid, 'wtv-client-rom-type') + proxy_query, - method: 'GET' -} - - -headers = "200 OK\nContent-type: text/html"; -const req = http.request(options, function (res) { - data = ''; - console.log(` * Upstream HTTP StatusCode: ${res.statusCode}`) - - res.on('data', d => { - data += d; - }) - - res.on('end', function () { - sendToClient(socket, headers, data); - }); -}); -req.end(); diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js new file mode 100644 index 00000000..ef2e4597 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js @@ -0,0 +1,50 @@ +// willie is just a graphical frontend to a list of ROMs +// the rest of the scripts should work if you manually link to a ROM, and actually have it. + +request_is_async = true; + +var proxy_query = ''; +if (request_headers.query.flash) delete request_headers.query.flash; +if (request_headers.query.vflash) delete request_headers.query.vflash; +if (request_headers.query.pflash) delete request_headers.query.pflash; + +for (const [key, value] of Object.entries(request_headers.query)) { + proxy_query += "&" + key + "=" + value; +} + +if (!services_configured.services[service_name].use_zefie_server) { + proxy_query += "&minisrv_local_mode=true"; +} + +var options = { + host: "wtv.zefie.com", + path: "/willie.php?minisrv=true&pflash=" + getSessionData(socket_session_data[socket.id].ssid, 'wtv-client-rom-type') + proxy_query, + timeout: 5000, + method: 'GET' +} + + +headers = "200 OK\nContent-type: text/html"; +const req = https.request(options, function (res) { + data = ''; + res.on('data', d => { + data += d; + }); + + res.on('error', function (e) { + if (!zquiet) console.log(" * Upstream Ultra Willies HTTP Error:", e); + var errpage = doErrorPage(400) + headers = errpage[0]; + data = errpage[1]; + sendToClient(socket, headers, data); + }); + + res.on('end', function () { + if (!zquiet) console.log(" * Upstream Ultra Willies HTTP Response:", res.statusCode, res.statusMessage); + if (request_headers.query.clear_cache) { + headers += "\nwtv-expire-all: wtv-flashrom"; + } + sendToClient(socket, headers, data); + }); +}); +req.end(); diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/finalize-security.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/finalize-security.js index ba53496f..25ed5f5b 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/finalize-security.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/finalize-security.js @@ -2,10 +2,10 @@ var challenge_response, challenge_header = ''; var gourl; if (socket_session_data[socket.id].ssid !== null) { - if (request_headers['wtv-ticket']) { - if (request_headers['wtv-ticket'].length > 8) { - DecodeTicket(request_headers['wtv-ticket']); - socket_session_data[socket.id].wtvsec.ticket_b64 = request_headers['wtv-ticket']; + if (request_headers["wtv-ticket"]) { + if (request_headers["wtv-ticket"].length > 8) { + DecodeTicket(request_headers["wtv-ticket"]); + socket_session_data[socket.id].wtvsec.ticket_b64 = request_headers["wtv-ticket"]; //socket_session_data[socket.id].secure == true; } } else if (socket_session_data[socket.id].wtvsec.ticket_b64 == null) { diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js index 47cebbad..be58d5a4 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js @@ -2,10 +2,9 @@ var challenge_response, challenge_header = ''; var gourl; if (socket_session_data[socket.id].ssid != null && !getSessionData(socket_session_data[socket.id].ssid, 'wtvsec_login')) { - var wtvsec_login = new WTVSec(); - wtvsec_login = new WTVSec(); + var wtvsec_login = new WTVSec(1,zdebug); wtvsec_login.IssueChallenge(); - wtvsec_login.set_incarnation(request_headers['wtv-incarnation']); + wtvsec_login.set_incarnation(request_headers["wtv-incarnation"]); setSessionData(socket_session_data[socket.id].ssid, 'wtvsec_login', wtvsec_login) } else { var wtvsec_login = getSessionData(socket_session_data[socket.id].ssid, 'wtvsec_login') @@ -13,23 +12,23 @@ if (socket_session_data[socket.id].ssid != null && !getSessionData(socket_sessio if (socket_session_data[socket.id].ssid !== null) { if (wtvsec_login.ticket_b64 == null) { - if (request_headers['wtv-ticket']) { - if (request_headers['wtv-ticket'].length > 8) { - wtvsec_login.DecodeTicket(request_headers['wtv-ticket']); - wtvsec_login.ticket_b64 = request_headers['wtv-ticket']; + if (request_headers["wtv-ticket"]) { + if (request_headers["wtv-ticket"].length > 8) { + wtvsec_login.DecodeTicket(request_headers["wtv-ticket"]); + wtvsec_login.ticket_b64 = request_headers["wtv-ticket"]; //socket_session_data[socket.id].secure = true; } } else { challenge_response = wtvsec_login.challenge_response; - var client_challenge_response = request_headers['wtv-challenge-response'] || null; + var client_challenge_response = request_headers["wtv-challenge-response"] || null; if (challenge_response && client_challenge_response) { //if (challenge_response.toString(CryptoJS.enc.Base64).substring(0,85) == client_challenge_response.substring(0,85)) { if (challenge_response.toString(CryptoJS.enc.Base64) == client_challenge_response) { - console.log(" * wtv-challenge-response success for "+socket_session_data[socket.id].ssid); + console.log(" * wtv-challenge-response success for " + processSSID(socket_session_data[socket.id].ssid)); wtvsec_login.PrepareTicket(); //socket_session_data[socket.id].secure = true; } else { - console.log(" * wtv-challenge-response FAILED for " + socket_session_data[socket.id].ssid); + console.log(" * wtv-challenge-response FAILED for " + processSSID(socket_session_data[socket.id].ssid)); if (zdebug) console.log("Response Expected:", challenge_response.toString(CryptoJS.enc.Base64)); if (zdebug) console.log("Response Received:", client_challenge_response) gourl = "wtv-head-waiter:/login?reissue_challenge=true"; @@ -54,7 +53,7 @@ else { var nickname = 'HackTVUsr_' + namerand; var userid = '1'+ Math.floor(Math.random() * 1000000000000000000); var offline_user_list = CryptoJS.enc.Latin1.parse("\n\t\n").toString(CryptoJS.enc.Base64); - + data = ''; headers = `200 OK Connection: Keep-Alive wtv-encrypted: true @@ -80,10 +79,10 @@ wtv-messenger-enable: 0 wtv-noback-all: wtv- wtv-service: reset `+ getServiceString('all') + ` -wtv-boot-url: wtv-1800:/preregister?relogin=true -wtv-ssl-certs-download-url: wtv-head-waiter:/ssl-cert.der -wtv-ssl-certs-checksum: 473926DC1B11F635A6B920953FDCDE6A -wtv-user-name: `+ nickname + ` +wtv-boot-url: wtv-1800:/preregister?relogin=true` +//wtv-ssl-certs-download-url: wtv-head-waiter:/ssl-cert.der +//wtv-ssl-certs-checksum: 473926DC1B11F635A6B920953FDCDE6A + headers += `wtv-user-name: `+ nickname + ` wtv-human-name: `+ nickname + ` wtv-irc-nick: `+ nickname + ` wtv-home-url: wtv-home:/home? diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js index be4cf9e3..e16e5d7e 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js @@ -2,17 +2,17 @@ var challenge_response, challenge_header = ''; if (socket_session_data[socket.id].ssid !== null) { var wtvsec_login = getSessionData(socket_session_data[socket.id].ssid, 'wtvsec_login'); - if (request_headers['wtv-ticket']) { + if (request_headers["wtv-ticket"]) { if (wtvsec_login.ticket_b64 == null) { - if (request_headers['wtv-ticket'].length > 8) { - wtvsec_login.DecodeTicket(request_headers['wtv-ticket']); - wtvsec_login.ticket_b64 = request_headers['wtv-ticket']; + if (request_headers["wtv-ticket"].length > 8) { + wtvsec_login.DecodeTicket(request_headers["wtv-ticket"]); + wtvsec_login.ticket_b64 = request_headers["wtv-ticket"]; } } } else { if (wtvsec_login) { challenge_response = wtvsec_login.challenge_response; - var client_challenge_response = request_headers['wtv-challenge-response'] || null; + var client_challenge_response = request_headers["wtv-challenge-response"] || null; if (challenge_response && client_challenge_response) { if (challenge_response.toString(CryptoJS.enc.Base64).substring(0, 85) == client_challenge_response.substring(0, 85)) { console.log(" * wtv-challenge-response success for " + socket_session_data[socket.id].ssid); diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/ssl-cert.der b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/ssl-cert.der deleted file mode 100644 index b4b9da93..00000000 Binary files a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/ssl-cert.der and /dev/null differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js b/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js index ae471606..957b5d26 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js @@ -13,7 +13,7 @@ if (getSessionData(socket_session_data[socket.id].ssid, 'box-does-psuedo-encrypt data =` Home for minisrv - + + + + + + + + + + + + +
+ + + +
+
+
+ + + + + +
+
Stop Music +
+
+
+
+
+ +
+ + + + + + + + +
+ + + +
+  WebTV MIDI Music +
+
+
+
+   + + + + + +
+
+ + + + +
+ +<font color="red" size="+1">WebTV JavaScript Bug!!! Press and hold CMD-R for 3 seconds</font><br> + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Bogged.mid + + Jazzin.mid + + Saunter.mid +
+ Bogged2.mid + + Jimi.mid + + ShadowMe.mid +
+ Brasilia.mid + + JiveJava.mid + + Shre.mid +
+ Busy.mid + + JustBlue.mid + + SlowDay.mid +
+ CantWait.mid + + LizLarry.mid + + SoGrand.mid +
+ Catamran.mid + + Midterm.mid + + StarDanc.mid +
+ ComeInn.mid + + Missin.mid + + Stubborn.mid +
+ CoolShad.mid + + Moorea.mid + + Surge.mid +
+ Dancing.mid + + MoveOver.mid + + Swang.mid +
+ DarkGame.mid + + NiteFunk.mid + + SwingSet.mid +
+ DeerXing.mid + + OnBoogie.mid + + TastyWav.mid +
+ Downtown.mid + + OnFire.mid + + TheGirl.mid +
+ Fever.mid + + ParkIt.mid + + Theme.mid +
+ Flutey.mid + + ParkWalk.mid + + Think.mid +
+ Flutter.mid + + PCH.mid + + Travel.mid +
+ Georgy.mid + + PianoJz1.mid + + Tumbling.mid +
+ GetBy.mid + + PianoJz2.mid + + Under.mid +
+ Glasses.mid + + Prezo.mid + + Upping.mid +
+ Harry.mid + + Prussian.mid + + Wind1.mid +
+ Herbie.mid + + Pundit.mid + + Xess.mid +
+ HomeAgn.mid + + RickPunk.mid + + MattMan69.mid + +

+

+ Huffin.mid + + Road.mid + +

+

+ +
+ + + \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jelly_kansascitystomp.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jelly_kansascitystomp.mid new file mode 100644 index 00000000..21de4e06 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jelly_kansascitystomp.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jelly_mrjoe.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jelly_mrjoe.mid new file mode 100644 index 00000000..785f79eb Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jelly_mrjoe.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jivecofe.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jivecofe.mid new file mode 100644 index 00000000..13e16643 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jivecofe.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_entertainer.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_entertainer.mid new file mode 100644 index 00000000..7276e3f0 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_entertainer.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_figleafrag.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_figleafrag.mid new file mode 100644 index 00000000..73f32b0f Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_figleafrag.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_mapleleafrag.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_mapleleafrag.mid new file mode 100644 index 00000000..b71fa42e Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_mapleleafrag.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_wallstreetrag.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_wallstreetrag.mid new file mode 100644 index 00000000..3c312432 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/joplin_wallstreetrag.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jscape.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jscape.mid new file mode 100644 index 00000000..fca43b97 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/jscape.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/just_wtv.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/just_wtv.mid new file mode 100644 index 00000000..ebd0a16e Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/just_wtv.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/mattman.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/mattman.mid new file mode 100644 index 00000000..eceb61b7 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/mattman.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/nightclub.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/nightclub.mid new file mode 100644 index 00000000..447c3096 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/nightclub.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/nite_wtv.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/nite_wtv.mid new file mode 100644 index 00000000..ade6b697 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/nite_wtv.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/oldshop.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/oldshop.mid new file mode 100644 index 00000000..a437cfc0 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/oldshop.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/pnojazz1.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/pnojazz1.mid new file mode 100644 index 00000000..4b03f248 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/pnojazz1.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/pnojazz2.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/pnojazz2.mid new file mode 100644 index 00000000..61337110 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/pnojazz2.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/relief.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/relief.mid new file mode 100644 index 00000000..050a49ee Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/relief.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/roadtrav.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/roadtrav.mid new file mode 100644 index 00000000..e6382aaf Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/roadtrav.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/royal.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/royal.mid new file mode 100644 index 00000000..a85709ba Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/royal.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/shre_wtv.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/shre_wtv.mid new file mode 100644 index 00000000..85797144 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/shre_wtv.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/stop.wav b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/stop.wav new file mode 100644 index 00000000..0191f10c Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/stop.wav differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/tekworld.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/tekworld.mid new file mode 100644 index 00000000..1c028923 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/tekworld.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/undr_wtv.mid b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/undr_wtv.mid new file mode 100644 index 00000000..d9eb5821 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/undr_wtv.mid differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/webtv.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/webtv.gif new file mode 100644 index 00000000..a2fb0f08 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/midi/webtv.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/music.jpg b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/music.jpg new file mode 100644 index 00000000..eb432570 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-music/demo/music.jpg differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/access.js b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/access.js index 4c9342fc..3281696d 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/access.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/access.js @@ -1,6 +1,6 @@ // Allow URL access outside our trusted minisrv -if (query['url']) var url = unescape(query['url']); +if (request_headers.query.url) var url = unescape(request_headers.query.url); else var url = "client:showalert?message=Please%20provide%20a%20%3Furl%3D%20with%20the%20url%20you%20would%20like%20to%20access.&buttonlabel1=Okay&buttonacction1=client:donothing" headers = `200 OK diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/blastcache.js b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/blastcache.js index 6269d576..6e352b5c 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/blastcache.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/blastcache.js @@ -5,8 +5,8 @@ Content-type: text/html` var visit_url = null; -if (request_headers['Referer']) visit_url = request_headers['Referer']; -else if (query['return_to']) visit_url = query['return_to']; +if (request_headers.Referer) visit_url = request_headers.Referer; +else if (request_headers.query.return_to) visit_url = request_headers.query.return_to; else visit_url = "client:goback"; data = ` diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/go-offline.js b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/go-offline.js index f43dad67..4d108b25 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/go-offline.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/go-offline.js @@ -9,8 +9,8 @@ wtv-service: reset // HackTV Homepage is default var url="file://Disk/Browser/Games/Games.html"; -if (query['url']) { - url = query['url']; +if (request_headers.query.url) { + url = request_headers.query.url; } data = ` @@ -33,8 +33,8 @@ if (window.location) {

` -if (query['title']) { - data += "Going offline and loading "+decodeURI(query['title'])+", please wait!"; +if (request_headers.query.title) { + data += "Going offline and loading " + decodeURI(request_headers.query.title)+", please wait!"; } else { data += "Please wait a moment."; } diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/sync.js b/zefie_wtvp_minisrv/ServiceVault/wtv-update/sync.js index 8be14f6b..36b4445f 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-update/sync.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-update/sync.js @@ -1,13 +1,15 @@ +// todo: async (and make this work anyway) + var content_dir = service_dir + '/content/'; var diskmap_dir = content_dir + '/diskmaps/'; -if (initial_headers['post_data']) { - console.log(initial_headers['post_data'].toString('CryptoJS.enc.Latin1')) +if (request_headers.post_data) { + console.log(request_headers.post_data.toString('CryptoJS.enc.Latin1')) } -if (query['diskmap']) { - if (fs.lstatSync(diskmap_dir + query['diskmap'] + ".txt")) { - var diskmap_data = fs.readFileSync(diskmap_dir + query['diskmap'] + ".txt").toString(); +if (request_headers.query.diskmap) { + if (fs.lstatSync(diskmap_dir + request_headers.query.diskmap + ".txt")) { + var diskmap_data = fs.readFileSync(diskmap_dir + request_headers.query.diskmap + ".txt").toString(); // try to parse diskmap and get an accurate timestamp for webtv versioning // check all files in the diskmap and return the timestamp of the most recently modified diff --git a/zefie_wtvp_minisrv/app.js b/zefie_wtvp_minisrv/app.js index f87ec4cd..78fb52e8 100644 --- a/zefie_wtvp_minisrv/app.js +++ b/zefie_wtvp_minisrv/app.js @@ -10,8 +10,6 @@ const mime = require('mime-types'); const { crc16 } = require('easy-crc'); var WTVSec = require('./wtvsec.js'); -var zdebug = true; - var ports = []; var service_vault_dir = __dirname + "/ServiceVault"; @@ -58,20 +56,6 @@ function setSessionData(ssid, key, value) { ssid_data[ssid][key] = value; } - -function getFile(path, deps = false) { - var dir = null; - if (deps) dir = __dirname + "/ServiceDeps/"; - else dir = __dirname + "/ServiceVault/"; - if (fs.lstatSync(dir + path).isFile()) { - return fs.readFileSync(dir + path, { - encoding: null, - flags: 'r' - }); - } - return null; -} - function getFileExt(path) { return path.reverse().split(".")[0].reverse(); } @@ -112,7 +96,7 @@ function getConType(path) { async function processPath(socket, path, request_headers = new Array(), query = new Array(), service_name) { var headers, data = null; var request_is_direct_file = false; - var request_is_async_js = false; + var request_is_async = false; path = path.replace(/\\/g, "/"); try { try { @@ -126,9 +110,9 @@ async function processPath(socket, path, request_headers = new Array(), query = if (request_is_direct_file) { // file exists, read it and return it - console.log(" * Found " + path + " to handle request (Direct File Mode) [Socket " + socket.id +"]"); + if (!zquiet) console.log(" * Found " + path + " to handle request (Direct File Mode) [Socket " + socket.id +"]"); var contype = getConType(path); - request_is_async_js = true; + request_is_async = true; headers = "200 OK\n" headers += "Content-Type: " + contype; fs.readFile(path, null, function (err, data) { @@ -136,51 +120,50 @@ async function processPath(socket, path, request_headers = new Array(), query = }); } else if (fs.existsSync(path + ".txt")) { // raw text format, entire payload expected (headers and content) - console.log(" * Found " + path + ".txt to handle request (Raw TXT Mode) [Socket " + socket.id +"]"); - var file_raw = fs.readFileSync(path + ".txt").toString(); - if (file_raw.indexOf("\n\n") > 0) { - var file_raw_split = file_raw.split("\n\n"); - headers = file_raw_split[0]; - file_raw_split.shift(); - data = file_raw_split.join("\n"); - } else if (file_raw.indexOf("\r\n\r\n") > 0) { - var file_raw_split = file_raw.split("\r\n\r\n"); - headers = file_raw_split[0].replace(/\r/g, ""); - file_raw_split.shift(); - data = file_raw_split.join("\r\n"); - } else { - headers = fdat; - } - } else if (fs.existsSync(path + ".async.js")) { - // asynchronous js scripting, process with vars, must manually call sendToClient(socket, headers, data); - // (hint: socket is already defined) - // loaded script will have r/w access to any JavaScript vars this function does. - // any query args are in an array named 'query' - request_is_async_js = true; - console.log(" * Found " + path + ".async.js to handle request (Async JS Interpreter mode) [Socket " + socket.id + "]"); - // expose var service_dir for script path to the root of the wtv-service - var service_dir = service_vault_dir.replace(/\\/g, "/") + "/" + service_name; - socket_session_data[socket.id].starttime = Math.floor(new Date().getTime() / 1000); - fs.readFile(path + ".async.js", "utf-8", function (err, data) { - eval(data); + if (!zquiet) console.log(" * Found " + path + ".txt to handle request (Raw TXT Mode) [Socket " + socket.id + "]"); + request_is_async = true; + fs.readFile(path + ".txt", 'Utf-8', function (err, file_raw) { + if (file_raw.indexOf("\n\n") > 0) { + // split headers and data by newline (unix format) + var file_raw_split = file_raw.split("\n\n"); + headers = file_raw_split[0]; + file_raw_split.shift(); + data = file_raw_split.join("\n"); + } else if (file_raw.indexOf("\r\n\r\n") > 0) { + // split headers and data by carrage return + newline (windows format) + var file_raw_split = file_raw.split("\r\n\r\n"); + headers = file_raw_split[0].replace(/\r/g, ""); + file_raw_split.shift(); + data = file_raw_split.join("\r\n"); + } else { + // couldn't find two line breaks, assume entire file is just headers + headers = file_raw; + data = ''; + } + sendToClient(socket, headers, data); }); } else if (fs.existsSync(path + ".js")) { // synchronous 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 (JS Interpreter mode) [Socket " + socket.id + "]"); + // request headers are in an array named `request_headers`. + // Query arguments in `request_headers.query` + if (!zquiet) console.log(" * Found " + path + ".js to handle request (JS Interpreter mode) [Socket " + socket.id + "]"); // expose var service_dir for script path to the root of the wtv-service var service_dir = service_vault_dir.replace(/\\/g, "/") + "/" + service_name; socket_session_data[socket.id].starttime = Math.floor(new Date().getTime() / 1000); var jscript_eval = fs.readFileSync(path + ".js").toString(); eval(jscript_eval); + if (request_is_async && !zquiet) console.log(" * Script requested Asynchronous mode"); } else if (fs.existsSync(path + ".html")) { // Standard HTML with no headers, WTV Style - console.log(" * Found " + path + ".html to handle request (HTML Mode) [Socket " + socket.id +"]"); - data = fs.readFileSync(path + ".html").toString(); + if (!zquiet) console.log(" * Found " + path + ".html to handle request (HTML Mode) [Socket " + socket.id +"]"); + request_is_async = true; headers = "200 OK\n" headers += "Content-Type: text/html" + fs.readFile(path + ".html", null, function (err, data) { + sendToClient(socket, headers, data); + }); } else { var errpage = doErrorPage(404); headers = errpage[0]; @@ -190,7 +173,7 @@ async function processPath(socket, path, request_headers = new Array(), query = // 'headers' and 'data' should both be set with content by this point! - if (headers == null && !request_is_async_js) { + if (headers == null && !request_is_async) { var errpage = doErrorPage(400); headers = errpage[0]; data = errpage[1]; @@ -204,59 +187,82 @@ async function processPath(socket, path, request_headers = new Array(), query = var errpage = doErrorPage(400); headers = errpage[0]; data = errpage[1] + "

The interpreter said:
" + e.toString() + "
"; - console.log(e); + console.log(" * Scripting error:",e); } - if (!request_is_async_js) { + if (!request_is_async) { sendToClient(socket, headers, data); } } +function processSSID(obj) { + if (services_configured.config.hide_ssid_in_logs) { + if (typeof (obj) == "string") { + if (obj.substr(0, 8) == "MSTVSIMU") { + return obj.substr(0, 10) + ('*').repeat(10) + obj.substr(20); + } else { + return obj.substr(0, 6) + ('*').repeat(9); + } + } else { + if (obj["wtv-client-serial-number"]) { + var ssid = obj["wtv-client-serial-number"]; + if (ssid.substr(0, 8) == "MSTVSIMU") { + obj["wtv-client-serial-number"] = ssid.substr(0, 10) + ('*').repeat(10) + ssid.substr(20); + } else { + obj["wtv-client-serial-number"] = ssid.substr(0, 6) + ('*').repeat(9); + } + } + return obj; + } + } else { + return obj; + } +} + async function processURL(socket, request_headers) { if (request_headers === null) { return; } var shortURL, headers, data = ""; - var query = new Array(); - if (request_headers['request_url']) { - if (request_headers['request_url'].indexOf('?') >= 0) { - shortURL = request_headers['request_url'].split('?')[0]; - var qraw = request_headers['request_url'].split('?')[1]; + request_headers.query = new Array(); + if (request_headers.request_url) { + if (request_headers.request_url.indexOf('?') >= 0) { + shortURL = request_headers.request_url.split('?')[0]; + var qraw = request_headers.request_url.split('?')[1]; if (qraw.length > 0) { qraw = qraw.split("&"); for (let i = 0; i < qraw.length; i++) { var k = qraw[i].split("=")[0]; if (k) { - query[k] = qraw[i].split("=")[1]; + request_headers.query[k] = qraw[i].split("=")[1]; } } - console.log(" * Request query:", query); } } else { - shortURL = request_headers['request_url']; + shortURL = request_headers.request_url; } if (shortURL.indexOf(':/') >= 0 && shortURL.indexOf('://') < 0) { var ssid = socket_session_data[socket.id].ssid; if (ssid == null) { - ssid = request_headers['wtv-client-serial-number']; + ssid = request_headers["wtv-client-serial-number"]; } var reqverb = "Request"; - if (request_headers['encrypted'] || request_headers['secure']) { + if (request_headers.encrypted || request_headers.secure) { reqverb = "Encrypted " + reqverb; } - if (request_headers['psuedo-encryption']) { + if (request_headers.psuedo_encryption) { reqverb = "Psuedo-encrypted " + reqverb; } if (ssid != null) { - console.log(" * " + reqverb + " for " + request_headers['request_url'] + " from WebTV SSID " + ssid, 'on', socket.id); + console.log(" * " + reqverb + " for " + request_headers.request_url + " from WebTV SSID " + (await processSSID(ssid)), 'on', socket.id); } else { - console.log(" * " + reqverb + " for " + request_headers['request_url'], 'on', socket.id); + console.log(" * " + reqverb + " for " + request_headers.request_url, 'on', socket.id); } // assume webtv since there is a :/ in the GET var service_name = shortURL.split(':/')[0]; var urlToPath = service_vault_dir.replace(/\\/g, "/") + "/" + service_name + "/" + shortURL.split(':/')[1]; - console.log(" * Incoming headers on socket ID", socket.id, request_headers); - processPath(socket, urlToPath, request_headers, query, service_name); + if (zshowheaders) console.log(" * Incoming headers on socket ID", socket.id, (await processSSID(request_headers))); + processPath(socket, urlToPath, request_headers, request_headers.query, service_name); } else if (shortURL.indexOf('http://') >= 0 || shortURL.indexOf('https://') >= 0) { doHTTPProxy(socket, request_headers); } else { @@ -271,8 +277,8 @@ async function processURL(socket, request_headers) { } async function doHTTPProxy(socket, request_headers) { - console.log(socket.id, request_headers); - var request_type = request_headers['request'].indexOf('https://') ? 'http' : 'https' + if (zshowheaders) console.log("HTTP Proxy: Client Request Headers on socket ID",socket.id, request_headers); + var request_type = request_headers.request.indexOf('https://') ? 'http' : 'https' switch (request_type) { case "https": var proxy_agent = https; @@ -283,41 +289,41 @@ async function doHTTPProxy(socket, request_headers) { } var request_data = new Array(); - request_data['method'] = request_headers['request'].split(' ')[0]; - var request_url_split = request_headers['request'].split(' ')[1].split('/'); - request_data['host'] = request_url_split[2]; - if (request_data['host'].indexOf(':') > 0) { - request_data['port'] = request_data['host'].split(':')[1]; - request_data['host'] = request_data['host'].split(':')[0]; + request_data.method = request_headers.request.split(' ')[0]; + var request_url_split = request_headers.request.split(' ')[1].split('/'); + request_data.host = request_url_split[2]; + if (request_data.host.indexOf(':') > 0) { + request_data.port = request_data.host.split(':')[1]; + request_data.host = request_data.host.split(':')[0]; } else { - if (request_type === 'https') request_data['port'] = 443; - else request_data['port'] = 80; + if (request_type === 'https') request_data.port = 443; + else request_data.port = 80; } for (var i = 0; i < 3; i++) request_url_split.shift(); - request_data['path'] = "/" + request_url_split.join('/'); + request_data.path = "/" + request_url_split.join('/'); - if (request_data['method'] && request_data['host'] && request_data['path']) { + if (request_data.method && request_data.host && request_data.path) { var options = { - host: request_data['host'], - port: request_data['port'], - path: request_data['path'], - method: request_data['method'], + host: request_data.host, + port: request_data.port, + path: request_data.path, + method: request_data.method, headers: { - "User-Agent": request_headers['User-Agent'] || "WebTV" + "User-Agent": request_headers["User-Agent"] || "WebTV" } } - if (request_headers['post_data']) { - if (request_headers['Content-type']) options.headers['Content-type'] = request_headers['Content-type']; - if (request_headers['Content-length']) options.headers['Content-length'] = request_headers['Content-length']; + if (request_headers.post_data) { + if (request_headers["Content-type"]) options.headers["Content-type"] = request_headers["Content-type"]; + if (request_headers["Content-length"]) options.headers["Content-length"] = request_headers["Content-length"]; } if (services_configured.services[request_type].use_external_proxy && services_configured.services[request_type].external_proxy_port) { options.host = services_configured.services[request_type].external_proxy_host; options.port = services_configured.services[request_type].external_proxy_port; - options.path = request_headers['request'].split(' ')[1]; - options.headers['Host'] = request_data['host']; + options.path = request_headers.request.split(' ')[1]; + options.headers.Host = request_data.host; } const req = proxy_agent.request(options, function (res) { var data = []; @@ -333,19 +339,19 @@ async function doHTTPProxy(socket, request_headers) { res.on('end', function () { var data_hex = Buffer.concat(data).toString('hex'); - console.log(` * Proxy Request ${request_type.toUpperCase()} ${res.statusCode} for ${request_headers['request']}`) + console.log(` * Proxy Request ${request_type.toUpperCase()} ${res.statusCode} for ${request_headers.request}`) var headers = new Array(); - headers['http_response'] = res.statusCode + " " + res.statusMessage; - headers['wtv-connection-close'] = false; - if (res.headers['server']) headers['Server'] = res.headers['server']; - if (res.headers['connection']) headers['Connection'] = res.headers['connection'] == "close" ? "Keep-Alive" : "Close"; - if (res.headers['date']) headers['Date'] = res.headers['date']; - if (res.headers['content-type']) headers['Content-type'] = res.headers['content-type']; - if (res.headers['cookie']) headers['Cookie'] = res.headers['cookie']; + headers.http_response = res.statusCode + " " + res.statusMessage; + headers["wtv-connection-close"] = false; + if (res.headers.server) headers.Server = res.headers.server; + if (res.headers.connection) headers.Connection = res.headers.connection == "close" ? "Keep-Alive" : "Close"; + if (res.headers.date) headers.Date = res.headers.date; + if (res.headers["content-type"]) headers["Content-type"] = res.headers["content-type"]; + if (res.headers.cookie) headers.Cookie = res.headers.cookie; // content-length is best auto-calculated - //if (res.headers['content-length']) headers['Content-Length'] = res.headers['content-length']; - if (res.headers['vary']) headers['Vary'] = res.headers['vary']; - if (res.headers['location']) headers['Location'] = res.headers['location']; + //if (res.headers["content-length"]) headers["Content-Length"] = res.headers["content-length"]; + if (res.headers.vary) headers.Vary = res.headers.vary; + if (res.headers.location) headers.Location = res.headers.location; if (data_hex.substring(0, 8) == "0d0a0d0a") data_hex = data_hex.substring(8); if (data_hex.substring(0, 4) == "0a0a") data_hex = data_hex.substring(4); sendToClient(socket, headers, Buffer.from(data_hex,'hex')); @@ -362,8 +368,8 @@ async function doHTTPProxy(socket, request_headers) { data = errpage[1]; sendToClient(socket, headers, data); });; - if (request_headers['post_data']) { - req.write(Buffer.from(request_headers['post_data'].toString(CryptoJS.enc.Hex), 'hex'), function () { + if (request_headers.post_data) { + req.write(Buffer.from(request_headers.post_data.toString(CryptoJS.enc.Hex), 'hex'), function () { req.end(); }); } else { @@ -378,13 +384,13 @@ async function headerStringToObj(headers, response = false) { var headers_obj_pre = headers.split("\n"); headers_obj_pre.forEach(function (d) { if (/^SECURE ON/.test(d) && !response) { - headers_obj['secure'] = true; + headers_obj.secure = true; //socket_session_data[socket.id].secure_headers = true; } else if (/^([0-9]{3}) $/.test(d.substring(0, 4)) && response) { - headers_obj['http_response'] = d.replace("\r", ""); + headers_obj.http_response = d.replace("\r", ""); } else if (/^(GET |PUT |POST)$/.test(d.substring(0, 4)) && !response) { - headers_obj['request'] = d.replace("\r", ""); - headers_obj['request_url'] = decodeURI(d.split(' ')[1]).replace("\r", ""); + headers_obj.request = d.replace("\r", ""); + headers_obj.request_url = decodeURI(d.split(' ')[1]).replace("\r", ""); } else if (d.indexOf(":") > 0) { var d_split = d.split(':'); var header_name = d_split[0]; @@ -405,14 +411,15 @@ async function headerStringToObj(headers, response = false) { async function sendToClient(socket, headers_obj, data) { var headers = ""; + if (typeof (data) === 'undefined') data = ''; if (typeof (headers_obj) === 'string') { // string to header object headers_obj = await headerStringToObj(headers_obj, true); } // add Connection header if missing, default to Keep-Alive - if (!headers_obj['Connection']) { - headers_obj['Connection'] = "Keep-Alive"; + if (!headers_obj.Connection) { + headers_obj.Connection = "Keep-Alive"; headers_obj = moveObjectElement('Connection', 'http_response', headers_obj); } @@ -424,26 +431,35 @@ async function sendToClient(socket, headers_obj, data) { } else if (typeof data.byteLength !== 'undefined') { clen = data.byteLength; } - headers_obj['wtv-encrypted'] = 'true'; + headers_obj["wtv-encrypted"] = 'true'; headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj); - if (clen > 0) { - console.log(" * Encrypting response to client ...") + if (clen > 0 && socket_session_data[socket.id].wtvsec) { + if (!zquiet) console.log(" * Encrypting response to client ...") var enc_data = socket_session_data[socket.id].wtvsec.Encrypt(1, data); data = enc_data; } } - // set content-length after encryption - if (!headers_obj["Content-length"] && !headers_obj["Content-Length"]) { - if (typeof data.length !== 'undefined') { - headers_obj['Content-Length'] = data.length; - } else if (typeof data.byteLength !== 'undefined') { - headers_obj['Content-Length'] = data.byteLength; - } + // fix captialization + if (headers_obj["Content-length"]) { + delete headers_obj["Content-length"]; } + if (headers_obj["Content-type"]) { + headers_obj["Content-Type"] = headers_obj["Content-type"]; + delete headers_obj["Content-type"]; + } + + // calculate content length + if (typeof data.length !== 'undefined') { + headers_obj["Content-Length"] = data.length; + } else if (typeof data.byteLength !== 'undefined') { + headers_obj["Content-Length"] = data.byteLength; + } + + // header object to string - console.log(" * Outgoing headers on socket ID", socket.id, headers_obj); + if (zshowheaders) console.log(" * Outgoing headers on socket ID", socket.id, headers_obj); Object.keys(headers_obj).forEach(function (k) { if (k == "http_response") { headers += headers_obj[k] + "\r\n"; @@ -464,18 +480,21 @@ async function sendToClient(socket, headers_obj, data) { toClient = headers + "\n" + data; socket.write(toClient); } else if (typeof data == 'object') { + if (zquiet) var verbosity_mod = (headers_obj["wtv-encrypted"] == 'true') ? " encrypted response" : ""; if (socket_session_data[socket.id].secure_headers == true) { // encrypt headers + if (zquiet)verbosity_mod += " with encrypted headers"; var enc_headers = socket_session_data[socket.id].wtvsec.Encrypt(1, headers + "\n"); socket.write(new Uint8Array(concatArrayBuffer(enc_headers, data))); } else { socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + "\n"), data))); } + if (zquiet) console.log(" * Sent" + verbosity_mod + " " + headers_obj.http_response + " to client (Content-Type:", headers_obj['Content-Type'], "~", headers_obj['Content-Length'], "bytes)"); } socket_session_data[socket.id].buffer = null; if (socket_session_data[socket.id].close_me) socket.end(); - if (headers_obj['Connection']) { - if (headers_obj['Connection'].toLowerCase() == "close" && !headers['wtv-connection-close'] == "false") { + if (headers_obj["Connection"]) { + if (headers_obj["Connection"].toLowerCase() == "close" && !headers["wtv-connection-close"] == "false") { socket.destroy(); } } @@ -511,17 +530,12 @@ function moveObjectElement(currentKey, afterKey, obj) { if (next !== -1) return result; else return obj; } -function headersAreStandard(string, verbose) { +function headersAreStandard(string, verbose = false) { // the test will see the binary compressed/enrypted data as ASCII, so a generic "isAscii" // is not suffuicent. This checks for characters expected in unecrypted headers, and returns // true only if every character in the string matches the regex. Once we know the string is binary // we can better process it with the raw base64 data in processRequest() below. - var test = /^([A-Za-z0-9\+\/\=\-\.\,\ \"\;\:\?\&\r\n\(\)\%\<\>\_]{8,})$/.test(string); - if (verbose) { - if (zdebug) console.log(" # Request is ascii: " + test); - if (zdebug) console.log(" # Request is SECURE ON: " + /^SECURE ON/.test(string)); - } - return test; + return /^([A-Za-z0-9\+\/\=\-\.\,\ \"\;\:\?\&\r\n\(\)\%\<\>\_]{8,})$/.test(string); } async function processRequest(socket, data_hex, returnHeadersBeforeSecure = false, encryptedRequest = false) { @@ -545,7 +559,7 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals if (socket_session_data[socket.id].secure != true) { // first time so reroll sessions if (zdebug) console.log(" # [ UNEXPECTED BINARY BLOCK ] First sign of encryption, re-creating RC4 sessions for socket id", socket.id); - socket_session_data[socket.id].wtvsec = new WTVSec(); + socket_session_data[socket.id].wtvsec = new WTVSec(1,zdebug); socket_session_data[socket.id].wtvsec.IssueChallenge(); socket_session_data[socket.id].wtvsec.SecureOn(); socket_session_data[socket.id].secure = true; @@ -554,7 +568,7 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals if (enc_data.sigBytes > 0) { var dec_data = CryptoJS.lib.WordArray.create(socket_session_data[socket.id].wtvsec.Decrypt(0, enc_data)); var secure_headers = await processRequest(socket, dec_data.toString(CryptoJS.enc.Hex), true, true); - headers['encrypted'] = true; + headers.encrypted = true; Object.keys(secure_headers).forEach(function (k, v) { headers[k] = secure_headers[k]; }); @@ -562,19 +576,19 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals } } - if (headers['wtv-client-serial-number'] != null) { - socket_session_data[socket.id].ssid = headers['wtv-client-serial-number']; + if (headers["wtv-client-serial-number"] != null) { + socket_session_data[socket.id].ssid = headers["wtv-client-serial-number"]; } - if (headers['wtv-client-rom-type'] != null) { + if (headers["wtv-client-rom-type"] != null) { if (socket_session_data[socket.id].ssid) { - setSessionData(socket_session_data[socket.id].ssid, 'wtv-client-rom-type', headers['wtv-client-rom-type']); + setSessionData(socket_session_data[socket.id].ssid, "wtv-client-rom-type", headers["wtv-client-rom-type"]); } } - if (headers['wtv-incarnation'] != null) { + if (headers["wtv-incarnation"] != null) { if (socket_session_data[socket.id].wtvsec) { - socket_session_data[socket.id].wtvsec.set_incarnation(headers['wtv-incarnation']); + socket_session_data[socket.id].wtvsec.set_incarnation(headers["wtv-incarnation"]); } else { - setSessionData(socket_session_data[socket.id].ssid, 'incarnation', headers['wtv-incarnation']) + setSessionData(socket_session_data[socket.id].ssid, "incarnation", headers["wtv-incarnation"]) } } @@ -583,15 +597,16 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals return headers; } - if (headers['secure'] === true) { + if (headers.secure === true) { if (!socket_session_data[socket.id].wtvsec) { - console.log(" * Starting new WTVSec instance on socket", socket.id); - socket_session_data[socket.id].wtvsec = new WTVSec(); - socket_session_data[socket.id].wtvsec.DecodeTicket(headers['wtv-ticket']); - socket_session_data[socket.id].wtvsec.ticket_b64 = headers['wtv-ticket']; - if (getSessionData(socket_session_data[socket.id].ssid, 'incarnation')) { - socket_session_data[socket.id].wtvsec.incarnation = getSessionData(socket_session_data[socket.id].ssid, 'incarnation'); + if (!zquiet) console.log(" * Starting new WTVSec instance on socket", socket.id); + if (getSessionData(socket_session_data[socket.id].ssid, "incarnation")) { + socket_session_data[socket.id].wtvsec = new WTVSec(getSessionData(socket_session_data[socket.id].ssid, "incarnation"), zdebug); + } else { + socket_session_data[socket.id].wtvsec = new WTVSec(1, zdebug); } + socket_session_data[socket.id].wtvsec.DecodeTicket(headers["wtv-ticket"]); + socket_session_data[socket.id].wtvsec.ticket_b64 = headers["wtv-ticket"]; socket_session_data[socket.id].wtvsec.SecureOn(); } if (socket_session_data[socket.id].secure != true) { @@ -599,7 +614,7 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals if (zdebug) console.log(" # [ SECURE ON BLOCK (" + socket.id + ")]"); socket_session_data[socket.id].secure = true; } - if (!headers['request_url']) { + if (!headers.request_url) { if (data_hex.indexOf("0d0a0d0a")) { // \r\n\r\n @@ -614,7 +629,7 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals // some builds (like our targeted 3833), send SECURE ON but then unencrypted headers if (zdebug) console.log(" # Psuedo-encrypted Request (SECURE ON)", "on", socket.id); // don't actually encrypt output - headers['psuedo-encryption'] = true; + headers.psuedo_encryption = true; setSessionData(socket_session_data[socket.id].ssid, 'box-does-psuedo-encryption', true); socket_session_data[socket.id].secure = false; var secure_headers = await processRequest(socket, enc_data.toString(CryptoJS.enc.Hex), true); @@ -633,18 +648,22 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals } } headers = await checkForPostData(socket, headers, data, data_hex); - if (!headers['request_url']) { + if (!headers.request_url) { // still no url, likely lost encryption stream, tell client to relog +/* socket_session_data[socket.id].secure = false; - headers = `200 OK + headers = `300 OK Connection: Keep-Alive Expires: Wed, 09 Oct 1991 22:00:00 GMT wtv-expire-all: wtv-head-waiter: wtv-expire-all: wtv-1800: +Location: client:relog wtv-visit: client:relog Content-type: text/html`; data = ''; + */ delete socket_session_data[socket.id].wtvsec; + socket_session_data[socket.id].close_me = true; sendToClient(socket, headers, data); } else { processURL(socket, headers); @@ -657,8 +676,8 @@ Content-type: text/html`; } async function checkForPostData(socket, headers, data, data_hex) { - if (headers['request']) { - if (headers['request'].substring(0, 4) == "POST") { + if (headers.request) { + if (headers.request.substring(0, 4) == "POST") { if (data_hex.indexOf("0d0a0d0a") != -1) { // \r\n\r\n var header_length = data.length + 4; @@ -673,20 +692,20 @@ async function checkForPostData(socket, headers, data, data_hex) { // some builds (like our targeted 3833), send SECURE ON but then unencrypted headers if (zdebug) console.log(" # Psuedo-encrypted POST Content (SECURE ON)", "on", socket.id); // don't actually encrypt output - headers['psuedo-encryption'] = true; + headers.psuedo_encryption = true; setSessionData(socket_session_data[socket.id].ssid, 'box-does-psuedo-encryption', true); socket_session_data[socket.id].secure = false; - headers['post_data'] = await processRequest(socket, enc_data.toString(CryptoJS.enc.Hex), true); + headers.post_data = await processRequest(socket, enc_data.toString(CryptoJS.enc.Hex), true); } else { // SECURE ON and detected encrypted data setSessionData(socket_session_data[socket.id].ssid, 'box-does-psuedo-encryption', false); - headers['post_data'] = CryptoJS.lib.WordArray.create(socket_session_data[socket.id].wtvsec.Decrypt(0, enc_data)) + headers.post_data = CryptoJS.lib.WordArray.create(socket_session_data[socket.id].wtvsec.Decrypt(0, enc_data)) if (zdebug) console.log(" # Encrypted POST Content (SECURE ON)", "on", socket.id); } } } else { if (zdebug) console.log(" # Unencrypted POST Content", "on", socket.id); - headers['post_data'] = CryptoJS.enc.Hex.parse(socket_session_data[socket.id].buffer.toString(CryptoJS.enc.Hex).substring(header_length * 2)); + headers.post_data = CryptoJS.enc.Hex.parse(socket_session_data[socket.id].buffer.toString(CryptoJS.enc.Hex).substring(header_length * 2)); } } } @@ -695,7 +714,7 @@ async function checkForPostData(socket, headers, data, data_hex) { async function cleanupSocket(socket) { try { - console.log(" * Destroying old WTVSec instance on disconnected socket", socket.id); + if (!zquiet) console.log(" * Destroying old WTVSec instance on disconnected socket", socket.id); delete socket_session_data[socket.id].buffer; delete socket_session_data[socket.id].wtvsec; @@ -769,6 +788,47 @@ Object.keys(services_configured.services).forEach(function (k) { } console.log(" * Configured Service", k, "on Port", services_configured.services[k].port, "- Host", services_configured.services[k].host, "- Bind Port:", !services_configured.services[k].nobind); }) +if (services_configured.config.hide_ssid_in_logs) console.log(" * Masking SSIDs in the console for security"); + +// defaults +var zdebug = false; +var zquiet = true; // will squash zdebug even if its true +var zshowheaders = false; + +if (services_configured.config.verbosity) { + switch (services_configured.config.verbosity) { + case 0: + zdebug = false; + zquiet = true; + zshowheaders = false; + console.log(" * Console Verbosity level 0 (quietest)") + break; + case 1: + zdebug = false; + zquiet = true; + zshowheaders = true; + console.log(" * Console Verbosity level 1 (headers shown)") + break; + case 2: + zdebug = true; + zquiet = true; + zshowheaders = false; + console.log(" * Console Verbosity level 2 (verbose without headers)") + break; + case 3: + zdebug = true; + zquiet = true; + zshowheaders = true; + console.log(" * Console Verbosity level 2 (verbose with headers)") + break; + default: + zdebug = true; + zquiet = false; + zshowheaders = true; + console.log(" * Console Verbosity level 3 (debug verbosity)") + break; + } +} var initstring = ''; ports.sort(); diff --git a/zefie_wtvp_minisrv/package.json b/zefie_wtvp_minisrv/package.json index 273dd83b..a7ab7014 100644 --- a/zefie_wtvp_minisrv/package.json +++ b/zefie_wtvp_minisrv/package.json @@ -1,6 +1,6 @@ { "name": "zefie_wtvp_minisrv", - "version": "0.7.2", + "version": "0.8.0", "description": "WebTV Service (WTVP) Emulation Server", "main": "app.js", "homepage": "https://github.com/zefie/zefie_wtvp_minisrv", diff --git a/zefie_wtvp_minisrv/services.json b/zefie_wtvp_minisrv/services.json index b24ecdb9..7c8b85fd 100644 --- a/zefie_wtvp_minisrv/services.json +++ b/zefie_wtvp_minisrv/services.json @@ -1,7 +1,10 @@ { "config": { "service_ip": "192.168.11.8", - "service_name": "HackTV" + "service_name": "HackTV", + "send_tellyscripts": false, + "hide_ssid_in_logs": true, + "verbosity": 2 }, "services": { "wtv-1800": { @@ -25,7 +28,8 @@ }, "wtv-log": { "port": 1609, - "connections": 1 + "connections": 1, + "write_logs_to_disk": true }, "wtv-home": { "port": 1612, @@ -37,7 +41,8 @@ }, "wtv-flashrom": { "port": 1618, - "flags": "0x00000040" + "flags": "0x00000040", + "use_zefie_server": true }, "wtv-music": { "port": 1656, diff --git a/zefie_wtvp_minisrv/wtvsec.js b/zefie_wtvp_minisrv/wtvsec.js index 7cc8c863..406c3ff2 100644 --- a/zefie_wtvp_minisrv/wtvsec.js +++ b/zefie_wtvp_minisrv/wtvsec.js @@ -18,11 +18,10 @@ class WTVSec { hRC4_Key1 = null; hRC4_Key2 = null; RC4Session = new Array(); - zdebug = false; - constructor(wtv_incarnation = 1) { - this.zdebug = true; + constructor(wtv_incarnation = 1, zdebug = false) { + this.zdebug = zdebug; this.initial_shared_key = CryptoJS.enc.Base64.parse(this.initial_shared_key_b64); if (this.initial_shared_key.sigBytes === 8) { @@ -295,16 +294,6 @@ class WTVSec { } return this.RC4Session[session_id].update(data); } - - Test() { - console.log("TEST RUN"); - console.log("Test python challenge"); - this.current_shared_key = CryptoJS.enc.Base64.parse("CC5rWmRUE0o="); - var current_challenge = "0kjyqIYAu0ziFBbSERN6DGaZ6S0fT+DBUCtpHCJ4lpuM7CbXdAm+x83BIDoJYztd1Z+5KFZ7ghmb3LJCT/6mhWUYkqqKOyfPRW8ZIdbICK/CV+Kxm8EUjRXZSk/97tsmFpH3hcCJ7C2TBw+TX38uQQ=="; - var expected_result = "0kjyqIYAu0zI5QrLhSuEUFgKkoVSxI3zBlUMfhnIYoMy0ExfIX4s/mHvILseDFx+17trk7YO+xG9D2qSY6v9XVUS1OP1m8ee"; - console.log("Expected: " + expected_result); - console.log("Got: " + this.ProcessChallenge(current_challenge)); - } } module.exports = WTVSec; \ No newline at end of file diff --git a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj index 389a659a..67294f82 100644 --- a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj +++ b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj @@ -34,18 +34,149 @@ Code + + Code + + + Code + - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -78,6 +209,9 @@ + + +