- major update: app.js: rewrite socket handling to stream data (fix issues POSTing with shoddy dialup, namely fix wtv-update:/sync issues)
 - update: wtv-home:/home: remove broken irc test, add links to DiskHax and VFatHax, remove URL Accessor form from MiniBrowser because it doesn't work
 - update: wtv-update:/sync: skip file if the Content-length matches the client and the client file is equal or newer, since client is not storing wtv-checksum for some reason. Client file time is set to when the client received the file last, and not actually when the file was modified on our end
 - update: wtv-head-waiter:/login-stage-two: offer prompt to minibrowser to go to home or willie
 - fix: clean up socket session data on socket error
 - code fixup: use `${}` instead of escaping string
 - app.js: better minibrowser session cleanup
 - update: http(s) proxy: do not send internal 'wtv-connection-close' header to client
 - fix: http(s) proxy: handle socks HostUnreachable error
 - fix: wtv-head-waiter:/login-stage-two: usernames longerfix: build 3833 crashes when `wtv-user-name` is too long
 - fix: wtv-log:/log
 - add: wtv-chat
 - add: wtv-setup
This commit is contained in:
zefie
2021-07-22 04:50:33 -04:00
parent 5b6d06241a
commit b0fd271dc3
22 changed files with 515 additions and 154 deletions

View File

