|
|
@@ -92,7 +91,7 @@ data += `
-
+
${flashrom_info.message}
|
|
|
-
+
|
|
|
@@ -119,7 +118,7 @@ ${flashrom_info.message}
|
|
|
-
+
|
|
|
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js
index b22756f3..3a00509a 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js
@@ -1,13 +1,12 @@
if (request_headers.query.path) {
-var url = "wtv-flashrom:/get-lc2-page?path=" + request_headers.query.path;
+var url = service_name + ":/get-lc2-page?path=" + request_headers.query.path;
var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
if (romtype == "bf0app") {
- url = "client:updateflash?ipaddr=" + minisrv_config.services[service_name].host + "&port=" + minisrv_config.services[service_name].port + "&path=" + escape(url.replace("get-lc2-page", "get-by-path"));
+ url = "client:updateflash?ipaddr=" + minisrv_config.services[service_name].host + "&port=" + minisrv_config.services[service_name].port + "&path=" + escape(service_name + ":/" +request_headers.query.path);
if (request_headers.query.numparts) url += escape("&numparts=" + request_headers.query.numparts);
}
- headers = "300 OK\n";
+ headers = "200 OK\n";
headers += "wtv-visit: " + url + "\n";
- headers += "Location: " + url + "\n";
headers += "Content-type: text/html";
data = '';
} else {
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 61ee429e..b072fe81 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-complete.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-complete.js
@@ -25,12 +25,12 @@ hspace=0 vspace=0 fontsize="large">
|
|
-
+
|
-
+
Updating complete
@@ -38,7 +38,7 @@ Updating complete
|
-
+
|
|
|
@@ -65,7 +65,7 @@ The update is complete.
|
|
|
-
+
|
|
|
@@ -74,7 +74,7 @@ The update is complete.
|
|
|
-
+
|
|
|
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.js
index 3cb3fa17..3f6e1b91 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.js
@@ -32,7 +32,7 @@ if (request_headers.query.error) {
}
-var try_again_url = 'wtv-flashrom:/willie';
+var try_again_url = service_name + ":/willie";
var try_again_url_path = ''
var try_again_url_start_time = parseInt(new Date().toUTCString()) / 1000;
@@ -53,12 +53,12 @@ data = `
|
|
-
+
|
-
+
Updating failed
@@ -66,7 +66,7 @@ data = `
|
-
+
|
|
|
@@ -96,7 +96,7 @@ data = `
|
|
|
-
+
|
|
|
@@ -105,7 +105,7 @@ data = `
|
|
|
-
+
|
|
|
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js
index 2600705c..765de4e3 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js
@@ -9,7 +9,7 @@ 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;
+ proxy_query += "&" + key + "=" + escape(value);
}
if (!minisrv_config.services[service_name].use_zefie_server) {
@@ -18,7 +18,7 @@ if (!minisrv_config.services[service_name].use_zefie_server) {
var options = {
host: "wtv.zefie.com",
- path: "/willie.php?minisrv=true&pflash=" + ssid_sessions[socket.ssid].get("wtv-client-rom-type") + proxy_query,
+ path: "/willie.php?minisrv=true&service_name="+escape(service_name)+"&pflash=" + ssid_sessions[socket.ssid].get("wtv-client-rom-type") + proxy_query,
timeout: 5000,
method: 'GET'
}
@@ -42,7 +42,7 @@ const req = https.request(options, function (res) {
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";
+ headers += "\nwtv-expire-all: "+service_name;
}
sendToClient(socket, headers, data);
});
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 415f3b64..fde0566b 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
@@ -31,11 +31,10 @@ if (socket.ssid !== null) {
}
}
-if (!ssid_sessions[socket.ssid].getSessionData("registered") && (!request_headers.query.guest_login || !minisrv_config.config.allow_guests)) gourl = "wtv-register:/splash";
+if (!ssid_sessions[socket.ssid].getSessionData("registered") && (!request_headers.query.guest_login || !minisrv_config.config.allow_guests)) gourl = "wtv-register:/splash?";
if (gourl) {
headers = `200 OK
-Connection: Close
wtv-open-isp-disabled: false
`;
if (!ssid_sessions[socket.ssid].getSessionData("registered") && (!request_headers.query.guest_login || !minisrv_config.config.allow_guests)) {
@@ -44,7 +43,7 @@ wtv-ticket: ${wtvsec_login.ticket_b64}
${getServiceString('wtv-register')}
${getServiceString('wtv-head-waiter')}
${getServiceString('wtv-star')}
-wtv-boot-url: wtv-register:/splash
+wtv-boot-url: wtv-head-waiter:/relogin?
`
}
headers += `wtv-visit: ${gourl}
@@ -127,11 +126,11 @@ wtv-connection-timeout: 90
wtv-show-time-enabled: true
wtv-fader-timeout: 900
wtv-tourist-enabled: true`
- headers += "\nwtv-relogin-url: wtv-1800:/preregister?relogin=true";
+ headers += "\nwtv-relogin-url: wtv-head-waiter:/relogin?relogin=true";
if (request_headers.query.guest_login) headers += "&guest_login=true";
- headers += "\nwtv-reconnect-url: wtv-1800:/preregister?reconnect=true";
+ headers += "\nwtv-reconnect-url: wtv-head-waiter:/relogin?reconnect=true";
if (request_headers.query.guest_login) headers += "&guest_login=true";
- headers += "\nwtv-boot-url: wtv-1800:/preregister?relogin=true";
+ headers += "\nwtv-boot-url: wtv-head-waiter:/relogin?relogin=true";
if (request_headers.query.guest_login) headers += "&guest_login=true";
headers += "\nwtv-allow-dsc: true";
headers += "\nwtv-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 ae847962..9f44b498 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js
@@ -53,8 +53,8 @@ wtv-expire-all: wtv-head-waiter:
wtv-log-url: wtv-log:/log`;
if (challenge_header != "") headers += "\n" + challenge_header;
headers += `
-wtv-relogin-url: wtv-1800:/preregister?relogin=true
-wtv-reconnect-url: wtv-1800:/preregister?reconnect=true
+wtv-relogin-url: wtv-head-waiter:/relogin?relogin=true
+wtv-reconnect-url: wwtv-head-waiter:/relogin?reconnect=true
wtv-visit: ${gourl}
Content-type: text/html`;
data = '';
@@ -66,7 +66,7 @@ Connection: Keep-Alive
Expires: Wed, 09 Oct 1991 22:00:00 GMT
wtv-expire-all: wtv-head-waiter:
wtv-expire-all: wtv-1800:
-wtv-visit: wtv-1800:/preregister?relogin=true
+wtv-visit: wtv-head-waiter:/relogin?relogin=true
Content-type: text/html`;
data = '';
}
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js
new file mode 100644
index 00000000..52cb2023
--- /dev/null
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js
@@ -0,0 +1,20 @@
+var gourl = "wtv-1800:/preregister?";
+if (request_headers.query.relogin) gourl += "relogin=true";
+else if (request_headers.query.reconnect) gourl += "reconnect=true";
+
+if (request_headers.query.guest_login) {
+ if (request_headers.query.relogin || request_headers.query.reconnect) gourl += "&";
+ gourl += "guest_login=true";
+ if (request_headers.query.skip_splash) gourl += "&skip_splash=true";
+}
+
+headers = `200 OK
+Connection: Keep-Alive
+Expires: Wed, 09 Oct 1991 22:00:00 GMT
+wtv-expire-all: wtv-head-waiter:
+wtv-expire-all: wtv-1800:
+wtv-service: reset
+${getServiceString('wtv-1800')}
+wtv-visit: ${gourl}
+Content-type: text/html`;
+data = '';
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js b/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js
index 214d201b..56e1609a 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js
@@ -12,6 +12,16 @@ if (ssid_sessions[socket.ssid].get('box-does-psuedo-encryption')) {
var cryptstatus = ((socket_sessions[socket.id].secure === true) ? "Encrypted" : "Not Encrypted")
}
+var comp_type = shouldWeCompress(socket.ssid,'text/html');
+var compstatus = "uncompressed";
+switch (comp_type) {
+ case 1:
+ compstatus = "wtv-lzpf";
+ break;
+ case 2:
+ compstatus = "gzip (level 9)";
+ break;
+}
data = `
@@ -24,13 +34,16 @@ function go() {
location.href=document.access.url.value;
}
-Welcome to `+ z_title + `
-`;
-if (minisrv_config.config.git_commit) data += "" + " ".repeat(32) + "git revision " + minisrv_config.config.git_commit + " ";
+Welcome to ${z_title}`;
+if (ssid_sessions[socket.ssid].getSessionData("registered")) data += ", " + ssid_sessions[socket.ssid].getSessionData("subscriber_username") + "!";
+data += " ";
+if (minisrv_config.config.git_commit) data += `git revision ${minisrv_config.config.git_commit} `;
+
data += `
-Encryption Status: ${cryptstatus}
+
+Status: ${cryptstatus} (${compstatus})
Connection Speed: &rate;
-
+
|
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/tricks.js b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/tricks.js
index f994ee0f..acc79f73 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/tricks.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/tricks.js
@@ -20,13 +20,13 @@ data = `
| Info
|
- | List Cookies
+ | List Cookies
|
|
|
| Visit Ultra Willie's!
|
- | Clear Cookies
+ | Clear Cookies
|
|
|
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/DealerDemo.js b/zefie_wtvp_minisrv/ServiceVault/wtv-update/DealerDemo.js
deleted file mode 100644
index ecf03f93..00000000
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-update/DealerDemo.js
+++ /dev/null
@@ -1,51 +0,0 @@
-headers = `200 OK
-Content-Type: text/html`
-
-data = `
-
-
-
- Retrieving Files
-
-
-
-
-
-
- |
-
-
-
-
-
- Retrieving Files
-
-
-
- |
- |
- |
- |
- |
- |
- |
- |
-
- Your Internet terminal is retrieving some files.
- This may take a while.
-
- |
- |
- |
-
-
-
-
- | |
-
-`
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/sync.js b/zefie_wtvp_minisrv/ServiceVault/wtv-update/sync.js
deleted file mode 100644
index 032a8dc5..00000000
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-update/sync.js
+++ /dev/null
@@ -1,187 +0,0 @@
-// todo: async
-
-var path = require("path");
-
-var content_dir = "content/"
-var diskmap_dir = content_dir + "diskmaps/";
-
-function generateDownloadList(diskmap_group_data, update_list, diskmap_data) {
- // create WebTV Download List
-
- var newest_file_epoch = 0;
- var download_list = '';
-
- if (diskmap_data.partition_size) {
- download_list += "CREATE " + diskmap_data.base + "\n";
- download_list += "partition-size: " + diskmap_data.partition_size + "\n\n";
- }
-
- download_list += "CREATE-GROUP " + diskmap_group_data + "-UPDATE\n";
- download_list += "state: invalid\n";
- download_list += "base: " + diskmap_data.base + ".GROUP-UPDATE/\n\n";
-
- Object.keys(update_list).forEach(function (k) {
- if (parseInt(update_list[k]["Last-modified"]) > newest_file_epoch) newest_file_epoch = parseInt(update_list[k]["Last-modified"]);
- download_list += "DISPLAY " + update_list[k].display + "\n\n";
- download_list += "GET " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
- download_list += "group: " + diskmap_group_data + "-UPDATE\n";
- download_list += "location: " + service_name + ":/" + update_list[k].location + "\n";
- download_list += "file-permission: r\n"
- download_list += "wtv-checksum: " + update_list[k]["wtv-checksum"] + "\n";
- download_list += "service-source-location: /webtv/content/" + service_name.replace("wtv-","") + "d/" + update_list[k].location + "\n";
- download_list += "client-dest-location: " + update_list[k].file + "\n\n";
- });
-
- download_list += "CREATE-GROUP " + diskmap_group_data + "\n";
- download_list += "state: invalid\n";
- download_list += "service-owned: " + (diskmap_data.service_owned || false) + "\n";
- download_list += "base: " + diskmap_data.base + "\n\n";
-
- Object.keys(update_list).forEach(function (k) {
- download_list += "DELETE " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
- download_list += "group: " + diskmap_group_data + "\n\n";
- });
-
- Object.keys(update_list).forEach(function (k) {
- download_list += "RENAME " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
- download_list += "group: " + diskmap_group_data + "-UPDATE\n";
- download_list += "destination-group: " + diskmap_group_data + "\n";
- download_list += "location: " + update_list[k].file.replace(diskmap_data.base, "") + "\n\n";
- });
-
- download_list += "DELETE-GROUP " + diskmap_group_data + "-UPDATE\n\n";
-
- download_list += "SET-GROUP " + diskmap_group_data + "\n";
- download_list += "state: ok\n";
- download_list += "version: " + newest_file_epoch + "\n";
- download_list += "last-checkup-time: " + new Date().toUTCString().replace("GMT", "+0000") + "\n\n";
-
- return download_list;
-}
-
-function processGroup(diskmap_primary_group, diskmap_group_data, diskmap_subgroup = null) {
- // parse webtv post
- var output_data = '';
- var post_data = request_headers.post_data.toString(CryptoJS.enc.Latin1).split("\n");
- var post_data_current_directory = '';
- var post_data_current_file = '';
- var post_data_fileinfo = new Array();
- var post_data_filecount = -1;
-
- Object.keys(post_data).forEach(function (k) {
- if (post_data[k] == "") return;
- if (post_data[k].substring(0, 7) == "file://") {
- post_data_current_directory = post_data[k];
- post_data_current_file = post_data[k];
- }
- if (post_data[k].indexOf(":") > 0) {
- var post_data_line = post_data[k].split(": ")
- var post_data_line_name = post_data_line[0];
- post_data_line.shift();
- var post_data_line_data = post_data_line.join(": ");
-
- if (!post_data_fileinfo[post_data_filecount]) post_data_fileinfo[post_data_filecount] = new Array();
-
- if (post_data_line_name == "Last-modified") {
- 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") {
- post_data_fileinfo[post_data_filecount][post_data_line_name] = parseInt(post_data_line_data);
- }
- else {
- post_data_fileinfo[post_data_filecount][post_data_line_name] = post_data_line_data;
- }
- } else {
- post_data_filecount++;
- post_data_current_file = post_data_current_directory + post_data[k];
- post_data_fileinfo[post_data_filecount] = new Array();
- post_data_fileinfo[post_data_filecount].file = post_data_current_file
- }
- });
- var wtv_download_list = new Array();
- Object.keys(diskmap_group_data.files).forEach(function (k) {
- if (!diskmap_group_data.files[k].location) diskmap_group_data.files[k].location = diskmap_group_data.location + diskmap_group_data.files[k].file.replace(diskmap_group_data.base, "");
- var post_match_file = null;
- Object.keys(service_vaults).forEach(function (g) {
- if (post_match_file != null) return;
- post_match_file = service_vaults[g] + "/" + service_name + "/" + diskmap_group_data.files[k].location;
- if (!fs.existsSync(post_match_file)) post_match_file = null;
- });
-
- var file_in_postdata = function (post_file) {
- 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, {
- encoding: null,
- flags: 'r'
- }));
- 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]["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 (post_match_result) {
- // md5s match, so client doesn't need file
- 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]);
- }
- var diskmap_group_name = (diskmap_subgroup == null) ? diskmap_primary_group : diskmap_primary_group + "-" + diskmap_subgroup;
- output_data = generateDownloadList(diskmap_group_name, wtv_download_list, diskmap_group_data)
- });
- return output_data;
-}
-
-if (request_headers.query.diskmap && request_headers.query.group && request_headers.post_data) {
- var diskmap_json_file = null;
- Object.keys(service_vaults).forEach(function (g) {
- if (diskmap_json_file != null) return;
- diskmap_json_file = service_vaults[g] + "/" + service_name + "/" + diskmap_dir + request_headers.query.diskmap + ".json";
- if (!fs.existsSync(diskmap_json_file)) diskmap_json_file = null;
- });
-
- if (diskmap_json_file != null) {
- if (fs.lstatSync(diskmap_json_file)) {
- try {
- // read diskmap
- var diskmap_data = JSON.parse(fs.readFileSync(diskmap_json_file).toString());
- if (!diskmap_data[request_headers.query.group]) {
- throw ("Invalid diskmap data (group does not match)");
- }
- data = '';
- diskmap_data = diskmap_data[request_headers.query.group];
- if (!diskmap_data.display) {
- Object.keys(diskmap_data).forEach(function (k) {
- if (diskmap_data[k]) data += processGroup(request_headers.query.group,diskmap_data[k],k);
- });
- } else {
- data = processGroup(request_headers.query.group, diskmap_data);
- }
-
- headers = "200 OK\nContent-Type: wtv/download-list";
- } catch (e) {
- var errpage = doErrorPage(400);
- headers = errpage[0];
- data = errpage[1];
- console.log("wtv-update:/sync error", e);
- }
- }
- } else {
- var errpage = doErrorPage(404,"The requested DiskMap does not exist.");
- headers = errpage[0];
- data = errpage[1];
- if (zdebug) console.log(" # wtv-update:/sync error", "could not find diskmap");
- }
-} else {
- var errpage = doErrorPage(400);
- headers = errpage[0];
- data = errpage[1];
- if (zdebug) console.log(" # wtv-update:/sync error", "missing query arguments");
-}
-
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/updatesuccess.txt b/zefie_wtvp_minisrv/ServiceVault/wtv-update/updatesuccess.txt
deleted file mode 100644
index 9655cb3d..00000000
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-update/updatesuccess.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-200 OK
-Content-Type: text/url
-
-client:ShowAlert?message=HackTV%20Update%20was%20successful%21&buttonlabel2=Go%20to%20HackTV&action2=file%3A%2F%2FDisk%2FBrowser%2FGames%2FGames.html&buttonlabel1=Okay&buttonaction1=client:goback&image=file://disk/browser/Games/hacktv2.gif&noback=true
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/WTVClientSessionData.js b/zefie_wtvp_minisrv/WTVClientSessionData.js
index bf1099dd..d44c948d 100644
--- a/zefie_wtvp_minisrv/WTVClientSessionData.js
+++ b/zefie_wtvp_minisrv/WTVClientSessionData.js
@@ -1,3 +1,5 @@
+const { lib } = require('crypto-js');
+
class WTVClientSessionData {
fs = require('fs');
@@ -38,7 +40,8 @@ class WTVClientSessionData {
}
}
- constructor(hide_ssid_in_logs, session_storage_directory) {
+ constructor(ssid, hide_ssid_in_logs, session_storage_directory) {
+ this.ssid = ssid;
if (hide_ssid_in_logs) this.hide_ssid_in_logs = hide_ssid_in_logs;
if (!session_storage_directory) session_storage_directory = __dirname + "/SessionStore";
this.session_storage = session_storage_directory;
@@ -91,9 +94,6 @@ class WTVClientSessionData {
this.session_store.cookies[cookie_index] = Object.assign({}, cookie_data);
- // do not write file if user is not registered
- if (getSessionData('registered')) this.storeSessionData();
-
return true;
}
@@ -172,11 +172,13 @@ class WTVClientSessionData {
return outstring;
}
- loadSessionData() {
+ loadSessionData(raw_data = false) {
try {
if (this.fs.lstatSync(this.session_storage + this.path.sep + this.ssid + ".json")) {
- var session_data_file = this.fs.readFileSync(this.session_storage + this.path.sep + this.ssid + ".json", 'Utf8');
- var session_data = JSON.parse(session_data_file);
+ var json_data = this.fs.readFileSync(this.session_storage + this.path.sep + this.ssid + ".json", 'Utf8')
+ if (raw_data) return json_data;
+
+ var session_data = JSON.parse(json_data);
this.session_store = session_data;
return true;
}
@@ -188,14 +190,22 @@ class WTVClientSessionData {
}
saveSessionData() {
- if (!this.session_store.registered) {
+ if (this.isRegistered()) {
+ // load data from disk and merge new data
var temp_store = this.session_store;
- this.loadSessionData();
- this.session_store = Object.assign(this.session_store, temp_store);
+ if (this.loadSessionData()) this.session_store = Object.assign(this.session_store, temp_store);
+ else this.session_store = temp_store;
+ temp_store = null;
+ } else {
+ // do not write file if user is not registered, return true because this is not an error
+ return true;
}
+
try {
- var store_data = JSON.stringify(this.session_store);
- this.fs.writeFileSync(this.session_storage + this.path.sep + this.ssid + ".json", store_data, "Utf8");
+ // only save if file has changed
+ var json_save_data = JSON.stringify(this.session_store);
+ var json_load_data = this.loadSessionData(true);
+ if (json_save_data != json_load_data) this.fs.writeFileSync(this.session_storage + this.path.sep + this.ssid + ".json", JSON.stringify(this.session_store), "Utf8");
return true;
} catch (e) {
console.error(" # Error saving session data for", this.filterSSID(this.ssid), e);
@@ -205,7 +215,7 @@ class WTVClientSessionData {
retrieveSessionData() {
// alias
- this.loadSessionData();
+ return this.loadSessionData();
}
storeSessionData() {
@@ -213,16 +223,32 @@ class WTVClientSessionData {
return this.saveSessionData();
}
+ SaveIfRegistered() {
+ if (this.isRegistered()) return this.saveSessionData();
+ return false;
+ }
+
+ isRegistered() {
+ var self = this;
+ var ssid_match = false;
+ this.fs.readdirSync(this.session_storage).forEach(file => {
+ if (!file.match(/.*\.json/ig)) return;
+ if (ssid_match) return;
+ if (file.split('.')[0] == self.ssid) ssid_match = true;
+ });
+ return ssid_match;
+ }
unregisterBox() {
try {
if (this.fs.lstatSync(this.session_storage + this.path.sep + this.ssid + ".json")) {
- return this.fs.unlinkSync(this.session_storage + this.path.sep + this.ssid + ".json");
+ this.fs.unlinkSync(this.session_storage + this.path.sep + this.ssid + ".json");
this.session_store = {};
+ return true;
}
} catch (e) {
// Don't log error 'file not found', it just means the client isn't registered yet
- if (e.code != "ENOENT") console.error(" # Error deleting session data for", this.filterSSID(this.ssid), e);
+ console.error(" # Error deleting session data for", this.filterSSID(this.ssid), e);
return false;
}
}
diff --git a/zefie_wtvp_minisrv/WTVFlashrom.js b/zefie_wtvp_minisrv/WTVFlashrom.js
index 478e5629..986c4666 100644
--- a/zefie_wtvp_minisrv/WTVFlashrom.js
+++ b/zefie_wtvp_minisrv/WTVFlashrom.js
@@ -43,7 +43,7 @@ class WTVFlashrom {
}
- async doLocalFlashROM(flashrom_file_path, callback, info_only = false) {
+ async doLocalFlashROM(flashrom_file_path, request_path, callback, info_only = false) {
// use local flashrom files;
console.log(info_only);
var self = this;
@@ -56,7 +56,7 @@ class WTVFlashrom {
callback(data, headers);
} else {
if (info_only) {
- callback(self.getFlashromData(data, flashrom_file_path));
+ callback(self.getFlashromInfo(data, request_path));
} else {
self.sendToClient(data, flashrom_file_path, callback);
}
@@ -117,7 +117,7 @@ class WTVFlashrom {
flashrom_info.message = new Buffer.from(part_header.toString('hex').substring(36 * 2, 68 * 2), 'hex').toString('ascii').replace(/[^0-9a-z\ \.\-]/gi, "");
flashrom_info.is_last_part = ((flashrom_info.byte_progress + flashrom_info.part_total_size) == flashrom_info.total_parts_size) ? true : false;
- flashrom_info.rompath = 'wtv-flashrom:/get-by-path?path=' + path + '&raw=true';
+ flashrom_info.rompath = `wtv-flashrom:/${path}`;
if (this.zdebug) console.log(" # Flashrom Part Bytes Sent (after this part):", flashrom_info.byte_progress + flashrom_info.part_total_size);
if (this.zdebug) console.log(" # Flashrom Part is Last Part", flashrom_info.is_last_part);
@@ -202,7 +202,7 @@ class WTVFlashrom {
});
req.end();
} else {
- this.doLocalFlashROM(flashrom_file_path, callback, ((length != 0) ? true : false));
+ this.doLocalFlashROM(flashrom_file_path, request_path, callback, ((length != 0) ? true : false));
}
}
}
diff --git a/zefie_wtvp_minisrv/WTVLzpf.js b/zefie_wtvp_minisrv/WTVLzpf.js
index 27b09cf8..5bfea2ea 100644
--- a/zefie_wtvp_minisrv/WTVLzpf.js
+++ b/zefie_wtvp_minisrv/WTVLzpf.js
@@ -1,5 +1,3 @@
-var EventEmitter = require('events').EventEmitter;
-
/**
* Pure-JS implementation of WebTV's LZPF compression
*
@@ -25,6 +23,7 @@ class WTVLzpf {
encoded_data = [];
nomatchEncode = [
+
[0x0000, 0x10], [0x0001, 0x10], [0x0002, 0x10],
[0x0003, 0x10], [0x0004, 0x10], [0x009A, 0x0F],
[0x0005, 0x10], [0x009C, 0x0F], [0x009E, 0x0F],
@@ -413,8 +412,8 @@ class WTVLzpf {
* @returns {Buffer} Lzpf compression data
*/
Finish() {
- var code_length = -1
- var code = -1
+ var code_length = -1;
+ var code = -1;
if (this.type_index == 2) {
this.EncodeLiteral(0x10, 0x00990000);
@@ -482,4 +481,4 @@ class WTVLzpf {
}
}
-module.exports = WTVLzpf;
\ No newline at end of file
+module.exports = WTVLzpf;
diff --git a/zefie_wtvp_minisrv/app.js b/zefie_wtvp_minisrv/app.js
index 95752d97..ac1624bb 100644
--- a/zefie_wtvp_minisrv/app.js
+++ b/zefie_wtvp_minisrv/app.js
@@ -2,6 +2,7 @@
const fs = require('fs');
const path = require('path');
+const zlib = require('zlib');
const http = require('http');
const https = require('https');
const strftime = require('strftime'); // used externally by service scripts
@@ -73,24 +74,31 @@ function getFileExt(path) {
return path.reverse().split(".")[0].reverse();
}
-function doErrorPage(code, data = null) {
+function doErrorPage(code, data = null, pc_mode = false) {
var headers = null;
switch (code) {
case 404:
if (data === null) data = "The service could not find the requested page.";
- headers = "404 " + data + "\r\n";
- headers += "Content-Type: text/html\r\n";
+ if (pc_mode) headers = "404 Not Found\n";
+ else headers = code + " "+ data + "\n";
+ headers += "Content-Type: text/html\n";
break;
case 400:
+ case 500:
if (data === null) data = "HackTV ran into a technical problem.";
- headers = "400 " + data + "\r\n";
- headers += "Content-Type: text/html\r\n";
+ if (pc_mode) headers = "500 Internal Server Error\n";
+ else headers = code + " " + data + "\n";
+ headers += "Content-Type: text/html\n";
+ break;
+ case 401:
+ if (data === null) data = "Access Denied.";
+ if (pc_mode) headers = "401 Access Denied\n";
+ else headers = code + " " + data + "\n";
+ headers += "Content-Type: text/html\n";
break;
default:
- // what we send when we did not detect a wtv-url.
- // e.g. when a pc browser connects
- headers = "HTTP/1.1 200 OK\r\n";
- headers += "Content-Type: text/html\r\n";
+ headers = code + " " + data + "\n";
+ headers += "Content-Type: text/html\n";
break;
}
console.error("doErrorPage Called:", code, data);
@@ -100,68 +108,94 @@ function doErrorPage(code, data = null) {
function getConType(path) {
var file_ext = getFileExt(path).toLowerCase();
+ var wtv_mime_type = "";
+ var modern_mime_type = "";
// process WebTV overrides, fall back to generic mime lookup
switch (file_ext) {
case "aif":
- return "audio/x-aif";
+ wtv_mime_type = "audio/x-aif";
+ break;
case "aifc":
- return "audio/x-aifc";
+ wtv_mime_type = "audio/x-aifc";
+ break;
case "aiff":
- return "audio/x-aiff";
+ wtv_mime_type = "audio/x-aiff";
+ break;
case "ani":
- return "x-wtv-animation";
+ wtv_mime_type = "x-wtv-animation";
+ break;
case "brom":
- return "binary/x-wtv-bootrom";
+ wtv_mime_type = "binary/x-wtv-bootrom";
+ break;
case "cdf":
- return "application/netcdf";
+ wtv_mime_type = "application/netcdf";
+ break;
case "dat":
- return "binary/cache-data";
+ wtv_mime_type = "binary/cache-data";
+ break;
case "dl":
- return "wtv/download-list";
+ wtv_mime_type = "wtv/download-list";
+ break;
case "gsm":
- return "audio/x-gsm";
+ wtv_mime_type = "audio/x-gsm";
+ break;
case "gz":
- return "application/gzip";
+ wtv_mime_type = "application/gzip";
+ break;
case "ini":
- return "wtv/jack-configuration";
+ wtv_mime_type = "wtv/jack-configuration";
+ break;
case "mips-code":
- return "code/x-wtv-code-mips";
+ wtv_mime_type = "code/x-wtv-code-mips";
+ break;
case "o":
- return "binary/x-wtv-approm";
+ wtv_mime_type = "binary/x-wtv-approm";
+ break;
case "ram":
- return "audio/x-pn-realaudio";
+ wtv_mime_type = "audio/x-pn-realaudio";
+ break;
case "rom":
- return "binary/x-wtv-flashblock";
+ wtv_mime_type = "binary/x-wtv-flashblock";
+ break;
case "rsp":
- return "wtv/jack-response";
+ wtv_mime_type = "wtv/jack-response";
+ break;
case "swa":
case "swf":
- return "application/x-shockwave-flash";
+ wtv_mime_type = "application/x-shockwave-flash";
+ break;
case "srf":
case "spl":
- return "wtv/jack-data";
+ wtv_mime_type = "wtv/jack-data";
+ break;
case "ttf":
- return "wtv/jack-fonts";
+ wtv_mime_type = "wtv/jack-fonts";
+ break;
case "tvch":
- return "wtv/tv-channels";
+ wtv_mime_type = "wtv/tv-channels";
+ break;
case "tvl":
- return "wtv/tv-listings";
+ wtv_mime_type = "wtv/tv-listings";
+ break;
case "tvsl":
- return "wtv/tv-smartlinks";
+ wtv_mime_type = "wtv/tv-smartlinks";
+ break;
case "wad":
- return "binary/doom-data";
+ wtv_mime_type = "binary/doom-data";
+ break;
case "mp2":
case "hsb":
case "rmf":
case "s3m":
case "mod":
case "xm":
- return "application/Music";
+ wtv_mime_type = "application/Music";
+ break;
}
- // if we reach here, its not a WebTV specific override
- // or we are not yet aware of said override
- return mime.lookup(path);
+ modern_mime_type = mime.lookup(path);
+ if (wtv_mime_type == "") wtv_mime_type = modern_mime_type;
+ return new Array(wtv_mime_type, modern_mime_type);
}
async function processPath(socket, service_vault_file_path, request_headers = new Array(), service_name) {
@@ -172,17 +206,35 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
try {
service_vaults.forEach(function (service_vault_dir) {
if (service_vault_found) return;
- service_vault_file_path = makeSafePath(service_vault_dir,service_path);
+ service_vault_file_path = makeSafePath(service_vault_dir, service_path);
+ // deny access to catchall file name directly
+ var service_path_split = service_path.split("/");
+ var service_path_request_file = service_path_split[service_path_split.length - 1];
+ if (minisrv_config.config.catchall_file_name) {
+ var minisrv_catchall = null;
+ if (minisrv_config.services[service_name]) minisrv_catchall = minisrv_config.services[service_name].catchall_file_name || minisrv_config.config.catchall_file_name || null;
+ else minisrv_catchall = minisrv_config.config.catchall_file_name || null;
+ if (minisrv_catchall) {
+ if (service_path_request_file == minisrv_catchall) {
+ var errpage = doErrorPage(401, "Access Denied");
+ headers = errpage[0];
+ data = errpage[1];
+ return;
+ }
+ }
+ }
+ minisrv_catchall, service_path_split, service_path_request_file = null;
if (fs.existsSync(service_vault_file_path)) {
// file exists, read it and return it
service_vault_found = true;
request_is_async = true;
if (!zquiet) console.log(" * Found " + service_vault_file_path + " to handle request (Direct File Mode) [Socket " + socket.id + "]");
- var contype = getConType(service_vault_file_path);
+ var contypes = getConType(service_vault_file_path);
headers = "200 OK\n"
- headers += "Content-Type: " + contype;
+ headers += "Content-Type: " + contypes[0] + "\n";
+ headers += "wtv-modern-content-type" + contypes[1];
fs.readFile(service_vault_file_path, null, function (err, data) {
sendToClient(socket, headers, data);
});
@@ -238,6 +290,31 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
fs.readFile(service_vault_file_path + ".html", null, function (err, data) {
sendToClient(socket, headers, data);
});
+ } else {
+ // look for a catchallin the current path and all parent paths up until the service root
+ if (minisrv_config.config.catchall_file_name) {
+ var minisrv_catchall_file_name = null;
+ if (minisrv_config.services[service_name]) minisrv_catchall_file_name = minisrv_config.services[service_name].catchall_file_name || minisrv_config.config.catchall_file_name || null;
+ else minisrv_catchall_file_name = minisrv_config.config.catchall_file_name || null;
+ if (minisrv_catchall_file_name) {
+ var service_check_dir = service_vault_file_path.split(path.sep);
+ service_check_dir.pop(); // pop filename
+
+ while (service_check_dir.join(path.sep) != service_vault_dir) {
+ var catchall_file = service_check_dir.join(path.sep) + path.sep + minisrv_catchall_file_name;
+ if (fs.existsSync(catchall_file)) {
+ if (!zquiet) console.log(" * Found catchall at " + catchall_file + ".html to handle request (HTML Mode) [Socket " + socket.id + "]");
+ var jscript_eval = fs.readFileSync(catchall_file).toString();
+ // don't pass these vars to the script
+ var service_check_dir, minisrv_catchall_file_name = null;
+ eval(jscript_eval);
+ if (request_is_async && !zquiet) console.log(" * Script requested Asynchronous mode");
+ } else {
+ service_check_dir.pop();
+ }
+ }
+ }
+ }
}
// either `request_is_async`, or `headers` and `data` MUST be defined by this point!
});
@@ -250,12 +327,12 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
if (!request_is_async) {
if (!service_vault_found) {
console.error(" * Could not find a Service Vault for " + service_name + ":/" + service_path.replace(service_name + path.sep, ""));
- var errpage = doErrorPage(404);
+ var errpage = doErrorPage(404, null, socket.minisrv_pc_mode);
headers = errpage[0];
data = errpage[1];
}
if (headers == null && !request_is_async) {
- var errpage = doErrorPage(400);
+ var errpage = doErrorPage(400, null, socket.minisrv_pc_mode);
headers = errpage[0];
data = errpage[1];
console.error(" * Scripting or Data error: Headers were not defined. (headers,data) as follows:")
@@ -279,8 +356,8 @@ function filterSSID(obj) {
return obj.substr(0, 6) + ('*').repeat(9);
}
} else {
- if (obj["wtv-client-serial-number"]) {
- var ssid = obj["wtv-client-serial-number"];
+ if (makeSafeSSID(obj["wtv-client-serial-number"])) {
+ var ssid = makeSafeSSID(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 if (ssid.substr(0, 5) == "1SEGA") {
@@ -296,6 +373,12 @@ function filterSSID(obj) {
}
}
+function makeSafeSSID(ssid = "") {
+ ssid = ssid.replace(/[^a-zA-Z0-9]/g, "");
+ if (ssid.length == 0) ssid = null;
+ return ssid;
+}
+
function makeSafePath(base, target) {
target.replace(/[\|\&\;\$\%\@\"\<\>\+\,\\]/g, "");
if (path.sep != "/") target = target.replace(/\//g, path.sep);
@@ -304,9 +387,6 @@ function makeSafePath(base, target) {
}
async function processURL(socket, request_headers) {
- if (request_headers === null) {
- return;
- }
var shortURL, headers, data = "";
request_headers.query = new Array();
if (request_headers.request_url) {
@@ -353,11 +433,46 @@ async function processURL(socket, request_headers) {
}
}
+ if ((shortURL.indexOf("http") != 0 && shortURL.indexOf("ftp") != 0 && shortURL.indexOf(":") > 0 && shortURL.indexOf(":/") == -1)) {
+ // Apparently it is within WTVP spec to accept urls without a slash (eg wtv-home:home)
+ // Here, we just reassemble the request URL as if it was a proper URL (eg wtv-home:/home)
+ // we will allow this on any service except http(s) and ftp
+ var shortURL_split = shortURL.split(':');
+ var shortURL_service_name = shortURL_split[0];
+ shortURL_split.shift();
+ var shortURL_service_path = shortURL_split.join(":");
+ shortURL = shortURL_service_name + ":/" + shortURL_service_path;
+ } else if (shortURL.indexOf(":") == -1 && request_headers.request.indexOf("HTTP/1") > 0) {
+ if (request_headers.Host) {
+ if (minisrv_config.config.pc_server_hidden_service_enabled) {
+ // browsers typically send a Host header
+ service_name = minisrv_config.config.pc_server_hidden_service;
+ socket.minisrv_pc_mode = true;
+ shortURL = service_name + ":" + shortURL;
+
+ // if a directory, request index
+ if (shortURL.substring(shortURL.length - 1) == "/") shortURL += "index";
+ } else {
+ // minimal pc mode to send error
+ socket.minisrv_pc_mode = true;
+ var errpage = doErrorPage(401, "PC services are disabled on this server", socket.minisrv_pc_mode);
+ headers = errpage[0];
+ data = errpage[1]
+ socket_sessions[socket.id].close_me = true;
+ sendToClient(socket, headers, data);
+ return;
+ }
+ }
+ }
+
if (shortURL.indexOf(':/') >= 0 && shortURL.indexOf('://') < 0) {
var ssid = socket.ssid;
if (ssid == null) {
- ssid = request_headers["wtv-client-serial-number"];
+ // prevent possible injection attacks via SSID and filesystem SessionStore
+ ssid = makeSafeSSID(request_headers["wtv-client-serial-number"]);
+ if (ssid == "") ssid = null;
}
+
var reqverb = "Request";
if (request_headers.encrypted || request_headers.secure) {
reqverb = "Encrypted " + reqverb;
@@ -475,6 +590,7 @@ async function doHTTPProxy(socket, request_headers) {
]);
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);
+ headers["wtv-http-proxy"] = true;
sendToClient(socket, headers, Buffer.from(data_hex,'hex'));
});
}).on('error', function (err) {
@@ -554,8 +670,69 @@ function headerStringToObj(headers, response = false) {
return headers_obj;
}
-async function sendToClient(socket, headers_obj, data) {
+function shouldWeCompress(ssid, headers_obj) {
var compress_data = false;
+ var compression_type = 0; // no compression
+ if (ssid_sessions[ssid]) {
+ if (ssid_sessions[ssid].capabilities) {
+ if (ssid_sessions[ssid].capabilities['client-can-receive-compressed-data']) {
+
+ if (minisrv_config.config.enable_lzpf_compression || minisrv_config.config.force_compression_type) {
+ compression_type = 1; // lzpf
+ }
+
+ if (ssid_sessions[ssid]) {
+ // if gzip is enabled...
+ if (minisrv_config.config.enable_gzip_compression || minisrv_config.config.force_compression_type) {
+ var is_bf0app = ssid_sessions[ssid].get("wtv-client-rom-type") == "bf0app";
+ var is_minibrowser = (ssid_sessions[ssid].get("wtv-needs-upgrade") || ssid_sessions[ssid].get("wtv-used-8675309"));
+ var is_softmodem = ssid_sessions[ssid].get("wtv-client-rom-type").match(/softmodem/);
+ if (!is_bf0app && ((!is_softmodem && !is_minibrowser) || (is_softmodem && !is_minibrowser))) {
+ // softmodem boxes do not appear to support gzip in the minibrowser
+ // LC2 appears to support gzip even in the MiniBrowser
+ // LC2 and newer approms appear to support gzip
+ // bf0app does not appear to support gzip
+ compression_type = 2; // gzip
+ }
+ }
+ }
+
+
+
+ // mostly for debugging
+ if (minisrv_config.config.force_compression_type == "lzpf") compression_type = 1;
+ if (minisrv_config.config.force_compression_type == "gzip") compression_type = 2;
+
+ // do not compress if already encoded
+ if (headers_obj["Content-Encoding"]) return 0;
+
+ // should we bother to compress?
+ var content_type = "";
+ if (typeof (headers_obj) == 'string') content_type = headers_obj;
+ else content_type = (typeof (headers_obj["wtv-modern-content-type"]) != 'undefined') ? headers_obj["wtv-modern-content-type"] : headers_obj["Content-Type"];
+
+ if (content_type) {
+ // both lzpf and gzip
+ if (content_type.match(/^text\//) && content_type != "text/tellyscript") compress_data = true;
+ else if (content_type.match(/^application\/(x-?)javascript$/)) compress_data = true;
+ else if (content_type == "application/json") compress_data = true;
+ if (compression_type == 2) {
+ // gzip only
+ if (content_type.match(/^audio\/(x-)?[s3m|mod|xm]$/)) compress_data = true; // s3m, mod, xm
+ if (content_type.match(/^audio\/(x-)?[midi|wav|wave]$/)) compress_data = true; // midi & wav
+ if (content_type.match(/^binary\/x-wtv-approm$/)) compress_data = true; // midi & wav
+
+ }
+ }
+ }
+ }
+ }
+
+ // return compression_type if compress_data = true
+ return (compress_data) ? compression_type : 0;
+}
+
+async function sendToClient(socket, headers_obj, data) {
var headers = "";
var content_length = 0;
if (typeof (data) === 'undefined') data = '';
@@ -576,11 +753,11 @@ async function sendToClient(socket, headers_obj, data) {
headers_obj = moveObjectElement('Connection', 'http_response', headers_obj);
}
- var clen = 0;
+ var content_length = 0;
if (typeof data.length !== 'undefined') {
- clen = data.length;
+ content_length = data.length;
} else if (typeof data.byteLength !== 'undefined') {
- clen = data.byteLength;
+ content_length = data.byteLength;
}
// fix captialization
@@ -589,31 +766,50 @@ async function sendToClient(socket, headers_obj, data) {
delete headers_obj["Content-type"];
}
-
// if box can do compression, see if its worth enabling
- if (ssid_sessions[socket.ssid].capabilities) {
- if (ssid_sessions[socket.ssid].capabilities['client-can-receive-compressed-data'] && minisrv_config.config.enable_lzpf_compression) {
- compress_data = shouldWeCompress(headers_obj["Content-Type"]);
- }
- }
+ // small files actually get larger, so don't compress them
+ var compression_type = 0;
+ if (content_length >= 256) compression_type = shouldWeCompress(socket.ssid, headers_obj);
// compress if needed
- if (compress_data && clen > 0) {
- content_length = clen;
+ if (compression_type > 0 && content_length > 0 && headers_obj['http_response'].substring(0,3) == "200") {
+ var uncompressed_content_length = content_length;
+ switch (compression_type) {
+ case 1:
+ // wtv-lzpf implementation
+ headers_obj["wtv-lzpf"] = 0;
+ var wtvcomp = new WTVLzpf();
+ data = wtvcomp.Compress(data);
+ wtvcomp = null; // Makes the garbage gods happy so it cleans up our mess
+ break;
- headers_obj["wtv-lzpf"] = 0;
+ case 2:
+ // zlib gzip implementation
+ headers_obj['Content-Encoding'] = 'gzip';
+ data = zlib.gzipSync(data, {
+ 'level': 9
+ });
+ break;
+ }
- var wtvcomp = new WTVLzpf();
- data = wtvcomp.Compress(data);
-
- wtvcomp = null; // Makes the garbage gods happy so it cleans up our mess
+ var compressed_content_length = 0;
+ if (content_length == 0 || compression_type != 1) {
+ // ultimately send compressed content length
+ compressed_content_length = data.byteLength;
+ content_length = compressed_content_length;
+ } else {
+ // ultimately send original content length if lzpf
+ compressed_content_length = data.byteLength;
+ }
+ var compression_percentage = ((compressed_content_length / uncompressed_content_length) * 100).toFixed(1).toString() + "%";
+ if (uncompressed_content_length != compressed_content_length) if (zdebug) console.log(" # Compression stats: Orig Size:", uncompressed_content_length, "~ Comp Size:", compressed_content_length, "~ Ratio:", compression_percentage);
}
// encrypt if needed
if (socket_sessions[socket.id].secure == true) {
headers_obj["wtv-encrypted"] = 'true';
headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj);
- if (clen > 0 && socket_sessions[socket.id].wtvsec) {
+ if (content_length > 0 && socket_sessions[socket.id].wtvsec) {
if (!zquiet) console.log(" * Encrypting response to client ...")
var enc_data = socket_sessions[socket.id].wtvsec.Encrypt(1, data);
data = enc_data;
@@ -625,14 +821,6 @@ async function sendToClient(socket, headers_obj, data) {
if (headers_obj["Content-Length"]) delete headers_obj["Content-Length"];
if (headers_obj["Content-length"]) delete headers_obj["Content-length"];
- if (content_length == 0) {
- if (typeof data.length !== 'undefined') {
- content_length = data.length;
- } else if (typeof data.byteLength !== 'undefined') {
- content_length = data.byteLength;
- }
- }
-
headers_obj["Content-length"] = content_length;
if (ssid_sessions[socket.ssid]) {
@@ -648,10 +836,10 @@ async function sendToClient(socket, headers_obj, data) {
}
var end_of_line = "\n";
- if (headers_obj['minisrv-use-carriage-return'] == "true") end_of_line = "\r\n";
- if (headers_obj['minisrv-use-carriage-return']) delete headers_obj['minisrv-use-carriage-return'];
-
- if (end_of_line == "\r\n" && zdebug) console.log(" * Script requested to send headers with carriage return (out of WTVP Spec)");
+ if (socket.minisrv_pc_mode) {
+ end_of_line = "\r\n";
+ headers_obj['http_response'] = "HTTP/1.0 " + headers_obj['http_response'];
+ }
// header object to string
if (zshowheaders) console.log(" * Outgoing headers on socket ID", socket.id, (await filterSSID(headers_obj)));
@@ -684,7 +872,7 @@ async function sendToClient(socket, headers_obj, data) {
} else {
socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + end_of_line), 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)");
+ if (zquiet) console.log(" * Sent" + verbosity_mod + " " + headers_obj.http_response + " to client (Content-Type:", headers_obj['Content-Type'], "~", headers_obj['Content-length'], "bytes)");
}
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
@@ -698,25 +886,12 @@ async function sendToClient(socket, headers_obj, data) {
if (socket_sessions[socket.id].close_me) socket.end();
if (headers_obj["Connection"]) {
- if (headers_obj["Connection"].toLowerCase() == "close" || wtv_connection_close == "true") {
+ if (headers_obj["Connection"].toLowerCase() == "close" && wtv_connection_close == "true") {
socket.destroy();
}
}
}
-function shouldWeCompress(content_type) {
- if (typeof (content_type) != 'undefined') {
- if ((content_type.match(/^text\//) && content_type != "text/tellyscript") ||
- content_type.match(/^application\/(x-?)javascript$/) ||
- content_type.match(/^audio\/(x-)?midi/) ||
- content_type.match(/^audio\/(x-)?wav/) ||
- content_type == "application/json") {
- return true;
- }
- }
- return false;
-}
-
function concatArrayBuffer(buffer1, buffer2) {
var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
tmp.set(new Uint8Array(buffer1), 0);
@@ -757,7 +932,7 @@ function isUnencryptedString(string, verbose = false) {
}
function filterSSID(ssid) {
- var WTVCSD = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs);
+ var WTVCSD = new WTVClientSessionData(null,minisrv_config.config.hide_ssid_in_logs);
return WTVCSD.filterSSID(ssid);
}
@@ -827,14 +1002,17 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
if (!headers) return;
- if (headers["wtv-client-serial-number"] != null) {
- socket.ssid = headers["wtv-client-serial-number"];
- if (!ssid_sessions[socket.ssid]) {
- ssid_sessions[socket.ssid] = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs);
+ if (headers["wtv-client-serial-number"] != null && socket.ssid == null) {
+ socket.ssid = makeSafeSSID(headers["wtv-client-serial-number"]);
+ if (socket.ssid != null) {
+ if (!ssid_sessions[socket.ssid]) {
+ ssid_sessions[socket.ssid] = new WTVClientSessionData(socket.ssid,minisrv_config.config.hide_ssid_in_logs);
+ ssid_sessions[socket.ssid].SaveIfRegistered();
+ }
+ if (!ssid_sessions[socket.ssid].data_store.sockets) ssid_sessions[socket.ssid].data_store.sockets = new Set();
+ ssid_sessions[socket.ssid].ssid = socket.ssid;
+ ssid_sessions[socket.ssid].data_store.sockets.add(socket);
}
- if (!ssid_sessions[socket.ssid].data_store.sockets) ssid_sessions[socket.ssid].data_store.sockets = new Set();
- ssid_sessions[socket.ssid].ssid = socket.ssid;
- ssid_sessions[socket.ssid].data_store.sockets.add(socket);
}
var ip2long = function (ip) {
@@ -920,7 +1098,8 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
if (headers["wtv-capability-flags"] != null) {
if (!ssid_sessions[socket.ssid]) {
- ssid_sessions[socket.ssid] = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs);
+ ssid_sessions[socket.ssid] = new WTVClientSessionData(socket.ssid,minisrv_config.config.hide_ssid_in_logs);
+ ssid_sessions[socket.ssid].SaveIfRegistered();
}
if (!ssid_sessions[socket.ssid].capabilities) ssid_sessions[socket.ssid].capabilities = new WTVClientCapabilities(headers["wtv-capability-flags"]);
}
@@ -1249,14 +1428,16 @@ async function cleanupSocket(socket) {
// set timer to destroy entirety of session data if client does not return in X time
var timeout = 180000; // timeout is in milliseconds, default 180000 (3 min) .. be sure to allow time for dialup reconnections
- if (!ssid_sessions[socket.ssid].data_store.socket_check) {
- ssid_sessions[socket.ssid].data_store.socket_check = setTimeout(function (ssid) {
- if (ssid_sessions[ssid].currentConnections() === 0) {
- if (!zquiet) console.log(" * WebTV SSID", filterSSID(ssid), " has not been seen in", (timeout / 1000), "seconds, cleaning up session data for this SSID");
- delete ssid_sessions[ssid];
- }
- }, timeout, socket.ssid);
- }
+ // clear any existing timeout check
+ if (ssid_sessions[socket.ssid].data_store.socket_check) clearTimeout(ssid_sessions[socket.ssid].data_store.socket_check);
+
+ // set timeout to check
+ ssid_sessions[socket.ssid].data_store.socket_check = setTimeout(function (ssid) {
+ if (ssid_sessions[ssid].currentConnections() === 0) {
+ if (!zquiet) console.log(" * WebTV SSID", filterSSID(ssid), " has not been seen in", (timeout / 1000), "seconds, cleaning up session data for this SSID");
+ delete ssid_sessions[ssid];
+ }
+ }, timeout, socket.ssid);
}
}
socket.end();
@@ -1270,6 +1451,7 @@ async function handleSocket(socket) {
// 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_sessions[socket.id] = [];
+ socket.minisrv_pc_mode = false;
socket.setEncoding('hex'); //set data encoding (Text: 'ascii', 'utf8' ~ Binary: 'hex', 'base64' (do not trust 'binary' encoding))
socket.setTimeout(10800000); // 3 hours
socket.on('data', function (data_hex) {
diff --git a/zefie_wtvp_minisrv/config.json b/zefie_wtvp_minisrv/config.json
index 91767a6f..80bd772d 100644
--- a/zefie_wtvp_minisrv/config.json
+++ b/zefie_wtvp_minisrv/config.json
@@ -14,8 +14,12 @@
"post_percentages": [ 0, 25, 50, 100 ],
"verbosity": 2,
"error_log_file": "errors.log",
- "allow_guests": true,
- "enable_lzpf_compression": true
+ "catchall_file_name": "catchall.js",
+ "enable_lzpf_compression": false,
+ "enable_gzip_compression": true,
+ "pc_server_hidden_service": "http_pc",
+ "pc_server_hidden_service_enabled": false,
+ "allow_guests": true
},
"services": {
"wtv-head-waiter": {
@@ -52,7 +56,8 @@
"flags": "0x00000040",
"debug": false,
"use_zefie_server": true,
- "bf0app_default_rom": "content/artemis-webtv-000/build7181/daily-nondebug/bf0app-part000.rom"
+ "bf0app_default_rom": "content/artemis-webtv-000/build7181/daily-nondebug/bf0app-part000.rom",
+ "catchall_file_name": "content-serve.js"
},
"wtv-setup": {
"port": 1613,
@@ -67,7 +72,7 @@
"port": 1630,
"connections": 3
},
- "wtv-update": {
+ "wtv-disk": {
"port": 1635,
"connections": 3
},
diff --git a/zefie_wtvp_minisrv/package.json b/zefie_wtvp_minisrv/package.json
index 6ae035e2..f16d9473 100644
--- a/zefie_wtvp_minisrv/package.json
+++ b/zefie_wtvp_minisrv/package.json
@@ -1,6 +1,6 @@
{
"name": "zefie_wtvp_minisrv",
- "version": "0.9.13",
+ "version": "0.9.16",
"description": "WebTV Service (WTVP) Emulation Server",
"main": "app.js",
"homepage": "https://github.com/zefie/zefie_wtvp_minisrv",
diff --git a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj
index 1e623a83..17205247 100644
--- a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj
+++ b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj
@@ -32,6 +32,8 @@
+
+
@@ -50,6 +52,7 @@
Code
+
Code
@@ -71,6 +74,9 @@
+
+ Code
+
@@ -247,15 +253,13 @@
Code
-
+
Code
-
+
Code
-
-
@@ -287,10 +291,12 @@
+
+
@@ -300,13 +306,13 @@
-
+
-
-
+
+
\ No newline at end of file
|