@@ -11,6 +11,14 @@ Some values are available that are not defined in `config.json` by default. I wi
``` ```
You can set the image to be loaded in the top left in place of the WebTV or MSN logo, as well as the main Splash image shown on login. You can set the image to be loaded in the top left in place of the WebTV or MSN logo, as well as the main Splash image shown on login.
If an absolute path (`wtv-url:/`, `file://` url, or `http(s)://` url) is not passed, the server will search for the specified filename in `wtv-star/images` of any Service Vault. You'll want to keep the filesizes low. If an absolute path (`wtv-url:/`, `file://` url, or `http(s)://` url) is not passed, the server will search for the specified filename in `wtv-star/images` of any Service Vault. You'll want to keep the filesizes low.
```
"post_debug": true
```
If you would like to see debug information about realtime bytes received from a client POST request, set `post_debug` to true.
```
"post_percentages": [ 0, 25, 50, 100]
```
If you would like to see progress updates on client POST requests, you can define which percentages to show here. Other examples would be `[ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ]` for every 10%, or you could set it to `false`, or `null`, to disable progress updates. Note that percentages are not shown when `post_debug` is enabled.
``` ```
"ssid_block_list": [ "ssid_block_list": [
"8100000000000000", "8100000000000000",

View File

@@ -0,0 +1,174 @@
headers = `200 OK`;
if (request_headers.query.nick) headers += `
wtv-irc-nick: ${request_headers.query.nick}
wtv-user-nick: ${request_headers.query.nick}`
;
headers += `
Content-Type: text/html`;
if (request_headers.query.host && request_headers.query.port && request_headers.query.channel) {
data = `<html>
<display address="${request_headers.query.host}, port ${request_headers.query.port}, room ${request_headers.query.channel}">
<wtvchat
host="${request_headers.query.host}"
port="${request_headers.query.port}"
channel="#${request_headers.query.channel}"
bgcolor="#101C1E"
>
<head>
<title>
${request_headers.query.channel}
</title>
</head>
<body bgcolor="#101C1E" text="#A2ACB5" link="#CFC382" vlink="#E1EOE3" fontsize="medium" vspace=0 hspace=0>
<sidebar width=109>
<table cellspacing=0 cellpadding=0>
<tr>
<td width=104 height=420 bgcolor=#69758B valign=top>
<table cellspacing=0 cellpadding=0>
<tr>
<td height=7 colspan=3>
<spacer type=vertical size=7>
<tr>
<td width=7>
<spacer type=horizontal size=7>
<td width=87 href="wtv-home:/home">
<img src="${minisrv_config.config.service_logo}" width=87 height=67>
<td width=10>
<spacer type=horizontal size=10>
</table>
<spacer type=vertical size=6>
<table cellspacing=0 cellpadding=0 border=0>
<tr> <td bgcolor=#2E3A54 height=2 width=104 colspan=3>
<tr>
<td width=10 height=26>
<td width=89 valign=middle>
<td width=5>
<tr> <td bgcolor=#2E3A54 height=2 width=104 colspan=3>
<tr>
<td width=10 height=26>
<td width=89 valign=middle>
<td width=5>
<tr> <td bgcolor=#2E3A54 height=2 width=104 colspan=3>
<tr>
<td width=10 height=26>
<td width=89 valign=middle>
<table cellspacing=0 cellpadding=0 href="javascript:void(window.open('newChatChannel.panel'))" >
<tr>
<td height=1>
<tr>
<td><shadow><font sizerange=medium color=#E1EOE3>Create</font></shadow>
</table>
<td width=5>
<tr> <td bgcolor=#2E3A54 height=2 width=104 colspan=3>
<tr>
<td width=10 height=26>
<td width=89 valign=middle>
<table cellspacing=0 cellpadding=0 href="client:ListChannelUsers" >
<tr>
<td height=1>
<tr>
<td><shadow><font sizerange=medium color=#E1EOE3>People</font></shadow>
</table>
<td width=5>
<tr> <td bgcolor=#2E3A54 height=2 width=104 colspan=3>
<tr>
<td width=10 height=26>
<td width=89 valign=middle>
<table cellspacing=0 cellpadding=0 href="client:OpenChatWhisperPanel" >
<tr>
<td height=1>
<tr>
<td><shadow><font sizerange=medium color=#E1EOE3>Whisper</font></shadow>
</table>
<td width=5>
<tr> <td bgcolor=#2E3A54 height=2 width=104 colspan=3>
</table>
<td width=5 bgcolor=#2E3A54>
</table>
</sidebar>
<table cellspacing=0 cellpadding=0 border=0>
<tr>
<td width=451 colspan=2 align=center bgcolor=#2E3A54>
<spacer type=vertical size=13>
<tr>
<td><img src="wtv-chat:/images/top_corner_dark.jpg" width=8 height=8>
<td width=60>
<tr>
<td bgcolor=#101C1E width=13>
<spacer type=horizontal size=13>
<td bgcolor=#101C1E width=438 valign=top>
<table cellspacing=0 cellpadding=0>
<tr>
<td width=105 height=9><spacer type=vertical size=9>
<td>
</table>
<tr>
<td colspan=2>
<table cellspacing=0 cellpadding=0 border=0>
<tr>
<td width=375 height=25 bgcolor=#101C1E gradcolor=#3C4652 gradangle=90>
<table cellspacing=0 cellpadding=0 border=0>
<tr>
<td width=366 valign=middle>&nbsp;&nbsp;
<blackface><font color=#D6D6D6> ${request_headers.query.channel}
</font></blackface><td>
<table cellspacing=0 cellpadding=0 border=0 bgcolor=#3C4652 gradcolor=#2E3A54 gradangle=90>
<tr>
<td><img src="wtv-chat:/images/widget.gif" width=16 height=16>
<td width=3>
<td width=54>
<spacer type=vertical size=1><br>
<a href="wtv-chat:/type"><font size=-1 color=#E7CE4A><b> Go to</b></font></a>
<td width=21>
<img src="wtv-chat:/images/widget.gif" width=16 height=16>
<td width=34>
</table>
</table>
</table>
<spacer type=vertical size=12> <table cellspacing=0 cellpadding=0>
<tr>
<td colspan=3 height=12>
<spacer type=vertical size=12> <tr>
<td abswidth=14>
<td>
<wtvchattranscript height=250 width=100%>
<td abswidth=20>
<tr>
<td height=10>
<tr>
<td>
<td colspan=2 height=2>
<spacer>
<tr>
<td height=1>
<tr>
<td>
<td colspan=2 height=2>
<spacer>
<tr>
<td height=6>
</table>
<table cellspacing=0 cellpadding=0 width=100%>
<tr>
<form action="client:ChatAddMessage" ONSUBMIT="this.chatinput.focus()">
<td abswidth=14>
<td>
<input id="chatinput" name="message" type="text" value="" size=32 bgcolor=262626 text=ffc342 cursor=cc9933 font=proportional selected autoactivate nohighlight>
<td align=right>
<font color=e7ce4a><shadow>
<input type=submit borderimage="file://ROM/Borders/ButtonBorder2.bif" value="Send" usestyle width=80>
<td abswidth=9>
</form>
<tr> <TD HEIGHT=8>
</table>
</body>
</html>`;
} else {
var errpage = doErrorPage("400 Chat requires host, port and channel arguments. Do not use the # on channels.");
headers = errpage[0];
data = errpage[1];
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

View File

@@ -123,7 +123,7 @@ hspace=0 vspace=0 fontsize="large">
<table cellspacing=0 cellpadding=0> <table cellspacing=0 cellpadding=0>
<tr> <tr>
<td width=104 height=74 valign=middle align=center bgcolor="3B3A4D"> <td width=104 height=74 valign=middle align=center bgcolor="3B3A4D">
<img src="`+ minisrv_config.config.service_logo +`" width=87 height=67> <img src="${minisrv_config.config.service_logo}" width=87 height=67>
<td width=20 valign=top align=left bgcolor="3B3A4D"> <td width=20 valign=top align=left bgcolor="3B3A4D">
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=1> <img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=1>
<td colspan=10 width=436 valign=middle align=left bgcolor="3B3A4D"> <td colspan=10 width=436 valign=middle align=left bgcolor="3B3A4D">
@@ -206,9 +206,6 @@ ${flashrom_message}
<td width=104 valign=middle align=center> <td width=104 valign=middle align=center>
<td width=20 valign=middle align=center> <td width=20 valign=middle align=center>
<td colspan=9 width=416 valign=top align=right> <td colspan=9 width=416 valign=top align=right>
<form action="client:gohome">
<input type="submit" value="Cancel Update" text="#CCCCCC" borderimage="file://ROM/Borders/ButtonBorder2.bif">
</form>
<table cellspacing=0 cellpadding=0> <table cellspacing=0 cellpadding=0>
<tr> <tr>
<td width=306 valign=top align=left> <td width=306 valign=top align=left>

View File

@@ -23,7 +23,7 @@ hspace=0 vspace=0 fontsize="large">
<table cellspacing=0 cellpadding=0> <table cellspacing=0 cellpadding=0>
<tr> <tr>
<td width=104 height=74 valign=middle align=center bgcolor="3B3A4D"> <td width=104 height=74 valign=middle align=center bgcolor="3B3A4D">
<img src="`+ minisrv_config.config.service_logo +`" width=87 height=67> <img src="${minisrv_config.config.service_logo}" width=87 height=67>
<td width=20 valign=top align=left bgcolor="3B3A4D"> <td width=20 valign=top align=left bgcolor="3B3A4D">
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=1> <img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=1>
<td colspan=10 width=436 valign=middle align=left bgcolor="3B3A4D"> <td colspan=10 width=436 valign=middle align=left bgcolor="3B3A4D">

View File

@@ -51,7 +51,7 @@ data = `<html>
<table cellspacing=0 cellpadding=0> <table cellspacing=0 cellpadding=0>
<tr> <tr>
<td width=104 height=74 valign=middle align=center bgcolor="3B3A4D"> <td width=104 height=74 valign=middle align=center bgcolor="3B3A4D">
<img src="`+ minisrv_config.config.service_logo +`" width=87 height=67> <img src="${minisrv_config.config.service_logo}" width=87 height=67>
<td width=20 valign=top align=left bgcolor="3B3A4D"> <td width=20 valign=top align=left bgcolor="3B3A4D">
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=1> <img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=1>
<td colspan=10 width=436 valign=middle align=left bgcolor="3B3A4D"> <td colspan=10 width=436 valign=middle align=left bgcolor="3B3A4D">

View File

@@ -16,17 +16,14 @@ if (socket.ssid !== null) {
if (request_headers["wtv-ticket"].length > 8) { if (request_headers["wtv-ticket"].length > 8) {
wtvsec_login.DecodeTicket(request_headers["wtv-ticket"]); wtvsec_login.DecodeTicket(request_headers["wtv-ticket"]);
wtvsec_login.ticket_b64 = request_headers["wtv-ticket"]; wtvsec_login.ticket_b64 = request_headers["wtv-ticket"];
//socket_sessions[socket.id].secure = true;
} }
} else { } else {
challenge_response = wtvsec_login.challenge_response; 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 && 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) { if (challenge_response.toString(CryptoJS.enc.Base64) == client_challenge_response) {
console.log(" * wtv-challenge-response success for " + filterSSID(socket.ssid)); console.log(" * wtv-challenge-response success for " + filterSSID(socket.ssid));
wtvsec_login.PrepareTicket(); wtvsec_login.PrepareTicket();
//socket_sessions[socket.id].secure = true;
} else { } else {
console.log(" * wtv-challenge-response FAILED for " + filterSSID(socket.ssid)); console.log(" * wtv-challenge-response FAILED for " + filterSSID(socket.ssid));
if (zdebug) console.log("Response Expected:", challenge_response.toString(CryptoJS.enc.Base64)); if (zdebug) console.log("Response Expected:", challenge_response.toString(CryptoJS.enc.Base64));
@@ -44,13 +41,13 @@ if (gourl) {
headers = `200 OK headers = `200 OK
Connection: Keep-Alive Connection: Keep-Alive
wtv-open-isp-disabled: false wtv-open-isp-disabled: false
wtv-visit: `+ gourl + ` wtv-visit: ${gourl}
Content-type: text/html`; Content-type: text/html`;
data = ''; data = '';
} }
else { else {
var namerand = Math.floor(Math.random() * 100000); var namerand = Math.floor(Math.random() * 100000);
var nickname = minisrv_config.config.service_name+'_Usr_' + namerand; var nickname = (minisrv_config.config.service_name + '_' + namerand).substring(0, 16);
var userid = '1'+ Math.floor(Math.random() * 1000000000000000000); var userid = '1'+ Math.floor(Math.random() * 1000000000000000000);
var offline_user_list = CryptoJS.enc.Latin1.parse("<user-list>\n\t<user userid=\"" + userid + " user-name=\"" + nickname + "\" first-name=\"" + minisrv_config.config.service_name + "User \" last-name=\\" + namerand + "\" password=\"\" mail-enabled=\"true\" />\n</user-list>").toString(CryptoJS.enc.Base64); var offline_user_list = CryptoJS.enc.Latin1.parse("<user-list>\n\t<user userid=\"" + userid + " user-name=\"" + nickname + "\" first-name=\"" + minisrv_config.config.service_name + "User \" last-name=\\" + namerand + "\" password=\"\" mail-enabled=\"true\" />\n</user-list>").toString(CryptoJS.enc.Base64);
data = ''; data = '';
@@ -63,16 +60,16 @@ wtv-country: US
wtv-language-header: en-US,en wtv-language-header: en-US,en
wtv-visit: client:closeallpanels wtv-visit: client:closeallpanels
wtv-expire-all: client:closeallpanels wtv-expire-all: client:closeallpanels
wtv-offline-user-list: `+ offline_user_list + ` wtv-offline-user-list: ${offline_user_list}
wtv-bypass-proxy: true wtv-bypass-proxy: true
wtv-ticket: `+ wtvsec_login.ticket_b64 + ` wtv-ticket: ${wtvsec_login.ticket_b64}
wtv-messagewatch-checktimeoffset: off wtv-messagewatch-checktimeoffset: off
wtv-input-timeout: 14400 wtv-input-timeout: 14400
wtv-connection-timeout: 90 wtv-connection-timeout: 90
wtv-fader-timeout: 900 wtv-fader-timeout: 900
wtv-ssl-log-url: wtv-log:/log wtv-ssl-log-url: wtv-log:/log
wtv-smartcard-inserted-message: Contacting service wtv-smartcard-inserted-message: Contacting service
user-id: `+ userid + ` user-id: ${userid}
wtv-transition-override: off wtv-transition-override: off
wtv-allow-dsc: true wtv-allow-dsc: true
wtv-messenger-enable: 0 wtv-messenger-enable: 0
@@ -80,12 +77,9 @@ wtv-noback-all: wtv-
wtv-service: reset wtv-service: reset
`+ getServiceString('all') + ` `+ getServiceString('all') + `
wtv-boot-url: wtv-1800:/preregister?relogin=true wtv-boot-url: wtv-1800:/preregister?relogin=true
`; wtv-user-name: ${nickname}
//wtv-ssl-certs-download-url: wtv-head-waiter:/ssl-cert.der wtv-human-name: ${nickname}
//wtv-ssl-certs-checksum: 473926DC1B11F635A6B920953FDCDE6A wtv-irc-nick: ${nickname}
headers += `wtv-user-name: `+ nickname + `
wtv-human-name: `+ nickname + `
wtv-irc-nick: `+ nickname + `
wtv-home-url: wtv-home:/home? wtv-home-url: wtv-home:/home?
wtv-domain: wtv.zefie.com wtv-domain: wtv.zefie.com
wtv-inactive-timeout: 0 wtv-inactive-timeout: 0
@@ -102,6 +96,7 @@ wtv-demo-mode: 0
wtv-wink-deferrer-retries: 3 wtv-wink-deferrer-retries: 3
wtv-offline-mail-enable: false wtv-offline-mail-enable: false
wtv-name-server: 8.8.8.8 wtv-name-server: 8.8.8.8
wtv-settings-url: wtv-setup:/get
wtv-visit: wtv-home:/splash? wtv-visit: wtv-home:/splash?
Content-Type: text/html`; Content-Type: text/html`;
} }

View File

@@ -23,26 +23,31 @@ function go() {
} }
</script> </script>
<h2>Welcome to `+ z_title + `</h2> <h2>Welcome to `+ z_title + `</h2>
<h3>Encryption Status: `+cryptstatus+`</h3> <b>Encryption Status</b>: ${cryptstatus}<br>
Connection Speed: &rate; <b>Connection Speed</b>: &rate;
<p>
<form name=access onsubmit="go()"> <form name=access onsubmit="go()">
<ul> <ul>
<li><a href="client:relog">client:relog (direct)</a></li> <li><a href="client:relog">client:relog (direct)</a></li>
<li><a href="wtv-tricks:/blastcache?return_to=wtv-home:/home">Clear Cache</a></li> <li><a href="wtv-tricks:/blastcache?return_to=wtv-home:/home">Clear Cache</a></li>
<li><a href="wtv-flashrom:/willie">Ultra Willies</a></li> <li><a href="wtv-flashrom:/willie" selected>Ultra Willies</a></li>
<li><a href="wtv-music:/demo/index">MIDI Music Demo</a></li> <li><a href="wtv-music:/demo/index">MIDI Music Demo</a></li>
<li><a href="client:diskhax">DiskHax</a> - <a href="client:vfathax">VFatHax</a></li>
<li>Old MSNTV DealerDemo: <a href="wtv-update:/DealerDemo">Download</a> ~ <a href="file://Disk/Demo/index.html">Access (after Download)</a></li> <li>Old MSNTV DealerDemo: <a href="wtv-update:/DealerDemo">Download</a> ~ <a href="file://Disk/Demo/index.html">Access (after Download)</a></li>
<li><a href="http://duckduckgo.com/lite/">DuckDuckGo Lite</a></li> <li><a href="http://duckduckgo.com/lite/">DuckDuckGo Lite</a></li>`
<li><input name=url `; if (ssid_sessions[socket.ssid].get('wtv-needs-upgrade') != 'true') {
data += `<li><input name=url `;
if (request_headers.query.url) { if (request_headers.query.url) {
data += "value='" + unescape(request_headers.query.url)+"'"; data += "value='" + unescape(request_headers.query.url) + "'";
}
data += `width=250 height=10 bgcolor=#444444 text=#ffdd33 cursor=#cc9933>
<input type=submit value="Access URL">
</form>`
} }
data += `width=250 height=10 bgcolor=#444444 text=#ffdd33 cursor=#cc9933 selected> data += "</li >\n</ul>";
<input type=submit value="Access URL">
</form></li>
</ul>`
if (fs.existsSync(service_vaults[0] + "/" + service_name + "/home.zefie.html")) { if (fs.existsSync(service_vaults[0] + "/" + service_name + "/home.zefie.html")) {
data += fs.readFileSync(service_vaults[0] + "/" + service_name + "/home.zefie.html", { 'encoding': 'utf8' }); data += fs.readFileSync(service_vaults[0] + "/" + service_name + "/home.zefie.html", { 'encoding': 'utf8' });

View File

@@ -2,7 +2,7 @@ headers = `200 OK
Connection: Keep-Alive Connection: Keep-Alive
wtv-expire-all: wtv- wtv-expire-all: wtv-
wtv-expire-all: http wtv-expire-all: http
Content-type: text/html` Content-Type: text/html`
data = `<html> data = `<html>
<head> <head>
@@ -15,7 +15,7 @@ data = `<html>
<center> <center>
<spacer type=block height=88 width=21> <spacer type=block height=88 width=21>
<img src="file://ROM/Images/spacer.gif" height=4><br> <img src="file://ROM/Images/spacer.gif" height=4><br>
<img src="`+ minisrv_config.config.service_splash_logo + `"> <img src="${minisrv_config.config.service_splash_logo}">
<br><br><br> <br><br><br>
<p><br> <p><br>
<p><br> <p><br>
@@ -23,14 +23,13 @@ data = `<html>
<tr><td width=150> <tr><td width=150>
Mini service Mini service
<tr><td> <tr><td>
zefie minisrv v`+ minisrv_config.version; zefie minisrv v${minisrv_config.version}`;
if (getGitRevision()) { if (getGitRevision()) {
data += ` (git ` + getGitRevision().substring(0,8) + `)`; data += " (git " + getGitRevision().substring(0, 8) + ")";
} }
data += ` data += `
<tr><td>&rate; <tr><td>&rate;
</table> </table>
</center> </center>
</body> </body>
</html> </html>`;
`;

View File

@@ -1,19 +1,18 @@
// write posted log data to disk. should be decrypted by this point (if it was encrypted) if the crypto stream didn't break // write posted log data to disk. should be decrypted by this point (if it was encrypted) if the crypto stream didn't break
request_is_async = true; request_is_async = true;
data = '';
var fullpath = __dirname + "/ServiceLogPost/" + Math.floor(new Date().getTime() / 1000) + "_" + request_headers.query.type;
if (socket.ssid) fullpath += "_" + socket.ssid;
fullpath += ".txt";
fullpath = fullpath.replace(/\\/g, "/");
if (request_headers.post_data) { if (request_headers.post_data) {
headers = `200 OK headers = `200 OK
Connection: Keep-Alive Connection: Keep-Alive
Content-length: 0`; Content-length: 0`;
data = '';
var fullpath = __dirname + "/ServiceLogPost/" + Math.floor(new Date().getTime() / 1000) + "_" + request_headers.query.type;
if (socket.ssid) fullpath += "_" + socket.ssid;
fullpath += ".txt";
fullpath = fullpath.replace(/\\/g, "/");
var logdata_outstring = ''; var logdata_outstring = '';
Object.keys(request_headers.query).forEach(function (k) { Object.keys(request_headers.query).forEach(function (k) {
logdata_outstring += k + "=" + unescape(request_headers.query[k].toString()) + "\r\n"; logdata_outstring += k + "=" + unescape(request_headers.query[k].toString()) + "\r\n";
@@ -35,7 +34,6 @@ Content-length: 0`;
Connection: Keep-Alive Connection: Keep-Alive
Content-length: 0`; Content-length: 0`;
data = '';
var logdata_outstring = ''; var logdata_outstring = '';
Object.keys(request_headers.query).forEach(function (k) { Object.keys(request_headers.query).forEach(function (k) {
logdata_outstring += k + "=" + unescape(request_headers.query[k].toString()) + "\r\n"; logdata_outstring += k + "=" + unescape(request_headers.query[k].toString()) + "\r\n";

View File

@@ -0,0 +1,31 @@
headers = `200 OK
Content-Type: text/html`
var settings_obj = new Array();
settings_obj["from-server"] = 1;
settings_obj["setup-advanced-options"] = 0;
settings_obj["setup-play-bgm"] = 0;
settings_obj["setup-bgm-tempo"] = -1;
settings_obj["setup-bgm-volume"] = 100;
settings_obj["setup-background-color"] = "c6c6c6";
settings_obj["setup-font-sizes"] = "medium";
settings_obj["setup-in-stereo"] = 1;
settings_obj["setup-keyboard"] = "alphabetical";
settings_obj["setup-link-color"] = "2222bb";
settings_obj["setup-play-songs"] = 1;
settings_obj["setup-play-sounds"] = 1;
settings_obj["setup-text-color"] = 0;
settings_obj["setup-visited-color"] = "8822bb";
settings_obj["setup-japan-keyboard"] = "roman";
settings_obj["setup-japan-softkeyboard"] = "norm"
settings_obj["setup-chat-access-level"] = 0;
settings_obj["setup-chat-on-nontrusted-pages"] = 1;
settings_obj["setup-tv-chat-level"] = 2;
data = "";
Object.keys(settings_obj).forEach(function (k, v) {
data += k + "=" + escape(settings_obj[k]) + "&";
});
data = data.substring(0, (data.length - 1));

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -83,7 +83,7 @@ function processGroup(diskmap_primary_group, diskmap_group_data, diskmap_subgrou
if (!post_data_fileinfo[post_data_filecount]) post_data_fileinfo[post_data_filecount] = new Array(); if (!post_data_fileinfo[post_data_filecount]) post_data_fileinfo[post_data_filecount] = new Array();
if (post_data_line_name == "Last-modified") { if (post_data_line_name == "Last-modified") {
post_data_fileinfo[post_data_filecount][post_data_line_name] = (Date.parse(post_data_line_data) / 1000); post_data_fileinfo[post_data_filecount][post_data_line_name] = (new Date(new Date(Date.parse(post_data_line_data)).toUTCString()) / 1000);
} else if (post_data_line_name == "Content-length") { } else if (post_data_line_name == "Content-length") {
post_data_fileinfo[post_data_filecount][post_data_line_name] = parseInt(post_data_line_data); post_data_fileinfo[post_data_filecount][post_data_line_name] = parseInt(post_data_line_data);
} }
@@ -107,14 +107,17 @@ function processGroup(diskmap_primary_group, diskmap_group_data, diskmap_subgrou
if (!fs.existsSync(post_match_file)) post_match_file = null; if (!fs.existsSync(post_match_file)) post_match_file = null;
}); });
var post_match_file_lstat = fs.lstatSync(post_match_file); var file_in_postdata = function (post_file) {
var post_match_result = post_data_fileinfo.find(el => el.file === diskmap_group_data.files[k].file) || null; return post_file.file === diskmap_group_data.files[k].file
}
var post_match_file_lstat = fs.lstatSync(post_match_file);
var post_match_result = post_data_fileinfo.find(file_in_postdata) || null;
var post_match_file_data = new Buffer.from(fs.readFileSync(post_match_file, { var post_match_file_data = new Buffer.from(fs.readFileSync(post_match_file, {
encoding: null, encoding: null,
flags: 'r' flags: 'r'
})); }));
diskmap_group_data.files[k]["Last-modified"] = (post_match_file_lstat.mtime / 1000); diskmap_group_data.files[k]["Last-modified"] = (new Date(new Date(post_match_file_lstat.mtime).toUTCString()) / 1000);
diskmap_group_data.files[k]["Content-length"] = post_match_file_lstat.size; diskmap_group_data.files[k]["Content-length"] = post_match_file_lstat.size;
diskmap_group_data.files[k]["wtv-checksum"] = CryptoJS.MD5(CryptoJS.lib.WordArray.create(post_match_file_data)).toString(CryptoJS.enc.Hex).toLowerCase(); diskmap_group_data.files[k]["wtv-checksum"] = CryptoJS.MD5(CryptoJS.lib.WordArray.create(post_match_file_data)).toString(CryptoJS.enc.Hex).toLowerCase();
if (!diskmap_group_data.files[k].display) diskmap_group_data.files[k].display = diskmap_group_data.display; if (!diskmap_group_data.files[k].display) diskmap_group_data.files[k].display = diskmap_group_data.display;
@@ -122,6 +125,9 @@ function processGroup(diskmap_primary_group, diskmap_group_data, diskmap_subgrou
if (post_match_result) { if (post_match_result) {
// md5s match, so client doesn't need file // md5s match, so client doesn't need file
if (diskmap_group_data.files[k]['wtv-checksum'].toLowerCase() == post_match_result["wtv-checksum"]) return; if (diskmap_group_data.files[k]['wtv-checksum'].toLowerCase() == post_match_result["wtv-checksum"]) return;
// last modified is equal to or newer than the last update, and file size match, so assume same file and client does not need it
else if ((post_match_result["Last-modified"] >= diskmap_group_data.files[k]["Last-modified"]) && (post_match_result["Content-length"] == diskmap_group_data.files[k]["Content-length"])) return;
// otherwise send to client
else wtv_download_list.push(diskmap_group_data.files[k]); else wtv_download_list.push(diskmap_group_data.files[k]);
} else { } else {
wtv_download_list.push(diskmap_group_data.files[k]); wtv_download_list.push(diskmap_group_data.files[k]);
@@ -170,12 +176,12 @@ if (request_headers.query.diskmap && request_headers.query.group && request_head
var errpage = doErrorPage(404,"The requested DiskMap does not exist."); var errpage = doErrorPage(404,"The requested DiskMap does not exist.");
headers = errpage[0]; headers = errpage[0];
data = errpage[1]; data = errpage[1];
console.log("wtv-update:/sync error", "could not find diskmap"); if (zdebug) console.log(" # wtv-update:/sync error", "could not find diskmap");
} }
} else { } else {
var errpage = doErrorPage(400); var errpage = doErrorPage(400);
headers = errpage[0]; headers = errpage[0];
data = errpage[1]; data = errpage[1];
if (zdebug) console.log("wtv-update:/sync error", "missing query arguments"); if (zdebug) console.log(" # wtv-update:/sync error", "missing query arguments");
} }

View File

@@ -344,8 +344,6 @@ async function doHTTPProxy(socket, request_headers) {
if (res.headers.date) headers.Date = res.headers.date; if (res.headers.date) headers.Date = res.headers.date;
if (res.headers["content-type"]) headers["Content-type"] = res.headers["content-type"]; if (res.headers["content-type"]) headers["Content-type"] = res.headers["content-type"];
if (res.headers.cookie) headers.Cookie = res.headers.cookie; 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.vary) headers.Vary = res.headers.vary;
if (res.headers.location) headers.Location = res.headers.location; 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, 8) == "0d0a0d0a") data_hex = data_hex.substring(8);
@@ -354,9 +352,9 @@ async function doHTTPProxy(socket, request_headers) {
}); });
}).on('error', function (err) { }).on('error', function (err) {
var errpage, headers, data = null; var errpage, headers, data = null;
if (err.code == "ENOTFOUND") { if (err.code == "ENOTFOUND") errpage = doErrorPage(400, `The publisher ${request_data.host} is unknown.`);
errpage = doErrorPage(400,`The publisher ${err.hostname} is unknown.`); else if (err.message.indexOf("HostUnreachable") > 0) errpage = doErrorPage(400, `The publisher ${request_data.host} could not be reached.`);
} else { else {
console.log(" * Unhandled Proxy Request Error:", err); console.log(" * Unhandled Proxy Request Error:", err);
errpage = doErrorPage(400); errpage = doErrorPage(400);
} }
@@ -412,6 +410,12 @@ async function sendToClient(socket, headers_obj, data) {
// string to header object // string to header object
headers_obj = headerStringToObj(headers_obj, true); headers_obj = headerStringToObj(headers_obj, true);
} }
if (!socket_sessions[socket.id]) {
socket.destroy();
return;
}
var wtv_connection_close = headers_obj["wtv-connection-close"];
if (typeof(headers_obj["wtv-connection-close"]) != 'undefined') delete headers_obj["wtv-connection-close"];
// add Connection header if missing, default to Keep-Alive // add Connection header if missing, default to Keep-Alive
if (!headers_obj.Connection) { if (!headers_obj.Connection) {
@@ -501,7 +505,7 @@ async function sendToClient(socket, headers_obj, data) {
socket_sessions[socket.id].buffer = null; socket_sessions[socket.id].buffer = null;
if (socket_sessions[socket.id].close_me) socket.end(); if (socket_sessions[socket.id].close_me) socket.end();
if (headers_obj["Connection"]) { if (headers_obj["Connection"]) {
if (headers_obj["Connection"].toLowerCase() == "close" && !headers["wtv-connection-close"] == "false") { if (headers_obj["Connection"].toLowerCase() == "close" && wtv_connection_close == "true") {
socket.destroy(); socket.destroy();
} }
} }
@@ -547,27 +551,42 @@ function headersAreStandard(string, verbose = false) {
} }
async function processRequest(socket, data_hex, returnHeadersBeforeSecure = false, encryptedRequest = false) { async function processRequest(socket, data_hex, returnHeadersBeforeSecure = false, encryptedRequest = false) {
var url = "";
var data = Buffer.from(data_hex,'hex').toString('ascii');
var headers = new Array(); // TODO: clean up this function (how much is even used anymore?)
var headers = null;
if (socket_sessions[socket.id]) {
if (socket_sessions[socket.id].headers) {
headers = socket_sessions[socket.id].headers;
delete socket_sessions[socket.id].headers;
}
}
var data = Buffer.from(data_hex, 'hex').toString('ascii');
if (typeof data === "string") { if (typeof data === "string") {
if (data.length > 1) { if ((data.indexOf("\r\n\r\n") != -1 || data.indexOf("\n\n") != -1) && typeof socket_sessions[socket.id].post_data == "undefined") {
if (data.indexOf("\r\n\r\n") != -1) { if (data.indexOf("\r\n\r\n") != -1) {
data = data.split("\r\n\r\n")[0]; data = data.split("\r\n\r\n")[0];
} else { } else {
data = data.split("\n\n")[0]; data = data.split("\n\n")[0];
} }
if (headersAreStandard(data)) { if (headersAreStandard(data)) {
headers = headerStringToObj(data); if (headers != null) {
var new_header_obj = headerStringToObj(data);
Object.keys(new_header_obj).forEach(function (k, v) {
headers[k] = new_header_obj[k];
});
new_header_obj = null;
} else {
headers = headerStringToObj(data);
}
} else if (!returnHeadersBeforeSecure) { } else if (!returnHeadersBeforeSecure) {
// if its a POST request, assume its a binary blob and not encrypted (dangerous) // if its a POST request, assume its a binary blob and not encrypted (dangerous)
if (!encryptedRequest) { if (!encryptedRequest) {
// its not a POST and it 1failed the headersAreStandard test, so we think this is an encrypted blob // its not a POST and it failed the headersAreStandard test, so we think this is an encrypted blob
if (socket_sessions[socket.id].secure != true) { if (socket_sessions[socket.id].secure != true) {
// first time so reroll sessions // 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); if (zdebug) console.log(" # [ UNEXPECTED BINARY BLOCK ] First sign of encryption, re-creating RC4 sessions for socket id", socket.id);
socket_sessions[socket.id].wtvsec = new WTVSec(1,zdebug); socket_sessions[socket.id].wtvsec = new WTVSec(1, zdebug);
socket_sessions[socket.id].wtvsec.IssueChallenge(); socket_sessions[socket.id].wtvsec.IssueChallenge();
socket_sessions[socket.id].wtvsec.SecureOn(); socket_sessions[socket.id].wtvsec.SecureOn();
socket_sessions[socket.id].secure = true; socket_sessions[socket.id].secure = true;
@@ -584,10 +603,13 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals
} }
var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data)); var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data));
var secure_headers = await processRequest(socket, dec_data.toString(CryptoJS.enc.Hex), true, true); var secure_headers = await processRequest(socket, dec_data.toString(CryptoJS.enc.Hex), true, true);
headers.encrypted = true; if (secure_headers) {
Object.keys(secure_headers).forEach(function (k, v) { var headers = new Array();
headers[k] = secure_headers[k]; headers.encrypted = true;
}); Object.keys(secure_headers).forEach(function (k, v) {
headers[k] = secure_headers[k];
});
}
} }
} }
} }
@@ -598,7 +620,7 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals
ssid_sessions[socket.ssid] = new ClientSessionData(); ssid_sessions[socket.ssid] = new ClientSessionData();
} }
if (!ssid_sessions[socket.ssid].data_store.sockets) ssid_sessions[socket.ssid].data_store.sockets = new Array(); if (!ssid_sessions[socket.ssid].data_store.sockets) ssid_sessions[socket.ssid].data_store.sockets = new Array();
ssid_sessions[socket.ssid].data_store.sockets.push(socket.id); ssid_sessions[socket.ssid].data_store.sockets.push(socket.id);
} }
var ip2long = function (ip) { var ip2long = function (ip) {
@@ -626,9 +648,9 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals
}; };
var rejectSSIDConnection = function (ssid, blacklist) { var rejectSSIDConnection = function (ssid, blacklist) {
if (blacklist) console.log(" * Request from SSID", filterSSID(ssid), "(" + socket.remoteAddr + "), but that SSID is in the blacklist, rejecting."); if (blacklist) console.log(" * Request from SSID", filterSSID(ssid), "(" + socket.remoteAddr + "), but that SSID is in the blacklist, rejecting.");
else console.log(" * Request from SSID", filterSSID(socket.ssid), "(" + socket.remoteAddress + "), but that SSID is not in the whitelist, rejecting."); else console.log(" * Request from SSID", filterSSID(socket.ssid), "(" + socket.remoteAddress + "), but that SSID is not in the whitelist, rejecting.");
var errpage = doErrorPage(401, "Access to this service is denied."); var errpage = doErrorPage(401, "Access to this service is denied.");
headers = errpage[0]; headers = errpage[0];
data = errpage[1]; data = errpage[1];
@@ -713,7 +735,6 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals
} }
if (returnHeadersBeforeSecure) { if (returnHeadersBeforeSecure) {
headers = await checkForPostData(socket, headers, data, data_hex);
return headers; return headers;
} }
@@ -735,13 +756,13 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals
socket_sessions[socket.id].secure = true; socket_sessions[socket.id].secure = true;
} }
if (!headers.request_url) { if (!headers.request_url) {
var header_length = 0;
if (data_hex.indexOf("0d0a0d0a")) { if (data_hex.indexOf("0d0a0d0a")) {
// \r\n\r\n // \r\n\r\n
var header_length = data.length + 4; header_length = data.length + 4;
} else if (data_hex.indexOf("0a0a")) { } else if (data_hex.indexOf("0a0a")) {
// \n\n // \n\n
var header_length = data.length + 2; header_length = data.length + 2;
} }
var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2)); var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2));
if (enc_data.sigBytes > 0) { if (enc_data.sigBytes > 0) {
@@ -752,12 +773,13 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals
headers.psuedo_encryption = true; headers.psuedo_encryption = true;
ssid_sessions[socket.ssid].set("box-does-psuedo-encryption", true); ssid_sessions[socket.ssid].set("box-does-psuedo-encryption", true);
socket_sessions[socket.id].secure = false; socket_sessions[socket.id].secure = false;
var secure_headers = await processRequest(socket, enc_data.toString(CryptoJS.enc.Hex), true); var secure_headers = await processRequest(socket, enc_data.toString(CryptoJS.enc.Hex), true, true);
} else { } else {
// SECURE ON and detected encrypted data // SECURE ON and detected encrypted data
ssid_sessions[socket.ssid].set("box-does-psuedo-encryption", false); ssid_sessions[socket.ssid].set("box-does-psuedo-encryption", false);
var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data)) var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data))
var secure_headers = await processRequest(socket, dec_data.toString(CryptoJS.enc.Hex), true); var secure_headers = await processRequest(socket, dec_data.toString(CryptoJS.enc.Hex), true, true);
if (!secure_headers) return;
if (zdebug) console.log(" # Encrypted Request (SECURE ON)", "on", socket.id); if (zdebug) console.log(" # Encrypted Request (SECURE ON)", "on", socket.id);
if (zshowheaders) console.log(secure_headers); if (zshowheaders) console.log(secure_headers);
if (!secure_headers.request) { if (!secure_headers.request) {
@@ -775,57 +797,162 @@ async function processRequest(socket, data_hex, returnHeadersBeforeSecure = fals
}); });
} }
} }
} else {
headers = await checkForPostData(socket, headers, data, data_hex);
} }
if (!headers.request_url) {
// still no url, likely lost encryption stream, tell client to relog // handle POST
/* if (headers['request']) {
socket_sessions[socket.id].secure = false; if (headers['request'].substring(0, 4) == "POST") {
headers = `300 OK if (typeof socket_sessions[socket.id].post_data == "undefined") {
Connection: Keep-Alive if (socket_sessions[socket.id].post_data_percents_shown) delete socket_sessions[socket.id].post_data_percents_shown;
Expires: Wed, 09 Oct 1991 22:00:00 GMT socket_sessions[socket.id].post_data_length = headers['Content-length'] || headers['Content-Length'] || 0;
wtv-expire-all: wtv-head-waiter: socket_sessions[socket.id].post_data_length = parseInt(socket_sessions[socket.id].post_data_length);
wtv-expire-all: wtv-1800: socket_sessions[socket.id].post_data = "";
Location: client:relog socket_sessions[socket.id].headers = headers;
wtv-visit: client:relog var post_string = "POST";
Content-type: text/html`; if (socket_sessions[socket.id].secure == true) {
data = ''; post_string = "Encrypted " + post_string;
*/ } else {
socket_sessions[socket.id].secure = false // if the request is not encrypted, the client may have just sent the data with the primary headers, so lets look for that.
socket_sessions[socket.id].close_me = true; if (data_hex.indexOf("0d0a0d0a") != -1) socket_sessions[socket.id].post_data = data_hex.substring(data_hex.indexOf("0d0a0d0a") + 8);
delete socket_sessions[socket.id].wtvsec; if (data_hex.indexOf("0a0a") != -1) socket_sessions[socket.id].post_data = data_hex.substring(data_hex.indexOf("0a0a") + 4);
sendToClient(socket, headers, data); }
if (socket_sessions[socket.id].post_data.length == (socket_sessions[socket.id].post_data_length * 2)) {
// got all expected data
console.log(" * Incoming", post_string, "request on", socket.id, "from", filterSSID(socket.ssid), "to", headers['request_url'], "(got all expected", socket_sessions[socket.id].post_data_length, "bytes of data from client already)");
headers.post_data = CryptoJS.enc.Hex.parse(socket_sessions[socket.id].post_data);
processURL(socket, headers);
} else {
// expecting more data (see below)
console.log(" * Incoming", post_string, "request on", socket.id, "from", filterSSID(socket.ssid), "to", headers['request_url'], "(expecting", socket_sessions[socket.id].post_data_length, "bytes of data from client...)");
}
if (socket_sessions[socket.id].post_data.length > (socket_sessions[socket.id].post_data_length * 2)) {
// got too much data ? ... should not ever reach this code
var errpage = doErrorPage(400, "Received too much data in POST request<br>Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length);
headers = errpage[0];
data = errpage[1];
sendToClient(socket, headers, data);
return;
}
return;
}
} else {
delete socket_sessions[socket.id].headers;
delete socket_sessions[socket.id].post_data;
delete socket_sessions[socket.id].post_data_length;
processURL(socket, headers);
return;
}
} else { } else {
processURL(socket, headers); socket_sessions[socket.id].headers = headers;
} }
} else { } else {
// socket error, terminate it. // handle streaming POST
socket.destroy(); if (typeof socket_sessions[socket.id].post_data != "undefined" && headers) {
} socket_sessions[socket.id].headers = headers;
} if (socket_sessions[socket.id].post_data.length < (socket_sessions[socket.id].post_data_length * 2)) {
} new_header_obj = null;
var enc_data = CryptoJS.enc.Hex.parse(data_hex);
if (socket_sessions[socket.id].secure) {
// decrypt if encrypted
var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data))
} else {
// just pass it over
var dec_data = enc_data;
}
async function checkForPostData(socket, headers, data, data_hex) { socket_sessions[socket.id].post_data += dec_data.toString(CryptoJS.enc.Hex);
if (headers.request) {
if (headers.request.substring(0, 4) == "POST") { var post_string = "POST";
if (data_hex.indexOf("0d0a0d0a") != -1) { if (socket_sessions[socket.id].secure == true) post_string = "Encrypted " + post_string;
// \r\n\r\n
var header_length = data.length + 4; if (minisrv_config.config.post_debug) {
} else if (data_hex.indexOf("0a0a") != -1) { // `post_debug` logging of every chunk
// \n\n console.log(" * ", Math.floor(new Date().getTime() / 1000), "Receiving", post_string, "data on", socket.id, "[", socket_sessions[socket.id].post_data.length / 2, "of", socket_sessions[socket.id].post_data_length, "bytes ]");
var header_length = data.length + 2; } else {
} // calculate and display percentage of data received
var post_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2)); var getPercentage = function(partialValue, totalValue) {
if (socket_sessions[socket.id].secure == true) { return Math.floor((100 * partialValue) / totalValue);
if (zdebug) console.log(" # Encrypted POST Content (SECURE ON)", "on", socket.id, "[", post_data.sigBytes, "bytes ]"); }
} else { var postPercent = getPercentage(socket_sessions[socket.id].post_data.length, (socket_sessions[socket.id].post_data_length * 2));
if (zdebug) console.log(" # Unencrypted POST Content", "on", socket.id); if (minisrv_config.config.post_percentages) {
} if (minisrv_config.config.post_percentages.includes(postPercent)) {
headers.post_data = post_data; if (!socket_sessions[socket.id].post_data_percents_shown) socket_sessions[socket.id].post_data_percents_shown = new Array();
if (!socket_sessions[socket.id].post_data_percents_shown[postPercent]) {
console.log(" * Received", postPercent, "% of", socket_sessions[socket.id].post_data_length, "bytes on", socket.id, "from", filterSSID(socket.ssid));
socket_sessions[socket.id].post_data_percents_shown[postPercent] = true;
}
if (postPercent == 100) delete socket_sessions[socket.id].post_data_percents_shown;
}
}
}
}
if (socket_sessions[socket.id].post_data.length == (socket_sessions[socket.id].post_data_length * 2)) {
// got all expected data
headers.post_data = CryptoJS.enc.Hex.parse(socket_sessions[socket.id].post_data);
if (socket_sessions[socket.id].secure == true) {
if (zdebug) console.log(" # Encrypted POST Content (SECURE ON)", "on", socket.id, "[", headers.post_data.sigBytes, "bytes ]");
} else {
if (zdebug) console.log(" # Unencrypted POST Content", "on", socket.id);
}
delete socket_sessions[socket.id].headers;
delete socket_sessions[socket.id].post_data;
delete socket_sessions[socket.id].post_data_length;
processURL(socket, headers);
return;
}
if (socket_sessions[socket.id].post_data.length > (socket_sessions[socket.id].post_data_length * 2)) {
// got too much data ? ... should not ever reach this code
var errpage = doErrorPage(400, "Received too much data in POST request<br>Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length);
headers = errpage[0];
data = errpage[1];
sendToClient(socket, headers, data);
return;
}
} else if (!returnHeadersBeforeSecure) {
if (!encryptedRequest) {
if (socket_sessions[socket.id].secure != true) {
socket_sessions[socket.id].wtvsec = new WTVSec(1, zdebug);
socket_sessions[socket.id].wtvsec.IssueChallenge();
socket_sessions[socket.id].wtvsec.SecureOn();
socket_sessions[socket.id].secure = true;
}
var enc_data = CryptoJS.enc.Hex.parse(data_hex);
if (enc_data.sigBytes > 0) {
if (!socket_sessions[socket.id].wtvsec) {
var errpage = doErrorPage(400);
var headers = errpage[0];
headers += "wtv-visit: client:relog\n";
data = errpage[1];
sendToClient(socket, headers, data);
return;
}
var str_test = enc_data.toString(CryptoJS.enc.Latin1);
if (headersAreStandard(str_test)) {
var dec_data = enc_data;
} else {
var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data));
}
var secure_headers = await processRequest(socket, dec_data.toString(CryptoJS.enc.Hex), false, true);
if (secure_headers) {
if (!headers) headers = new Array();
headers.encrypted = true;
Object.keys(secure_headers).forEach(function (k, v) {
headers[k] = secure_headers[k];
});
if (headers['request']) {
if (headers['request'].substring(0, 4) == "POST" && !socket_sessions[socket.id].post_data) {
socket_sessions[socket.id].post_data_length = headers['Content-length'] || headers['Content-Length'] || 0;
socket_sessions[socket.id].post_data = "";
}
processRequest(socket, dec_data.toString(CryptoJS.enc.Hex));
}
}
}
}
}
} }
} }
return headers;
} }
async function cleanupSocket(socket) { async function cleanupSocket(socket) {
@@ -844,6 +971,10 @@ async function cleanupSocket(socket) {
// if last socket for SSID disconnected, destroy login session // if last socket for SSID disconnected, destroy login session
if (!zquiet) console.log(" * Last socket from WebTV SSID", filterSSID(socket.ssid),"disconnected, cleaning up primary WTVSec instance for this SSID"); if (!zquiet) console.log(" * Last socket from WebTV SSID", filterSSID(socket.ssid),"disconnected, cleaning up primary WTVSec instance for this SSID");
ssid_sessions[socket.ssid].delete("wtvsec_login"); ssid_sessions[socket.ssid].delete("wtvsec_login");
// clean up possible minibrowser session data
if (ssid_sessions[socket.ssid].get("wtv-needs-upgrade")) ssid_sessions[socket.ssid].delete("wtv-needs-upgrade");
if (ssid_sessions[socket.ssid].get("wtv-used-8675309")) ssid_sessions[socket.ssid].delete("wtv-used-8675309");
} }
} }
socket.end(); socket.end();
@@ -856,38 +987,32 @@ async function cleanupSocket(socket) {
async function handleSocket(socket) { async function handleSocket(socket) {
// create unique socket id with client address and port // create unique socket id with client address and port
socket.id = parseInt(crc16('CCITT-FALSE', Buffer.from(String(socket.remoteAddress) + String(socket.remotePort), "utf8")).toString(16), 16); socket.id = parseInt(crc16('CCITT-FALSE', Buffer.from(String(socket.remoteAddress) + String(socket.remotePort), "utf8")).toString(16), 16);
socket_sessions[socket.id] = []; socket_sessions[socket.id] = [];
socket.setEncoding('hex'); //set data encoding (Text: 'ascii', 'utf8' ~ Binary: 'hex', 'base64' (do not trust 'binary' encoding)) socket.setEncoding('hex'); //set data encoding (Text: 'ascii', 'utf8' ~ Binary: 'hex', 'base64' (do not trust 'binary' encoding))
// NOTE: As it stands we use a 'timeout' to start processing data when we have not recieved any data
// from the client in X time (defined in config, in milliseconds). The problem with this is in the case of
// a modem retrain during a request.
// TODO: Properly know when client is done sending data, by parsing headers.
// Caveat of this is that sometimes the Content-length header does not exist, or will be encrypted.
socket.on('data', function (data_hex) { socket.on('data', function (data_hex) {
socket.setTimeout(minisrv_config.config.socket_timeout); // the timeout mentioned above if (!socket_sessions[socket.id].secure) {
// buffer unencrypted data until we see the classic double-newline, or get blank
// Store all received data into a buffer. Kind of misleading as its not a true JS Buffer if (!socket_sessions[socket.id].header_buffer) socket_sessions[socket.id].header_buffer = "";
// but instead a CryptoJS WordArray socket_sessions[socket.id].header_buffer += data_hex;
if (socket_sessions[socket.id].buffer) { var header_buffer_text = CryptoJS.enc.Hex.parse(socket_sessions[socket.id].header_buffer).toString(CryptoJS.enc.Latin1);
socket_sessions[socket.id].buffer.concat(CryptoJS.enc.Hex.parse(data_hex)); if (header_buffer_text.indexOf("\r\n\r\n") != -1 || header_buffer_text.indexOf("\n\n") != -1 || header_buffer_text == "") {
data_hex = socket_sessions[socket.id].header_buffer;
delete socket_sessions[socket.id].header_buffer;
processRequest(this, data_hex);
}
} else { } else {
socket_sessions[socket.id].buffer = CryptoJS.enc.Hex.parse(data_hex); // stream encrypted requests through the processor
processRequest(this, data_hex);
} }
}); });
socket.on('timeout', async function () { socket.on('timeout', function () {
// start the async chain cleanupSocket(socket);
if (socket_sessions[socket.id].buffer) {
// process the request if the buffer exists
processRequest(this, socket_sessions[socket.id].buffer.toString(CryptoJS.enc.Hex));
}
}); });
socket.on('error', (err) => { socket.on('error', (err) => {
socket.end(); cleanupSocket(socket);
}); });
socket.on('end', function () { socket.on('end', function () {
@@ -942,12 +1067,20 @@ function getGitRevision() {
} }
// SERVER START // SERVER START
var git_commit = getGitRevision()
var z_title = "zefie's wtv minisrv v" + require('./package.json').version; if (git_commit) {
var z_title = "zefie's wtv minisrv v" + require('./package.json').version + " (git " + git_commit.substring(0,8) + ")";
} else {
var z_title = "zefie's wtv minisrv v" + require('./package.json').version;
}
console.log("**** Welcome to " + z_title + " ****"); console.log("**** Welcome to " + z_title + " ****");
console.log(" *** Reading global configuration..."); console.log(" *** Reading global configuration...");
try { try {
var minisrv_config = JSON.parse(fs.readFileSync(__dirname + "/config.json")); var minisrv_config = JSON.parse(fs.readFileSync(__dirname + "/config.json"));
if (git_commit) {
minisrv_config.config.git_commit = git_commit;
delete this.git_commit;
}
} catch (e) { } catch (e) {
throw ("ERROR: Could not read config.json", e); throw ("ERROR: Could not read config.json", e);
} }
@@ -1016,8 +1149,8 @@ Object.keys(minisrv_config.services).forEach(function (k) {
if (minisrv_config.config.hide_ssid_in_logs) console.log(" * Masking SSIDs in console logs for security"); if (minisrv_config.config.hide_ssid_in_logs) console.log(" * Masking SSIDs in console logs for security");
else console.log(" * Full SSIDs will be shown in console logs"); else console.log(" * Full SSIDs will be shown in console logs");
if (minisrv_config.config.service_logo.indexOf(':') == -1) minisrv_config.config.service_logo = "wtv-star:/images/" + minisrv_config.config.service_logo; if (minisrv_config.config.service_logo.indexOf(':') == -1) minisrv_config.config.service_logo = "wtv-star:/ROMCache/" + minisrv_config.config.service_logo;
if (minisrv_config.config.service_splash_logo.indexOf(':') == -1) minisrv_config.config.service_splash_logo = "wtv-star:/images/" + minisrv_config.config.service_splash_logo; if (minisrv_config.config.service_splash_logo.indexOf(':') == -1) minisrv_config.config.service_splash_logo = "wtv-star:/ROMCache/" + minisrv_config.config.service_splash_logo;
minisrv_config.version = require('./package.json').version; minisrv_config.version = require('./package.json').version;

View File

@@ -9,7 +9,7 @@
"service_logo": "MSNLogo.gif", "service_logo": "MSNLogo.gif",
"service_splash_logo": "splash_logo_msn.gif", "service_splash_logo": "splash_logo_msn.gif",
"hide_ssid_in_logs": true, "hide_ssid_in_logs": true,
"socket_timeout": 350, "post_percentages": [ 0, 25, 50, 100],
"verbosity": 2 "verbosity": 2
}, },
"services": { "services": {
@@ -55,6 +55,16 @@
"flags": "0x04", "flags": "0x04",
"connections": 3 "connections": 3
}, },
"wtv-setup": {
"port": 1613,
"flags": "0x00000010",
"connections": 3
},
"wtv-chat": {
"port": 1630,
"connections": 3,
"flags": "0x00000010"
},
"http": { "http": {
"port": 1650, "port": 1650,
"connections": 3, "connections": 3,

View File

@@ -1,6 +1,6 @@
{ {
"name": "zefie_wtvp_minisrv", "name": "zefie_wtvp_minisrv",
"version": "0.9.4", "version": "0.9.5",
"description": "WebTV Service (WTVP) Emulation Server", "description": "WebTV Service (WTVP) Emulation Server",
"main": "app.js", "main": "app.js",
"homepage": "https://github.com/zefie/zefie_wtvp_minisrv", "homepage": "https://github.com/zefie/zefie_wtvp_minisrv",

View File

@@ -32,6 +32,7 @@
<Content Include=".gitignore" /> <Content Include=".gitignore" />
<Content Include="app.js" /> <Content Include="app.js" />
<Content Include="config.json" /> <Content Include="config.json" />
<Content Include="ServiceVault\wtv-chat\MakeChatPage.js" />
<Content Include="ServiceVault\wtv-flashrom\get-by-path.js"> <Content Include="ServiceVault\wtv-flashrom\get-by-path.js">
<SubType>Code</SubType> <SubType>Code</SubType>
</Content> </Content>
@@ -174,9 +175,11 @@
<Content Include="ServiceVault\wtv-music\demo\midi\Wind1.mid" /> <Content Include="ServiceVault\wtv-music\demo\midi\Wind1.mid" />
<Content Include="ServiceVault\wtv-music\demo\midi\Xess.mid" /> <Content Include="ServiceVault\wtv-music\demo\midi\Xess.mid" />
<Content Include="ServiceVault\wtv-music\demo\music.jpg" /> <Content Include="ServiceVault\wtv-music\demo\music.jpg" />
<Content Include="ServiceVault\wtv-star\images\HackTVLogo.gif" /> <Content Include="ServiceVault\wtv-setup\get.js">
<Content Include="ServiceVault\wtv-star\images\HackTVLogoJewel.gif" /> <SubType>Code</SubType>
<Content Include="ServiceVault\wtv-star\images\WebTVLogoJewel.gif" /> </Content>
<Content Include="ServiceVault\wtv-star\ROMCache\HackTVLogoJewel.gif" />
<Content Include="ServiceVault\wtv-star\ROMCache\WebTVLogoJewel.gif" />
<Content Include="ServiceVault\wtv-tricks\access.js" /> <Content Include="ServiceVault\wtv-tricks\access.js" />
<Content Include="ServiceVault\wtv-tricks\blastcache.js" /> <Content Include="ServiceVault\wtv-tricks\blastcache.js" />
<Content Include="ServiceVault\wtv-tricks\go-offline.js" /> <Content Include="ServiceVault\wtv-tricks\go-offline.js" />
@@ -211,13 +214,15 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="ServiceVault\" /> <Folder Include="ServiceVault\" />
<Folder Include="ServiceVault\wtv-chat\" />
<Folder Include="ServiceVault\wtv-flashrom\" /> <Folder Include="ServiceVault\wtv-flashrom\" />
<Folder Include="ServiceVault\wtv-flashrom\ROMCache\" /> <Folder Include="ServiceVault\wtv-flashrom\ROMCache\" />
<Folder Include="ServiceVault\wtv-music\" /> <Folder Include="ServiceVault\wtv-music\" />
<Folder Include="ServiceVault\wtv-music\demo\" /> <Folder Include="ServiceVault\wtv-music\demo\" />
<Folder Include="ServiceVault\wtv-music\demo\midi\" /> <Folder Include="ServiceVault\wtv-music\demo\midi\" />
<Folder Include="ServiceVault\wtv-setup\" />
<Folder Include="ServiceVault\wtv-star\" /> <Folder Include="ServiceVault\wtv-star\" />
<Folder Include="ServiceVault\wtv-star\images\" /> <Folder Include="ServiceVault\wtv-star\ROMCache\" />
<Folder Include="ServiceVault\wtv-tricks\" /> <Folder Include="ServiceVault\wtv-tricks\" />
<Folder Include="ServiceVault\wtv-update\" /> <Folder Include="ServiceVault\wtv-update\" />
<Folder Include="ServiceVault\wtv-1800\" /> <Folder Include="ServiceVault\wtv-1800\" />