diff --git a/.gitignore b/.gitignore
index 25a2816b..527f3261 100644
--- a/.gitignore
+++ b/.gitignore
@@ -367,3 +367,4 @@ FodyWeavers.xsd
/zefie_wtvp_minisrv/UserServiceVault/*-*/
/zefie_wtvp_minisrv/ServiceLogPost/*.log
/zefie_wtvp_minisrv/SessionStore/*.json
+/zefie_wtvp_minisrv/SessionStore/*/
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/noflash.js b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/noflash.js
index 984e5442..1c68e5b8 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/noflash.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/noflash.js
@@ -1,5 +1,5 @@
if (socket.ssid != null && !ssid_sessions[socket.ssid].get("wtvsec_login")) {
- var wtvsec_login = new WTVSec();
+ var wtvsec_login = new WTVSec(minisrv_config);
wtvsec_login.IssueChallenge();
wtvsec_login.set_incarnation(request_headers["wtv-incarnation"]);
ssid_sessions[socket.ssid].set("wtvsec_login", wtvsec_login);
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js
index fd2bfc70..56180d57 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js
@@ -2,7 +2,7 @@
if (socket.ssid) {
if (ssid_sessions[socket.ssid].loadSessionData() == true) {
- console.log(" * Loaded session data from disk for", filterSSID(socket.ssid))
+ console.log(" * Loaded session data from disk for", wtvshared.filterSSID(socket.ssid))
ssid_sessions[socket.ssid].setSessionData("registered", (ssid_sessions[socket.ssid].getSessionData("registered") == true) ? true : false);
} else {
ssid_sessions[socket.ssid].session_data = {};
@@ -20,15 +20,15 @@
}
}
});
- if (i > 0 && zdebug) console.log(" # Closed", i, "previous sockets for", filterSSID(socket.ssid));
+ if (i > 0 && minisrv_config.config.debug_flags.debug) console.log(" # Closed", i, "previous sockets for", wtvshared.filterSSID(socket.ssid));
}
}
if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
- if (zdebug) console.log(" # Recreating primary WTVSec login instance for", filterSSID(socket.ssid));
+ if (minisrv_config.config.debug_flags.debug) console.log(" # Recreating primary WTVSec login instance for", wtvshared.filterSSID(socket.ssid));
delete ssid_sessions[socket.ssid].data_store.wtvsec_login;
}
- ssid_sessions[socket.ssid].data_store.wtvsec_login = new WTVSec();
+ ssid_sessions[socket.ssid].data_store.wtvsec_login = new WTVSec(minisrv_config);
ssid_sessions[socket.ssid].data_store.wtvsec_login.IssueChallenge();
ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(request_headers["wtv-incarnation"] || 1);
} else {
@@ -115,24 +115,23 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
gourl = "wtv-head-waiter:/login-stage-two?relogin=true";
}
- if (request_headers.query.reconnect) {
- gourl = null;
- }
-
- if (!file_path != null && !zquiet) console.log(" * Sending TellyScript", file_path, "on socket", socket.id);
+ if (request_headers.query.reconnect) gourl = null;
if (request_headers.query.guest_login) {
send_tellyscript = false;
- gourl += "&guest_login=true"
+ if (gourl != null) gourl += "&guest_login=true"
if (request_headers.query.skip_splash) gourl += "&skip_splash=true";
}
+ if (!file_path != null && send_tellyscript && !minisrv_config.config.debug_flags.quiet) console.log(" * Sending TellyScript", file_path, "on socket", socket.id);
+
+
headers = "200 OK\n"
if (bf0app_update) headers += "minisrv-use-carriage-return: false\n";
headers += "Connection: Keep-Alive\n";
headers += "wtv-initial-key: " + ssid_sessions[socket.ssid].data_store.wtvsec_login.challenge_key.toString(CryptoJS.enc.Base64) + "\n";
headers += "Content-Type: " + prereg_contype + "\n";
- headers += "wtv-service: reset\n";
+ if (!request_headers.query.reconnect) headers += "wtv-service: reset\n";
if (!bf0app_update) headers += getServiceString('wtv-1800') + "\n";
if (bf0app_update) headers += getServiceString('wtv-head-waiter', { "flags": "0x00000001" }) + "\n";
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/Modem_Firmware/Locale/en-US/kflex/modem_firmware.dat.gz b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/Modem_Firmware/Locale/en-US/kflex/modem_firmware.dat.gz
new file mode 100644
index 00000000..8d709962
Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/Modem_Firmware/Locale/en-US/kflex/modem_firmware.dat.gz differ
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/Modem_Firmware/Locale/en-US/v90/modem_firmware.dat.gz b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/Modem_Firmware/Locale/en-US/v90/modem_firmware.dat.gz
new file mode 100644
index 00000000..f1df9b19
Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/Modem_Firmware/Locale/en-US/v90/modem_firmware.dat.gz differ
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/Modem_Firmware/Locale/ja-JP/modem_firmware.dat.gz b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/Modem_Firmware/Locale/ja-JP/modem_firmware.dat.gz
new file mode 100644
index 00000000..45e80dc8
Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/Modem_Firmware/Locale/ja-JP/modem_firmware.dat.gz differ
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/diskmaps/ModemFirmware.json b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/diskmaps/ModemFirmware.json
new file mode 100644
index 00000000..93aebcff
--- /dev/null
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/diskmaps/ModemFirmware.json
@@ -0,0 +1,18 @@
+{
+ "ModemFirmware": {
+ "base": "file://Disk/Browser/Modem_Firmware/",
+ "location": "content/Modem_Firmware/",
+ "execute": "client:ModemReload",
+ "execute_when": "atEnd",
+ "service_owned": true,
+ "files": [
+ {
+ "file": "file://Disk/Browser/Modem_Firmware/Locale/en-US/modem_firmware.dat.gz",
+ "location": "content/Modem_Firmware/Locale/en-US/v90/modem_firmware.dat.gz"
+ },
+ {
+ "file": "file://Disk/Browser/Modem_Firmware/Locale/ja-JP/modem_firmware.dat.gz"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/diskmaps/ModemFirmwareOld.json b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/diskmaps/ModemFirmwareOld.json
new file mode 100644
index 00000000..ff770dfd
--- /dev/null
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/diskmaps/ModemFirmwareOld.json
@@ -0,0 +1,18 @@
+{
+ "ModemFirmware": {
+ "base": "file://Disk/Browser/Modem_Firmware/",
+ "location": "content/Modem_Firmware/",
+ "execute": "client:ModemReload",
+ "execute_when": "atEnd",
+ "service_owned": true,
+ "files": [
+ {
+ "file": "file://Disk/Browser/Modem_Firmware/Locale/en-US/modem_firmware.dat.gz",
+ "location": "content/Modem_Firmware/Locale/en-US/kflex/modem_firmware.dat.gz"
+ },
+ {
+ "file": "file://Disk/Browser/Modem_Firmware/Locale/ja-JP/modem_firmware.dat.gz"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-disk/sync.js b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/sync.js
index 8f8429b6..6f37edd8 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-disk/sync.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/sync.js
@@ -1,88 +1,104 @@
-// todo: async
+const WTVDownloadList = require("./WTVDownloadList.js");
+var wtvdl = new WTVDownloadList(minisrv_config, service_name);
var force_update = (request_headers.query.force == "true") ? true : false;
-console.log(force_update);
if (request_headers['wtv-request-type'] == 'download') {
- 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.execute && diskmap_data.execute_when == "atStart") {
- download_list += "EXECUTE " + diskmap_data.execute + "\n\n";
- }
-
- 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";
-
- 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) {
- if (!update_list[k].invalid) return;
- download_list += "DELETE " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
- download_list += "group: " + diskmap_group_data + "\n\n";
- });
-
+ wtvdl.reset();
+ var files_to_send = 0;
Object.keys(update_list).forEach(function (k) {
if (update_list[k].checksum_match && !force_update) return;
if (!update_list[k].invalid && !force_update) return;
- 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].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";
+ files_to_send++;
});
- 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) {
- if (!update_list[k].invalid) return;
- 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 += "SET-GROUP " + diskmap_group_data + "\n";
- download_list += "state: ok\n";
- download_list += "version: " + diskmap_data.version + "\n";
- download_list += "last-checkup-time: " + new Date().toUTCString().replace("GMT", "+0000") + "\n\n";
-
- if (diskmap_data.execute && diskmap_data.execute_when == "atEnd") {
- download_list += "EXECUTE " + diskmap_data.execute + "\n\n";
+ // create WebTV Download List
+ if (diskmap_data.execute && diskmap_data.execute_when) {
+ if (diskmap_data.execute_when.toLowerCase().match(/start/)) {
+ wtvdl.execute(diskmap_data.execute);
+ }
}
- download_list += "DELETE-GROUP " + diskmap_group_data + "-UPDATE\n\n";
- download_list += "DELETE " + diskmap_data.base + ".GROUP-UPDATE/\n\n";
- console.log(download_list);
+ if (diskmap_group_data.display) wtvdl.display(diskmap_group_data.display);
+
+ if (files_to_send > 0) {
+
+ if (diskmap_data.partition_size) {
+ wtvdl.createPartition(diskmap_data.base, diskmap_data.partition_size);
+ }
+
+ if (!diskmap_data.nogroup) {
+ // only send group commands if group mode is enable
+ // useful to disable for PUT
+ wtvdl.createUpdateGroup(diskmap_group_data, diskmap_data.base, "invalid", (diskmap_data.service_owned || false));
+ }
+
+ Object.keys(update_list).forEach(function (k) {
+ // file { "action": "delete" }
+ // Useful to purge files we no longer want on the client
+ if (update_list[k].action != "DELETE") {
+ // skip deleting valid files if we aren't specifically requesting their deletion
+ if (update_list[k].checksum_match && !force_update) return;
+ if (!update_list[k].invalid && !force_update) return;
+ }
+ wtvdl.delete(update_list[k].file.replace(diskmap_data.base, ""), diskmap_group_data);
+ });
+
+ Object.keys(update_list).forEach(function (k) {
+ if (update_list[k].checksum_match && !force_update) return;
+ if (!update_list[k].invalid && !force_update) return;
+ if (update_list[k].display) wtvdl.display(update_list[k].display);
+ switch (update_list[k].action) {
+ case "PUT":
+ wtvdl.put(update_list[k].file.replace(diskmap_data.base, ""), service_name + ":/" + update_list[k].location, update_list[k].display);
+ break;
+
+ case "GET":
+ wtvdl.get(update_list[k].file.replace(diskmap_data.base, ""), update_list[k].file, service_name + ":/" + update_list[k].location, diskmap_group_data, update_list[k].checksum, update_list[k].uncompressed_size || null, update_list[k].original_filename)
+ break;
+ }
+ });
+
+ if (!diskmap_data.nogroup) {
+ wtvdl.createGroup(diskmap_group_data, diskmap_data.base, "invalid", (diskmap_data.service_owned || false));
+
+
+ // this rename loop is a part of the group system
+ Object.keys(update_list).forEach(function (k) {
+ if (update_list[k].checksum_match && !force_update) return;
+ if (!update_list[k].invalid && !force_update) return;
+ wtvdl.rename(update_list[k].file.replace(diskmap_data.base, ""), update_list[k].file.replace(diskmap_data.base, ""), diskmap_group_data, diskmap_group_data);
+ });
+
+ wtvdl.setGroup(diskmap_group_data, 'ok', diskmap_data.version);
+ }
+
+ }
+
+ if (diskmap_data.execute && diskmap_data.execute_when) {
+ if (diskmap_data.execute_when.toLowerCase().match(/end/)) {
+ wtvdl.execute(diskmap_data.execute);
+ }
+ }
+
+ if (files_to_send > 0) {
+ if (!diskmap_data.nogroup) {
+ wtvdl.deleteGroupUpdate(diskmap_group_data, diskmap_data.base);
+ }
+ }
+ var download_list = wtvdl.getDownloadList();
+ if (minisrv_config.config.show_diskmap) console.log(download_list);
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 = new Array();
+ if (request_headers.post_data) post_data = request_headers.post_data.toString(CryptoJS.enc.Latin1).split("\n");
var post_data_current_directory = '';
var post_data_current_file = false;
var post_data_current_group = '';
@@ -172,6 +188,8 @@ if (request_headers['wtv-request-type'] == 'download') {
if (!fs.existsSync(post_match_file)) post_match_file = null;
});
+
+
var post_match_file_lstat = fs.lstatSync(post_match_file);
var post_match_file_data = new Buffer.from(fs.readFileSync(post_match_file, {
encoding: null,
@@ -180,10 +198,23 @@ if (request_headers['wtv-request-type'] == 'download') {
diskmap_group_data.files[k].base = diskmap_group_data.base;
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].checksum = CryptoJS.MD5(CryptoJS.lib.WordArray.create(post_match_file_data)).toString(CryptoJS.enc.Hex).toLowerCase();
+ diskmap_group_data.files[k].action = (diskmap_group_data.files[k].action) ? diskmap_group_data.files[k].action.toUpperCase() : "GET";
+
+ if (wtvshared.getFileExt(post_match_file).toLowerCase() == "gz") {
+ // we need the checksum of the uncompressed data
+ var gunzipped = zlib.gunzipSync(post_match_file_data);
+ diskmap_group_data.files[k].checksum = CryptoJS.MD5(CryptoJS.lib.WordArray.create(gunzipped)).toString(CryptoJS.enc.Hex).toLowerCase();
+ var gzip_fn_end = post_match_file_data.indexOf("\0", 10);
+ if (!diskmap_group_data.files[k].dont_extract_filename) {
+ diskmap_group_data.files[k].original_filename = post_match_file_data.toString('utf8', 10, gzip_fn_end);
+ }
+ //diskmap_group_data.files[k].uncompressed_size = gunzipped.byteLength;
+ gunzipped = null;
+ } else {
+ diskmap_group_data.files[k].checksum = CryptoJS.MD5(CryptoJS.lib.WordArray.create(post_match_file_data)).toString(CryptoJS.enc.Hex).toLowerCase();
+ }
if (parseInt(diskmap_group_data.files[k].last_modified) > newest_file_epoch) newest_file_epoch = parseInt(diskmap_group_data.files[k].last_modified);
- if (!diskmap_group_data.files[k].display) diskmap_group_data.files[k].display = diskmap_group_data.display;
diskmap_group_data.files[k].invalid = true;
wtv_download_list.push(diskmap_group_data.files[k]);
@@ -205,7 +236,7 @@ if (request_headers['wtv-request-type'] == 'download') {
return output_data;
}
- if (request_headers.query.diskmap && request_headers.query.group && request_headers.post_data) {
+ if (request_headers.query.diskmap && request_headers.query.group) {
var diskmap_json_file = null;
Object.keys(service_vaults).forEach(function (g) {
if (diskmap_json_file != null) return;
@@ -243,69 +274,17 @@ if (request_headers['wtv-request-type'] == 'download') {
var errpage = doErrorPage(404, "The requested DiskMap does not exist.");
headers = errpage[0];
data = errpage[1];
- if (zdebug) console.error(" # " + service_name +":/sync error", "could not find diskmap");
+ if (minisrv_config.config.debug_flags.debug) console.error(" # " + service_name +":/sync error", "could not find diskmap");
}
} else {
var errpage = doErrorPage(400);
headers = errpage[0];
data = errpage[1];
- if (zdebug) console.error(" # " + service_name + ":/sync error", "missing query arguments");
+ if (minisrv_config.config.debug_flags.debug) console.error(" # " + service_name + ":/sync error", "missing query arguments");
}
} else if (request_headers.query.group && request_headers.query.diskmap) {
var message = request_headers.query.message || "Retrieving files...";
var main_message = request_headers.query.main_message || "Your receiver is downloading files.";
- headers = `200 OK
-Content-Type: text/html`;
-
- data = `
-
-
-
-
- Retrieving files...
-
-
-
-
-
-
- |
-
-
-
-
-
- ${message}
-
-
-
- |
- |
- |
- |
- |
- |
- |
- |
-
- ${main_message}
- This may take a while.
-
- |
- |
- |
-
-
-
-
- | |
-
-
-`;
-
+ headers = "200 OK\nwtv-connection-close: close\nConnection: close\nContent-Type: text/html";
+ data = wtvdl.getSyncPage(message, request_headers.query.group, request_headers.query.diskmap, main_message, message, force_update)
}
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-disk/userstore.js b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/userstore.js
new file mode 100644
index 00000000..f53bd496
--- /dev/null
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/userstore.js
@@ -0,0 +1,21 @@
+if (request_headers.post_data) {
+ if (request_headers.query.partialPath || request_headers.query.path) {
+ if (socket.ssid) {
+ if (ssid_sessions[socket.ssid]) {
+ if (ssid_sessions[socket.ssid].isRegistered()) {
+ var result = ssid_sessions[socket.ssid].storeUserStoreFile(request_headers.query.path || request_headers.query.partialPath, new Buffer.from(request_headers.post_data.toString(CryptoJS.enc.Hex), 'hex'), request_headers.query['last-modified-seconds'] || null, (request_headers.query.no_overwrite) ? false : true);
+ if (result) {
+ headers = "200 OK\n";
+ headers += "Content-Type: text/plain";
+ }
+ }
+ }
+ }
+ }
+}
+
+if (!headers) {
+ var errpage = doErrorPage(400)
+ headers = errpage[0];
+ data = errpage[1];
+}
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/content/content-serve.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/content/content-serve.js
index b8209c2a..95fdea50 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/content/content-serve.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/content/content-serve.js
@@ -1,6 +1,5 @@
const WTVFlashrom = require("./WTVFlashrom.js");
request_is_async = true;
-console.log(request_headers);
var bf0app_update = false;
var request_path = request_headers.request_url.replace(service_name + ":/", "");
@@ -15,7 +14,7 @@ if ((romtype == "bf0app" || !romtype) && (bootver == "105" || !bootver)) {
}
if (!ssid_sessions[socket.ssid].data_store.WTVFlashrom) {
- ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, bf0app_update, minisrv_config.services[service_name].debug);
+ ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(minisrv_config, service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, bf0app_update);
}
ssid_sessions[socket.ssid].data_store.WTVFlashrom.getFlashRom(request_path, function (data, headers) {
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/current-noflash.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/current-noflash.js
index 642803cf..25858295 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/current-noflash.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/current-noflash.js
@@ -22,7 +22,7 @@ if (ssid_sessions[socket.ssid].get("wtv-client-rom-type") == "bf0app" && ssid_se
}
if (!ssid_sessions[socket.ssid].data_store.WTVFlashrom) {
- ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, bf0app_update, minisrv_config.services[service_name].debug);
+ ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(minisrv_config, service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, bf0app_update);
}
ssid_sessions[socket.ssid].data_store.WTVFlashrom.getFlashRom(request_path, function (data, headers) {
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js
index a2ad57e0..317c5fa4 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js
@@ -15,7 +15,7 @@ if ((romtype == "bf0app" || !romtype) && (bootver == "105" || !bootver)) {
if (request_headers.query.raw || bf0app_update) {
if (!ssid_sessions[socket.ssid].data_store.WTVFlashrom) {
- ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, bf0app_update, minisrv_config.services[service_name].debug);
+ ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(minisrv_config, service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, bf0app_update);
}
ssid_sessions[socket.ssid].data_store.WTVFlashrom.getFlashRom(request_path, function (data, headers) {
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js
index a7f93034..b71cfd69 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js
@@ -8,7 +8,7 @@ if (!request_headers.query.path) {
headers = errpage[0];
data = errpage[1];
} else {
- var wtvflashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, minisrv_config.services[service_name].debug);
+ var wtvflashrom = new WTVFlashrom(minisrv_config, service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, false, true);
var request_path = request_headers.query.path;
// read flashrom header info into array using WTVFlashrom class
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 3a00509a..dc6ca784 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js
@@ -5,8 +5,9 @@ var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
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 = "200 OK\n";
+ headers = "300 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/noflash.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/noflash.js
index 03c990e9..1ee36f57 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/noflash.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/noflash.js
@@ -22,7 +22,7 @@ if (ssid_sessions[socket.ssid].get("wtv-client-rom-type") == "bf0app" && ssid_se
}
if (!ssid_sessions[socket.ssid].data_store.WTVFlashrom) {
- ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(service_vaults, service_name, 0, minisrv_config.services[service_name].use_zefie_server, bf0app_update, minisrv_config.services[service_name].debug);
+ ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(minisrv_config, service_vaults, service_name, 0, minisrv_config.services[service_name].use_zefie_server, bf0app_update, minisrv_config.services[service_name].debug);
}
ssid_sessions[socket.ssid].data_store.WTVFlashrom.getFlashRom(request_path, function (data, headers) {
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js
index 765de4e3..2ac678cf 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js
@@ -32,7 +32,7 @@ const req = https.request(options, function (res) {
});
res.on('error', function (e) {
- if (!zquiet) console.log(" * Upstream Ultra Willies HTTP Error:", e);
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * Upstream Ultra Willies HTTP Error:", e);
var errpage = doErrorPage(400)
headers = errpage[0];
data = errpage[1];
@@ -40,7 +40,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 (!minisrv_config.config.debug_flags.quiet) console.log(" * Upstream Ultra Willies HTTP Response:", res.statusCode, res.statusMessage);
if (request_headers.query.clear_cache) {
headers += "\nwtv-expire-all: "+service_name;
}
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 fde0566b..55efe6c4 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js
@@ -2,7 +2,7 @@ var challenge_response, challenge_header = '';
var gourl;
if (socket.ssid != null && !ssid_sessions[socket.ssid].get("wtvsec_login")) {
- var wtvsec_login = new WTVSec(1,zdebug);
+ var wtvsec_login = new WTVSec(minisrv_config);
wtvsec_login.IssueChallenge();
wtvsec_login.set_incarnation(request_headers["wtv-incarnation"]);
ssid_sessions[socket.ssid].set("wtvsec_login", wtvsec_login);
@@ -16,13 +16,13 @@ if (socket.ssid !== null) {
var client_challenge_response = request_headers["wtv-challenge-response"] || null;
if (challenge_response && 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 " + wtvshared.filterSSID(socket.ssid));
wtvsec_login.PrepareTicket();
} else {
- 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 Received:", client_challenge_response)
+ console.log(" * wtv-challenge-response FAILED for " + wtvshared.filterSSID(socket.ssid));
+ if (minisrv_config.config.debug_flags.debug) console.log("Response Expected:", challenge_response.toString(CryptoJS.enc.Base64));
+ if (minisrv_config.config.debug_flags.debug) console.log("Response Received:", client_challenge_response)
gourl = "wtv-head-waiter:/login?reissue_challenge=true";
}
} else {
@@ -147,6 +147,7 @@ wtv-open-isp-disabled: false
wtv-offline-mail-enable: false
wtv-demo-mode: 0
wtv-wink-deferrer-retries: 3
+wtv-name-server: 8.8.8.8
wtv-visit: ${home_url}
Content-Type: text/html`;
}
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js
index 9f44b498..38e60ef4 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js
@@ -54,7 +54,7 @@ wtv-log-url: wtv-log:/log`;
if (challenge_header != "") headers += "\n" + challenge_header;
headers += `
wtv-relogin-url: wtv-head-waiter:/relogin?relogin=true
-wtv-reconnect-url: wwtv-head-waiter:/relogin?reconnect=true
+wtv-reconnect-url: wtv-head-waiter:/relogin?reconnect=true
wtv-visit: ${gourl}
Content-type: text/html`;
data = '';
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js b/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js
index 56e1609a..6b804319 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js
@@ -5,14 +5,9 @@ wtv-expire-all: wtv-flashrom:
Content-type: text/html`
if (request_headers.query.url) headers += "\nwtv-visit: " + request_headers.query.url;
+var cryptstatus = ((socket_sessions[socket.id].secure === true) ? "Encrypted" : "Not Encrypted")
-if (ssid_sessions[socket.ssid].get('box-does-psuedo-encryption')) {
- var cryptstatus = "Psuedo-encrypted";
-} else {
- var cryptstatus = ((socket_sessions[socket.id].secure === true) ? "Encrypted" : "Not Encrypted")
-}
-
-var comp_type = shouldWeCompress(socket.ssid,'text/html');
+var comp_type = wtvmime.shouldWeCompress(ssid_sessions[socket.ssid],'text/html');
var compstatus = "uncompressed";
switch (comp_type) {
case 1:
@@ -58,7 +53,7 @@ if (ssid_sessions[socket.ssid].hasCap("client-has-disk")) {
data += "DiskHax ~ VFatHax\n";
if (ssid_sessions[socket.ssid].hasCap("client-can-do-macromedia-flash2")) {
// only show demo if client can do flash2
- data += "Old MSNTV DealerDemo: Download ~ Access (after Download)\n";
+ data += "Old DealerDemo: Download ~ Access\n";
}
}
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-log/log.js b/zefie_wtvp_minisrv/ServiceVault/wtv-log/log.js
index 47fa7299..b3e69ae5 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-log/log.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-log/log.js
@@ -22,7 +22,7 @@ Content-length: 0`;
logdata_outstring_hex += request_headers.post_data.toString(CryptoJS.enc.Hex);
if (minisrv_config.services[service_name].write_logs_to_disk) {
fs.writeFile(fullpath, logdata_outstring_hex, "Hex", function () {
- if (!zquiet) console.log(" * Wrote POST log data from", filterSSID(socket.ssid), "for", socket.id);
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * Wrote POST log data from", wtvshared.filterSSID(socket.ssid), "for", socket.id);
sendToClient(socket, headers, data);
});
} else {
@@ -41,7 +41,7 @@ Content-length: 0`;
var logdata_outstring_hex = Buffer.from(logdata_outstring, 'utf8').toString('hex');
if (minisrv_config.services[service_name].write_logs_to_disk) {
fs.writeFile(fullpath, logdata_outstring_hex, "Hex", function () {
- if (!zquiet) console.log(" * Wrote GET log data from", filterSSID(socket.ssid), "for", socket.id);
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * Wrote GET log data from", wtvshared.filterSSID(socket.ssid), "for", socket.id);
sendToClient(socket, headers, data);
});
} else {
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateReviewAccountInfo.js b/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateReviewAccountInfo.js
index 32315cbf..9479296b 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateReviewAccountInfo.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateReviewAccountInfo.js
@@ -17,7 +17,7 @@ if (!request_headers.query.registering ||
ssid_sessions[socket.ssid].setSessionData("subscriber_contact_method", request_headers.query.subscriber_contact_method);
ssid_sessions[socket.ssid].setSessionData("subscriber_userid", '1' + Math.floor(Math.random() * 1000000000000000000));
ssid_sessions[socket.ssid].setSessionData("registered", true);
- if (!ssid_sessions[socket.ssid].storeSessionData()) {
+ if (!ssid_sessions[socket.ssid].storeSessionData(true)) {
var errpage = doErrorPage(400);
headers = errpage[0];
data = errpage[1];
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/info.js b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/info.js
index 06550461..bc3d6111 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/info.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/info.js
@@ -18,7 +18,7 @@ Content-Type: text/html`
var wtv_system_version = ssid_sessions[socket.ssid].get("wtv-system-version");
var wtv_client_bootrom_version = ssid_sessions[socket.ssid].get("wtv-client-bootrom-version");
- var wtv_client_serial_number = filterSSID(ssid_sessions[socket.ssid].get("wtv-client-serial-number"));
+ var wtv_client_serial_number = wtvshared.filterSSID(ssid_sessions[socket.ssid].get("wtv-client-serial-number"));
var wtv_client_rom_type = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
var wtv_system_chipversion_str = ssid_sessions[socket.ssid].get("wtv-system-chipversion");
var wtv_system_sysconfig_hex = parseInt(ssid_sessions[socket.ssid].get("wtv-system-sysconfig")).toString(16);
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/unregister.js b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/unregister.js
index 7f40113f..1f0af15a 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/unregister.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/unregister.js
@@ -2,7 +2,9 @@ headers = `200 OK
Content-Type: text/html`;
if (!ssid_sessions[socket.ssid].getSessionData("registered")) {
- var redirect = [10, "client:goback?"];
+ headers += "\nwtv-noback-all: wtv-";
+ headers += "\nwtv-expire-all: wtv-";
+ var redirect = [5, "client:relogin?"];
var message = "Error: Your box is not registered. You are accessing " + minisrv_config.config.service_name + " in Guest Mode. There is nothing to delete!";
} else if (request_headers.query.confirm_unregister) {
if (ssid_sessions[socket.ssid].unregisterBox()) {
@@ -14,7 +16,7 @@ if (!ssid_sessions[socket.ssid].getSessionData("registered")) {
} else {
var redirect = [10, "client:goback?"];
var message = "There was an error deleting your account data. Please try again later. If the problem persists, please contact " + minisrv_config.config.service_owner + " to request manual deletion.";
- message += "SSID verifcation may be required to perform a manual deletion.< br >
Returning from whence you came...
";
+ message += "SSID verifcation may be required to perform a manual deletion.
Returning from whence you came...
";
message += `Click here if you are not automatically redirected.`;
}
} else {
diff --git a/zefie_wtvp_minisrv/WTVClientSessionData.js b/zefie_wtvp_minisrv/WTVClientSessionData.js
index d44c948d..1737eda2 100644
--- a/zefie_wtvp_minisrv/WTVClientSessionData.js
+++ b/zefie_wtvp_minisrv/WTVClientSessionData.js
@@ -4,55 +4,109 @@ class WTVClientSessionData {
fs = require('fs');
path = require('path');
+
ssid = null;
data_store = null;
session_store = null;
login_security = null;
capabilities = null;
session_storage = "";
- hide_ssid_in_logs = true;
+ minisrv_config = [];
+ wtvshared = null;
+ wtvmime = null;
- filterSSID(obj) {
- if (this.hide_ssid_in_logs === true) {
- if (typeof (obj) == "string") {
- if (obj.substr(0, 8) == "MSTVSIMU") {
- return obj.substr(0, 10) + ('*').repeat(10) + obj.substr(20);
- } else if (obj.substr(0, 5) == "1SEGA") {
- return obj.substr(0, 6) + ('*').repeat(6) + obj.substr(13);
- } else {
- return obj.substr(0, 6) + ('*').repeat(9);
- }
- } else {
- if (obj["wtv-client-serial-number"]) {
- var ssid = obj["wtv-client-serial-number"];
- if (ssid.substr(0, 8) == "MSTVSIMU") {
- obj["wtv-client-serial-number"] = ssid.substr(0, 10) + ('*').repeat(10) + ssid.substr(20);
- } else if (ssid.substr(0, 5) == "1SEGA") {
- obj["wtv-client-serial-number"] = ssid.substr(0, 6) + ('*').repeat(6) + ssid.substr(13);
- } else {
- obj["wtv-client-serial-number"] = ssid.substr(0, 6) + ('*').repeat(9);
- }
- }
- return obj;
- }
- } else {
- return obj;
- }
- }
+ constructor(minisrv_config, ssid) {
+ if (!minisrv_config) throw ("minisrv_config required");
+ var WTVShared = require('./WTVShared.js')['WTVShared'];
+ var WTVMime = require('./WTVMime.js');
+ this.minisrv_config = minisrv_config;
+ this.wtvshared = new WTVShared(minisrv_config);
+ this.wtvmime = new WTVMime(minisrv_config);
- 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;
this.data_store = new Array();
this.session_store = {};
}
- getUTCTime(offset = 0) {
- return new Date((new Date).getTime() + offset).toUTCString();
+ /**
+ * Returns the absolute path to the user's file store, or false if unregistered
+ * @returns {string|boolean} Absolute path to the user's file store, or false if unregistered
+ */
+ getUserStoreDirectory() {
+ if (!this.isRegistered()) return false;
+ return this.minisrv_config.config.SessionStore + this.path.sep + this.ssid + this.path.sep;
}
+ /**
+ * Store a file in the user's file store
+ * @param {string} path Relative path to User's file store
+ * @param {Buffer} data File data
+ * @param {number|null} last_modified Unix timestamp to set last modified date to
+ * @param {boolean} overwrite Overwrite if file exists
+ * @returns {boolean} Whether or not the file was written
+ */
+ storeUserStoreFile(path, data, last_modified = null, overwrite = true) {
+ var store_dir = this.getUserStoreDirectory();
+ if (!store_dir) return false; // unregistered
+ var result = false;
+ var path_split = path.split('/');
+ var file_name = path_split.pop();
+ var store_dir_path = this.wtvshared.makeSafePath(store_dir, path_split.join('/').replace('/', this.path.sep));
+ var store_full_path = this.wtvshared.makeSafePath(store_dir_path, file_name);
+
+ try {
+ if (!this.fs.existsSync(store_dir_path)) this.fs.mkdirSync(store_dir_path, { recursive: true });
+ var file_exists = this.fs.existsSync(store_full_path);
+ if (!file_exists || (file_exists && overwrite)) result = this.fs.writeFileSync(store_full_path, data);
+ if (result !== false && last_modified) {
+ var file_timestamp = new Date(last_modified * 1000);
+ fs.utimesSync(store_full_path, Date.now(), file_timestamp)
+ }
+ } catch (e) {
+ console.error(" # User File Store failed", e);
+ }
+ return (result === false) ? false : true;
+ }
+
+ /**
+ * Retrieves a file from the user store
+ * @param {string} path Path relative to the User File Store
+ * @returns {Buffer|false} Buffer data, or false if could not open file
+ */
+ getUserStoreFile(path) {
+ var store_dir = this.getUserStoreDirectory();
+ if (!store_dir) return false; // unregistered
+ var store_dir_path = this.wtvshared.makeSafePath(store_dir, path.replace('/', this.path.sep));
+ if (this.fs.existsSync(store_dir_path)) return this.fs.readFileSync(store_dir_path);
+ else return false;
+ }
+
+ /**
+ * Retrieves a file from the user store with a file://Disk/ url
+ * @param {string} url file://Disk/ base url
+ * @returns {Buffer|false} Buffer data, or false if could not open file
+ */
+ getUserStoreFileByURL(url) {
+ var path_split = url.split('/');
+ path_split.shift();
+ path_split.shift();
+ var store_dir_path = path_split.join('/').replace('/', this.path.sep);
+ return this.getUserStoreFile(store_dir_path);
+ }
+
+ /**
+ * Retrieves the Content-Type of a User Store File
+ * @param {string} path Path relative to the User File Store
+ * @returns {string|false} Content-Type, or false if could not open file
+ */
+ getUserStoreContentType(path) {
+ return this.wtvmime.getSimpleContentType(path);
+ }
+
+ /**
+ * Returns the number of user cookies
+ * @returns {number} Number of cookies
+ */
countCookies() {
return Object.keys(this.session_store.cookies).length || 0;
}
@@ -60,7 +114,7 @@ class WTVClientSessionData {
resetCookies() {
this.session_store.cookies = {};
// webtv likes to have at least one cookie in the list, set a dummy cookie for zefie's site expiring in 1 year.
- this.addCookie("wtv.zefie.com", "/", this.getUTCTime(365 * 86400000), "cookie_type=chocolatechip");
+ this.addCookie("wtv.zefie.com", "/", this.wtvshared.getUTCTime(365 * 86400000), "cookie_type=chocolatechip");
}
addCookie(domain, path = null, expires = null, data = null) {
@@ -174,8 +228,8 @@ class WTVClientSessionData {
loadSessionData(raw_data = false) {
try {
- if (this.fs.lstatSync(this.session_storage + this.path.sep + this.ssid + ".json")) {
- var json_data = this.fs.readFileSync(this.session_storage + this.path.sep + this.ssid + ".json", 'Utf8')
+ if (this.fs.lstatSync(this.minisrv_config.config.SessionStore + this.path.sep + this.ssid + ".json")) {
+ var json_data = this.fs.readFileSync(this.minisrv_config.config.SessionStore + this.path.sep + this.ssid + ".json", 'Utf8')
if (raw_data) return json_data;
var session_data = JSON.parse(json_data);
@@ -184,12 +238,12 @@ class WTVClientSessionData {
}
} 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 loading session data for", this.filterSSID(this.ssid), e);
+ if (e.code != "ENOENT") console.error(" # Error loading session data for", this.wtvshared.filterSSID(this.ssid), e);
return false;
}
}
- saveSessionData() {
+ saveSessionData(force_write = false) {
if (this.isRegistered()) {
// load data from disk and merge new data
var temp_store = this.session_store;
@@ -198,17 +252,18 @@ class WTVClientSessionData {
temp_store = null;
} else {
// do not write file if user is not registered, return true because this is not an error
- return true;
+ // force write needed to set the initial reg
+ if (!force_write) return true;
}
try {
// 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");
+ if (json_save_data != json_load_data) this.fs.writeFileSync(this.minisrv_config.config.SessionStore + 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);
+ console.error(" # Error saving session data for", this.wtvshared.filterSSID(this.ssid), e);
return false;
}
}
@@ -218,9 +273,9 @@ class WTVClientSessionData {
return this.loadSessionData();
}
- storeSessionData() {
+ storeSessionData(force_write = false) {
// alias
- return this.saveSessionData();
+ return this.saveSessionData(force_write);
}
SaveIfRegistered() {
@@ -231,7 +286,7 @@ class WTVClientSessionData {
isRegistered() {
var self = this;
var ssid_match = false;
- this.fs.readdirSync(this.session_storage).forEach(file => {
+ this.fs.readdirSync(this.minisrv_config.config.SessionStore).forEach(file => {
if (!file.match(/.*\.json/ig)) return;
if (ssid_match) return;
if (file.split('.')[0] == self.ssid) ssid_match = true;
@@ -240,15 +295,19 @@ class WTVClientSessionData {
}
unregisterBox() {
+ var user_store_base = this.wtvshared.makeSafePath(this.wtvshared.getAbsolutePath(this.minisrv_config.config.SessionStore), this.path.sep + this.ssid);
try {
- if (this.fs.lstatSync(this.session_storage + this.path.sep + this.ssid + ".json")) {
- this.fs.unlinkSync(this.session_storage + this.path.sep + this.ssid + ".json");
+ if (this.fs.existsSync(user_store_base + ".json")) {
+ this.fs.unlinkSync(user_store_base + ".json");
this.session_store = {};
- return true;
}
+ if (this.fs.existsSync(user_store_base)) {
+ this.fs.rmdirSync(user_store_base, { recursive: true });
+ }
+ return true;
} catch (e) {
// Don't log error 'file not found', it just means the client isn't registered yet
- console.error(" # Error deleting session data for", this.filterSSID(this.ssid), e);
+ console.error(" # Error deleting session data for", this.wtvshared.filterSSID(this.ssid), e);
return false;
}
}
diff --git a/zefie_wtvp_minisrv/WTVDownloadList.js b/zefie_wtvp_minisrv/WTVDownloadList.js
new file mode 100644
index 00000000..9daa7e45
--- /dev/null
+++ b/zefie_wtvp_minisrv/WTVDownloadList.js
@@ -0,0 +1,310 @@
+/**
+ * wtv/download-list creation helper class
+ * By: zefie
+ */
+class WTVDownloadList {
+
+ download_list = "";
+ service_name = "";
+ content_type = "wtv/download-list";
+ wtvshared = null;
+ clientShowAlert = null;
+ minisrv_config = [];
+
+ /**
+ * Constructs the WTVDownloadList Class
+ * @param {string} service_name Service name to use in wtv-urls
+ */
+ constructor(minisrv_config, service_name = "wtv-disk") {
+ var { WTVShared, clientShowAlert } = require('./WTVShared.js');
+ this.minisrv_config = minisrv_config;
+ this.wtvshared = new WTVShared(minisrv_config);
+ this.clientShowAlert = clientShowAlert;
+ this.service_name = service_name
+ this.clear();
+ }
+
+ /**
+ * Clears the download list
+ */
+ clear() {
+ this.download_list = "";
+ }
+
+ /**
+ * Alias to clear() (clears the download list)
+ */
+ reset() {
+ this.clear();
+ }
+
+ /**
+ * Returns the download list.
+ * @returns {string} Download list for client;
+ */
+ getDownloadList() {
+ return this.download_list;
+ }
+
+ /**
+ * Adds a DISPLAY command to the download list
+ * @param {string} message Message to display to the client
+ */
+ display(message) {
+ this.download_list += "DISPLAY " + message + "\n\n";
+ }
+
+ /**
+ * Adds an EXECUTE command to the download list
+ * @param {string} command client command to execute
+ */
+ execute(command) {
+ this.download_list += "EXECUTE " + command + "\n\n";
+ }
+
+ /**
+ * Adds a CREATE partition command to the download list
+ * @param {string} path file://Disk/ path to desired partition
+ * @param {string} size Size of the desired partition
+ */
+ createPartition(path, size) {
+ this.download_list += "CREATE " + path + "\n";
+ this.download_list += "partition-size: " + size + "\n\n";
+ }
+
+ /**
+ * Adds a CREATE-GROUP command to the download list
+ * @param {string} name Group name
+ * @param {string} path file://Disk/ path of desired group
+ * @param {string} state Group state
+ * @param {boolean|null} service_owned Sets service owned flag. (null = don't set)
+ */
+ createGroup(name, path, state = 'invalid', service_owned = null) {
+ this.download_list += "CREATE-GROUP " + name + "\n";
+ this.download_list += "state: " + state + "\n";
+ if (service_owned !== null) this.download_list += "service-owned: " + service_owned + "\n";
+ this.download_list += "base: " + path + "\n\n";
+ }
+
+ /**
+ * An alias for createGroup() that handles creating the '-UPDATE' group for you
+ * @param {string} name Group name
+ * @param {string} path file://Disk/ path of desired group
+ * @param {string} state Group state
+ * @param {boolean} service_owned Sets service owned flag.
+ */
+ createUpdateGroup(name, path, state = 'invalid', service_owned = false) {
+ this.createGroup(name + "-UPDATE", path, state);
+ this.createGroup(name, path, state, service_owned);
+ }
+
+ /**
+ * Adds a DELETE command to the download list
+ * @param {string} path Non-absolute path of client destination file (relative to group base) if group defined, otherwise absolute file://Disk/ path to delete
+ * @param {string} group Group to which it belongs
+ */
+ delete(path, group = null) {
+ path = this.wtvshared.stripGzipFromPath(path);
+ this.download_list += "DELETE " + path + "\n";
+ if (group !== null) this.download_list += "group: " + group + "\n\n";
+ }
+
+ /**
+ * Adds a PUT command to the download list
+ * @param {string} path Absolute file://Disk/ path of a file to upload to the service
+ * @param {string} destination Destination address (wtv url on service) in which to POST upload the file to
+ */
+ put(path, destination) {
+ this.download_list += "PUT " + path + "\n";
+ this.download_list += "location: " + destination + "\n\n";
+ }
+
+ /**
+ * Alias to put() for User Store
+ * @param {string} path Absolute file://Disk/ path of a file to upload to the service
+ * @param {string} destination Destination file path in the User Store
+ */
+ putUserStoreDest(path, destination) {
+ this.put(path, this.service_name + ":/userstore?partialPath=" + escape(destination));
+ }
+
+ /**
+ * Alias to putUserStoreDest() that generates the destination
+ * @param {any} path
+ */
+ putUserStore(path) {
+ var destination = path.replace("file://", "");
+ this.putUserStoreDest(path, destination);
+ }
+ /**
+ * Adds a GET command to the download list
+ * @param {string} file Non-absolute path of client destination file (relative to group base)
+ * @param {string} path Absolute file://Disk/ path of destination
+ * @param {string} source wtv-url to fetch file from
+ * @param {string} group Group this file belongs to
+ * @param {string} display Message to display while working on this file
+ * @param {string} checksum md5sum of the file
+ * @param {string} file_permission File permissions
+ */
+ get(file, path, source, group, checksum = null, uncompressed_size = null, original_filename = null, file_permission = 'r') {
+ if (original_filename) {
+ file = file.split('/');
+ var file_name = file[file.length - 1];
+ path = path.replace(file_name, original_filename);
+ file.pop();
+ if (file.length > 0) file = file.join('/') + '/' + original_filename;
+ else file = original_filename;
+ }
+ this.download_list += "GET " + file + "\n";
+
+ this.download_list += "group: " + group + "-UPDATE\n";
+ this.download_list += "location: " + source + "\n";
+ this.download_list += "file-permission: " + file_permission + "\n";
+ if (checksum != null) this.download_list += "wtv-checksum: " + checksum + "\n";
+ if (uncompressed_size != null) this.download_list += "wtv-uncompressed-filesize: " + uncompressed_size + "\n";
+ this.download_list += "service-source-location: /webtv/content/" + source.substr(source.indexOf('-') + 1, source.indexOf(':/') - source.indexOf('-') - 1) + "d/" + source.substr(source.indexOf(':/') + 2) + "\n";
+ this.download_list += "client-dest-location: " + path + "\n\n";
+ }
+
+ /**
+ * Adds a RENAME command to the download list
+ * @param {string} srcfile Non-absolute path of client source file (relative to source group base)
+ * @param {string} destfile Non-absolute path of client destination file (relative to destination group base)
+ * @param {string} srcgroup Source Group
+ * @param {string} destgroup Destination Group
+ */
+ rename(srcfile, destfile, srcgroup, destgroup) {
+ srcfile = this.wtvshared.stripGzipFromPath(srcfile);
+ destfile = this.wtvshared.stripGzipFromPath(destfile);
+ this.download_list += "RENAME " + srcfile + "\n";
+ this.download_list += "group: " + srcgroup + "-UPDATE\n";
+ this.download_list += "destination-group: " + destgroup + "\n";
+ this.download_list += "location: " + destfile + "\n\n";
+ }
+
+ /**
+ * Adds a SET-GROUP command to the download list
+ * @param {string} group Group to set state of
+ * @param {string} state State to set group to
+ * @param {string} version Version to set group to
+ */
+ setGroup(group, state, version) {
+ this.download_list += "SET-GROUP " + group + "\n";
+ this.download_list += "state: " + state + "\n";
+ this.download_list += "version: " + version + "\n";
+ this.download_list += "last-checkup-time: " + new Date().toUTCString().replace("GMT", "+0000") + "\n\n";
+ }
+
+ /**
+ * Adds a DELETE-GROUP command to the download list
+ * @param {string} group Group to delete
+ */
+ deleteGroup(group) {
+ this.download_list += "DELETE-GROUP " + group + "\n\n";
+ }
+
+ /**
+ * An alias for deleteGroup() that handles deleting the '-UPDATE' group files for you
+ * @param {string} group Group to delete
+ * @param {string} path Group base path
+ */
+ deleteGroupUpdate(group, path) {
+ this.deleteGroup(group + "-UPDATE");
+ this.delete(path + ".GROUP-UPDATE/");
+ }
+
+ /**
+ * Generates the Download page
+ * @param {object} minisrv_config minisrv config object
+ * @param {string} title Page title
+ * @param {string} group
+ * @param {string|null} diskmap
+ * @param {string|null} main_message Message displayed in the center of the page
+ * @param {string|null} message Initial progress bar message
+ * @param {boolean|null} force_update Force this update even if the client reports the files are synced
+ * @param {string|null} success_url Where the client goes when the process succeeds
+ * @param {string|null} fail_url Where the client goes when the process fails.
+ * @param {string|null} url Use your own URL for client:fetch?source= instead of our generated one
+ * @returns {string} HTML Download Page
+ */
+ getSyncPage(title, group, diskmap = null, main_message = null, message = null, force_update = null, success_url = null, fail_url = null, url = null) {
+ // Begin Set defaults
+ if (main_message === null) main_message = "Your receiver is downloading files.";
+
+ if (message === null) message = "Retrieving files";
+
+ if (force_update === null) force_update = false;
+
+ if (url === null) url = this.service_name + ":/sync?diskmap=" + escape(diskmap) + "&force=" + force_update;
+
+ if (success_url === null) success_url = new this.clientShowAlert({
+ 'image': this.minisrv_config.config.service_logo,
+ 'message': "Download successful!",
+ 'buttonlabel1': "Okay",
+ 'buttonaction1': "client:goback",
+ 'noback': true,
+ }).getURL();
+
+ if (fail_url === null) fail_url = new this.clientShowAlert({
+ 'image': this.minisrv_config.config.service_logo,
+ 'message': "Download failed...",
+ 'buttonlabel1': "Fuck!",
+ 'buttonaction1': "client:goback",
+ 'noback': true,
+ }).getURL();
+ // End set defaults
+ return `
+
+
+
+ ${title}
+
+
+
+
+
+
+ |
+
+
+
+
+
+ ${message}
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+ ${main_message}
+ This may take a while.
+
+ |
+ |
+ |
+
+
+
+
+ | |
+
+
+
+`
+ }
+
+}
+
+module.exports = WTVDownloadList;
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/WTVFlashrom.js b/zefie_wtvp_minisrv/WTVFlashrom.js
index 986c4666..cf8b6c9e 100644
--- a/zefie_wtvp_minisrv/WTVFlashrom.js
+++ b/zefie_wtvp_minisrv/WTVFlashrom.js
@@ -5,16 +5,18 @@ class WTVFlashrom {
use_zefie_server = true;
bf0app_update = false;
service_vaults = new Array();
+ no_debug = false;
service_name = "";
- zdebug = false;
+ minisrv_config = [];
- constructor(service_vaults, service_name, use_zefie_server = true, bf0app_update = false, debug = false) {
+ constructor(minisrv_config, service_vaults, service_name, use_zefie_server = true, bf0app_update = false, no_debug = false) {
this.service_vaults = service_vaults;
this.service_name = service_name;
this.use_zefie_server = use_zefie_server;
this.bf0app_update = bf0app_update;
- this.zdebug = true;
+ this.no_debug = no_debug;
+ this.minisrv_config = minisrv_config;
}
@@ -95,31 +97,37 @@ class WTVFlashrom {
if (flashrom_info.magic == flashrom_magic) flashrom_info.valid_flashrom = true;
if (!flashrom_info.valid_flashrom) console.error(" * Warning! FlashROM File Magic (" + flashrom_info.magic + ") did not match expected magic (" + flashrom_magic + ")...");
- if (this.zdebug) console.log(" # FlashROM File Magic (" + flashrom_info.magic + "), expected magic (" + flashrom_magic + "), OK = " + flashrom_info.valid_flashrom + "...");
+ //if (this.minisrv_config.config.debug_flags.debug && !this.no_debug) console.log(" # FlashROM File Magic (" + flashrom_info.magic + "), expected magic (" + flashrom_magic + "), OK = " + flashrom_info.valid_flashrom + "...");
flashrom_info.byte_progress = data.readUInt32BE(68);
- if (this.zdebug) console.log(" # Flashrom Part Bytes Sent:", flashrom_info.byte_progress);
flashrom_info.compression_type = parseInt(part_header[16], 16);
- if (this.zdebug) console.log(" # Flashrom Part Compression Type:", flashrom_info.compression_type);
+ //if (this.minisrv_config.config.debug_flags.debug && !this.no_debug) console.log(" # Flashrom Part Compression Type:", flashrom_info.compression_type);
flashrom_info.part_data_size = data.readUInt32BE(4);
- if (this.zdebug) console.log(" # Flashrom Part Data Size:", flashrom_info.part_data_size);
+ //if (this.minisrv_config.config.debug_flags.debug && !this.no_debug) console.log(" # Flashrom Part Data Size:", flashrom_info.part_data_size);
flashrom_info.part_total_size = flashrom_info.part_data_size + flashrom_info.header_length;
- if (this.zdebug) console.log(" # Flashrom Part Total Size:", flashrom_info.part_total_size);
-
flashrom_info.total_parts_size = data.readUInt32BE(32);
- if (this.zdebug) console.log(" # Flashrom All Parts Total Size:", flashrom_info.total_parts_size);
+ flashrom_info.percent_complete = ((((flashrom_info.byte_progress + flashrom_info.part_total_size) / flashrom_info.total_parts_size)) * 100).toFixed(1);
+
+ if (this.minisrv_config.config.debug_flags.debug && !this.no_debug) console.log(" # Flashrom Part Size :", flashrom_info.part_total_size);
+ if (this.minisrv_config.config.debug_flags.debug && !this.no_debug) console.log(" # Flashrom Bytes Sent :", flashrom_info.byte_progress);
+ if (this.minisrv_config.config.debug_flags.debug && !this.no_debug) console.log(" # Flashrom Bytes Sent+:", flashrom_info.byte_progress + flashrom_info.part_total_size, "(" + flashrom_info.percent_complete + "% complete)");
+ if (this.minisrv_config.config.debug_flags.debug && !this.no_debug) console.log(" # Flashrom Total Size :", flashrom_info.total_parts_size);
// read current part number bit from part header
flashrom_info.part_number = data.readUInt16BE(28);
- if (this.zdebug) console.log(" # Flashrom Current Part Number:", flashrom_info.part_number);
+ if (this.minisrv_config.config.debug_flags.debug && !this.no_debug) console.log(" # Flashrom Curr Part Number :", flashrom_info.part_number);
+ flashrom_info.is_last_part = ((flashrom_info.byte_progress + flashrom_info.part_total_size) == flashrom_info.total_parts_size) ? true : false;
+
+ if (flashrom_info.is_last_part) {
+ if (this.minisrv_config.config.debug_flags.debug && !this.no_debug) console.log(" # Flashrom Curr Part is Last:", flashrom_info.is_last_part);
+ } else {
+ flashrom_info.next_part_number = flashrom_info.part_number + 1;
+ if (this.minisrv_config.config.debug_flags.debug && !this.no_debug) console.log(" # Flashrom Next Part Number :", flashrom_info.next_part_number);
+ }
// read current part display message from part header
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:/${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);
if (flashrom_info.is_last_part && this.bf0app_update) {
flashrom_info.next_rompath = null;
@@ -138,7 +146,7 @@ class WTVFlashrom {
var flashrom_info = this.getFlashromInfo(data, request_path)
if (flashrom_info.is_bootrom) headers += "Content-Type: binary/x-wtv-bootrom"; // maybe?
else headers += "Content-Type: binary/x-wtv-flashblock";
- if (flashrom_info.next_rompath != null) headers += "\nwtv-visit: " + flashrom_info.next_rompath;
+ if (flashrom_info.next_rompath != null && this.bf0app_update) headers += "\nwtv-visit: " + flashrom_info.next_rompath;
callback(data, headers);
}
@@ -179,7 +187,7 @@ class WTVFlashrom {
})
res.on('end', function () {
- console.log(` * Zefie's FlashROM Server HTTP Status: ${res.statusCode} ${res.statusMessage}`)
+ if (self.minisrv_config.config.debug_flags.debug) console.log(` * Zefie's FlashROM Server HTTP Status: ${res.statusCode} ${res.statusMessage}`)
if (res.statusCode == 200) {
var data = Buffer.from(data_hex, 'hex');
} else if (res.statusCode == 206) {
diff --git a/zefie_wtvp_minisrv/WTVLzpf.js b/zefie_wtvp_minisrv/WTVLzpf.js
index 5bfea2ea..09eb3cfd 100644
--- a/zefie_wtvp_minisrv/WTVLzpf.js
+++ b/zefie_wtvp_minisrv/WTVLzpf.js
@@ -400,8 +400,6 @@ class WTVLzpf {
this.EncodeLiteral(code_length, code);
}
}
-
- return Buffer.from(this.encoded_data);
}
/**
@@ -442,32 +440,26 @@ class WTVLzpf {
// End
this.AddByte((this.current_literal >>> 0x18) & 0xFF);
this.AddByte(0x20);
+
+ return Buffer.from(this.encoded_data);
}
/**
* Converts the data to a Javascript Buffer object
*
- * @param data {String|Buffer|CryptoJS.lib.WordArray} Data to convert
+ * @param data {String|Buffer} Data to convert
*
* @returns {Buffer} Javascript Buffer object
*/
ConvertToBuffer(data) {
- if (data.words) {
- var WTVSec = require("./WTVSec.js");
- wtvsec = new WTVSec(1);
- data = wtvsec.wordArrayToBuffer(data);
- WTVSec, wtvsec = null;
- } else if (!data.byteLength) {
- // otherwise if its not already a Buffer, convert it to one
- data = new Buffer.from(data);
- }
+ data = new Buffer.from(data.toString('binary'));
return data;
}
/**
* Compress data using WebTV's Lzpf compression algorithm and adds the footer to the end.
*
- * @param uncompressed_data {String|Buffer|CryptoJS.lib.WordArray} data to compress
+ * @param uncompressed_data {String|Buffer} data to compress
*
* @returns {Buffer} Lzpf compression data
*/
@@ -475,9 +467,7 @@ class WTVLzpf {
uncompressed_data = this.ConvertToBuffer(uncompressed_data);
this.Begin();
this.EncodeBlock(uncompressed_data, true);
- this.Finish();
-
- return Buffer.from(this.encoded_data);
+ return this.Finish();
}
}
diff --git a/zefie_wtvp_minisrv/WTVMime.js b/zefie_wtvp_minisrv/WTVMime.js
new file mode 100644
index 00000000..ac9e1eaf
--- /dev/null
+++ b/zefie_wtvp_minisrv/WTVMime.js
@@ -0,0 +1,198 @@
+/**
+ * Simple class for WebTV Mime Types and overrides
+ */
+
+
+class WTVMime {
+
+ mime = require('mime-types');
+ wtvshared = null;
+ minisrv_config = [];
+
+
+ constructor(minisrv_config) {
+ var WTVShared = require('./WTVShared.js')['WTVShared'];
+ this.minisrv_config = minisrv_config;
+ this.wtvshared = new WTVShared(minisrv_config);
+ if (!String.prototype.reverse) {
+ String.prototype.reverse = function () {
+ var splitString = this.split("");
+ var reverseArray = splitString.reverse();
+ var joinArray = reverseArray.join("");
+ return joinArray;
+ }
+ }
+ }
+
+
+ shouldWeCompress(ssid_session, headers_obj) {
+ var compress_data = false;
+ var compression_type = 0; // no compression
+ if (ssid_session) {
+ if (ssid_session.capabilities) {
+ if (ssid_session.capabilities['client-can-receive-compressed-data']) {
+
+ if (this.minisrv_config.config.enable_lzpf_compression || this.minisrv_config.config.force_compression_type) {
+ compression_type = 1; // lzpf
+ }
+
+ if (ssid_session) {
+ // if gzip is enabled...
+ if (this.minisrv_config.config.enable_gzip_compression || this.minisrv_config.config.force_compression_type) {
+ var is_bf0app = ssid_session.get("wtv-client-rom-type") == "bf0app";
+ var is_minibrowser = (ssid_session.get("wtv-needs-upgrade") || ssid_session.get("wtv-used-8675309"));
+ var is_softmodem = ssid_session.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 (this.minisrv_config.config.force_compression_type == "lzpf") compression_type = 1;
+ if (this.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; // approms
+ if (content_type.match(/^binary\/doom-data$/)) compress_data = true; // DOOM WADs
+ }
+ }
+ }
+ }
+ }
+
+ // return compression_type if compress_data = true
+ return (compress_data) ? compression_type : 0;
+ }
+
+ /**
+ * Gets the WebTV Content-Type
+ * @param {string} path Path to a file
+ * @returns {string} Content-Type
+ */
+ getSimpleContentType(path) {
+ return this.getContentType(path)[0];
+ }
+
+ /**
+ * Gets both the WebTV Content-Type and the Modern Content-Type
+ * @param {string} path Path to a file
+ * @returns {Array} (WebTV Content-Type, Modern Content-Type)
+ */
+ getContentType(path) {
+ var file_ext = this.wtvshared.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":
+ wtv_mime_type = "audio/x-aif";
+ break;
+ case "aifc":
+ wtv_mime_type = "audio/x-aifc";
+ break;
+ case "aiff":
+ wtv_mime_type = "audio/x-aiff";
+ break;
+ case "ani":
+ wtv_mime_type = "x-wtv-animation";
+ break;
+ case "brom":
+ wtv_mime_type = "binary/x-wtv-bootrom";
+ break;
+ case "cdf":
+ wtv_mime_type = "application/netcdf";
+ break;
+ case "dat":
+ wtv_mime_type = "binary/cache-data";
+ break;
+ case "dl":
+ wtv_mime_type = "wtv/download-list";
+ break;
+ case "gsm":
+ wtv_mime_type = "audio/x-gsm";
+ break;
+ case "gz":
+ wtv_mime_type = "application/gzip";
+ break;
+ case "ini":
+ wtv_mime_type = "wtv/jack-configuration";
+ break;
+ case "mips-code":
+ wtv_mime_type = "code/x-wtv-code-mips";
+ break;
+ case "o":
+ wtv_mime_type = "binary/x-wtv-approm";
+ break;
+ case "ram":
+ wtv_mime_type = "audio/x-pn-realaudio";
+ break;
+ case "rom":
+ wtv_mime_type = "binary/x-wtv-flashblock";
+ break;
+ case "rsp":
+ wtv_mime_type = "wtv/jack-response";
+ break;
+ case "swa":
+ case "swf":
+ wtv_mime_type = "application/x-shockwave-flash";
+ break;
+ case "srf":
+ case "spl":
+ wtv_mime_type = "wtv/jack-data";
+ break;
+ case "ttf":
+ wtv_mime_type = "wtv/jack-fonts";
+ break;
+ case "tvch":
+ wtv_mime_type = "wtv/tv-channels";
+ break;
+ case "tvl":
+ wtv_mime_type = "wtv/tv-listings";
+ break;
+ case "tvsl":
+ wtv_mime_type = "wtv/tv-smartlinks";
+ break;
+ case "wad":
+ wtv_mime_type = "binary/doom-data";
+ break;
+ case "mp2":
+ case "hsb":
+ case "rmf":
+ case "s3m":
+ case "mod":
+ case "xm":
+ wtv_mime_type = "application/Music";
+ break;
+ }
+
+ modern_mime_type = this.mime.lookup(path);
+ if (wtv_mime_type == "") wtv_mime_type = modern_mime_type;
+ return new Array(wtv_mime_type, modern_mime_type);
+ }
+
+}
+
+module.exports = WTVMime;
diff --git a/zefie_wtvp_minisrv/WTVSec.js b/zefie_wtvp_minisrv/WTVSec.js
index cbdfe98a..a73a5c31 100644
--- a/zefie_wtvp_minisrv/WTVSec.js
+++ b/zefie_wtvp_minisrv/WTVSec.js
@@ -31,19 +31,18 @@ class WTVSec {
hRC4_Key1 = null;
hRC4_Key2 = null;
RC4Session = new Array();
- zdebug = false;
-
+ minisrv_config = [];
/**
*
* Initialize the WTVSec class.
*
* @param {Number} wtv_incarnation Sets the wtv-incarnation for this instance
- * @param {Boolean} zdebug Enable debugging
+ * @param {Boolean} minisrv_config.config.debug_flags.debug Enable debugging
*
*/
- constructor(wtv_incarnation = 1, zdebug = false) {
- this.zdebug = zdebug;
+ constructor(minisrv_config, wtv_incarnation = 1) {
+ this.minisrv_config = minisrv_config;
this.initial_shared_key = CryptoJS.enc.Base64.parse(this.initial_shared_key_b64);
if (this.initial_shared_key.sigBytes === 8) {
@@ -238,7 +237,8 @@ class WTVSec {
* #returns {Buffer} JS Buffer object
*/
wordArrayToBuffer(wordArray) {
- return new Buffer.from(wordArray.toString(CryptoJS.enc.Hex), 'hex');
+ if (wordArray) return new Buffer.from(wordArray.toString(CryptoJS.enc.Hex), 'hex');
+ else return null;
}
/**
@@ -247,7 +247,7 @@ class WTVSec {
*
*/
SecureOn(rc4session = null) {
- if (this.zdebug) console.log(" # Generating RC4 sessions with wtv-incarnation: " + this.incarnation);
+ if (this.minisrv_config.config.debug_flags.debug) console.log(" # Generating RC4 sessions with wtv-incarnation: " + this.incarnation);
var buf = new Uint8Array([0xff & this.incarnation, 0xff & (this.incarnation >> 8), 0xff & (this.incarnation >> 16), 0xff & (this.incarnation >> 24)]);
endianness(buf, 4);
diff --git a/zefie_wtvp_minisrv/WTVShared.js b/zefie_wtvp_minisrv/WTVShared.js
new file mode 100644
index 00000000..f3d6493d
--- /dev/null
+++ b/zefie_wtvp_minisrv/WTVShared.js
@@ -0,0 +1,195 @@
+/**
+ * Shared functions across all classes and apps
+ */
+
+class WTVShared {
+
+ path = require('path');
+ fs = require('fs');
+ minisrv_config = [];
+
+ constructor(minisrv_config) {
+ this.minisrv_config = minisrv_config;
+ if (!String.prototype.reverse) {
+ String.prototype.reverse = function () {
+ var splitString = this.split("");
+ var reverseArray = splitString.reverse();
+ var joinArray = reverseArray.join("");
+ return joinArray;
+ }
+ }
+ }
+
+ /**
+ * Returns the Last-Modified date in Unix Timestamp format
+ * @param {string} file Path to a file
+ */
+ getFileLastModified(file) {
+ var stats = this.fs.lstatSync(file);
+ if (stats) return new Date(stats.mtimeMs);
+ return false;
+ }
+
+ /**
+ * Returns the Last-Modified date in a RFC7231 compliant UTC Date String
+ * @param {string} file Path to a file
+ */
+ getFileLastModifiedUTCString(file) {
+ return this.getFileLastModified(file).toUTCString();
+ }
+
+ /**
+ * Returns a RFC7231 compliant UTC Date String from the current time
+ * @param {Number} offset Offset from current time (+/-)
+ * @returns {string} A RFC7231 compliant UTC Date String from the current time
+ */
+ getUTCTime(offset = 0) {
+ return new Date((new Date).getTime() + offset).toUTCString();
+ }
+
+ /**
+ * Returns a censored SSID
+ * @param {string|Array} obj SSID String or Headers Object
+ */
+ filterSSID(obj) {
+ if (this.minisrv_config.config.hide_ssid_in_logs === true) {
+ if (typeof (obj) == "string") {
+ if (obj.substr(0, 8) == "MSTVSIMU") {
+ return obj.substr(0, 10) + ('*').repeat(10) + obj.substr(20);
+ } else if (obj.substr(0, 5) == "1SEGA") {
+ return obj.substr(0, 6) + ('*').repeat(6) + obj.substr(13);
+ } else {
+ return obj.substr(0, 6) + ('*').repeat(9);
+ }
+ } else {
+ if (obj["wtv-client-serial-number"]) {
+ var ssid = obj["wtv-client-serial-number"];
+ if (ssid.substr(0, 8) == "MSTVSIMU") {
+ obj["wtv-client-serial-number"] = ssid.substr(0, 10) + ('*').repeat(10) + ssid.substr(20);
+ } else if (ssid.substr(0, 5) == "1SEGA") {
+ obj["wtv-client-serial-number"] = ssid.substr(0, 6) + ('*').repeat(6) + ssid.substr(13);
+ } else {
+ obj["wtv-client-serial-number"] = ssid.substr(0, 6) + ('*').repeat(9);
+ }
+ }
+ return obj;
+ }
+ } else {
+ return obj;
+ }
+ }
+
+ /**
+ * Returns an absolute path
+ * @param {string} path
+ * @param {string} directory Root directory
+ */
+ getAbsolutePath(path, directory = __dirname) {
+ if (path.substring(0, 1) != this.path.sep && path.substring(1, 1) != ":") {
+ // non-absolute path, so use current directory as base
+ path = (directory + this.path.sep + path);
+ } else {
+ // already absolute path
+ }
+ return path;
+ }
+
+ /**
+ * Returns a percentage
+ * @param {number} partialValue
+ * @param {number} totalValue
+ * @returns {number} percentage
+ */
+ getPercentage = function (partialValue, totalValue) {
+ return Math.floor((100 * partialValue) / totalValue);
+ }
+
+ /**
+ * If the file ends with .gz, remove it
+ * @param {string} path
+ * @return {string} path without gz, or unmodified path if it isnt a gz
+ */
+ stripGzipFromPath(path) {
+ var path_split = path.split('.');
+ if (path_split[path_split.length - 1].toLowerCase() == "gz") {
+ path_split.pop();
+ path = path_split.join(".");
+ }
+ return path;
+ }
+
+ /**
+ * Gets the file extension from a path
+ * @param {string} path
+ * @returns {String} File Extension (without dot)
+ */
+ getFileExt(path) {
+ return path.reverse().split(".")[0].reverse();
+ }
+
+ /**
+ * Strips bad things from paths
+ * @param {string} base Base path
+ * @param {string} target Sub path
+ */
+ makeSafePath(base, target) {
+ target.replace(/[\|\&\;\$\%\@\"\<\>\+\,\\]/g, "");
+ if (this.path.sep != "/") target = target.replace(/\//g, this.path.sep);
+ var targetPath = this.path.posix.normalize(target)
+ return base + this.path.sep + targetPath;
+ }
+
+ /**
+ * Makes sure an SSID is clean, and doesn't contain any exploitable characters
+ * @param {string} ssid
+ * @returns {string} Sanitized SSID
+ */
+ makeSafeSSID(ssid = "") {
+ ssid = ssid.replace(/[^a-zA-Z0-9]/g, "");
+ if (ssid.length == 0) ssid = null;
+ return ssid;
+ }
+}
+
+class clientShowAlert {
+ message = null;
+ buttonlabel1 = null;
+ buttonlabel2 = null;
+ buttonaction1 = null;
+ buttonaction2 = null;
+ noback = null;
+ image = null;
+
+ constructor(image = null, message = null, buttonlabel1 = null, buttonaction1 = null, buttonlabel2 = null, buttonaction2 = null, noback = null) {
+ this.message = message;
+ this.buttonlabel1 = buttonlabel1;
+ this.buttonlabel2 = buttonlabel2;
+ this.buttonaction1 = buttonaction1;
+ this.buttonaction2 = buttonaction2;
+ this.message = message;
+ this.noback = noback;
+ if (typeof image === 'object') {
+ this.image = null;
+ Object.keys(image).forEach(function (k) {
+ if (this[k] === null) this[k] = image[k];
+ }, this);
+ } else {
+ this.image = image;
+ }
+ }
+
+ getURL() {
+ var url = "client:ShowAlert?";
+ if (this.message) url += "message=" + escape(this.message) + "&";
+ if (this.buttonlabel1) url += "buttonlabel1=" + escape(this.buttonlabel1) + "&";
+ if (this.buttonaction1) url += "buttonaction1=" + escape(this.buttonaction1) + "&";
+ if (this.buttonlabel2) url += "buttonlabel2=" + escape(this.buttonlabel2) + "&";
+ if (this.buttonaction2) url += "buttonaction2=" + escape(this.buttonaction2) + "&";
+ if (this.image) url += "image=" + escape(this.image) + "&";
+ if (this.noback) url += "noback=true&";
+ return url.substring(0, url.length - 1);
+ }
+}
+
+module.exports.WTVShared = WTVShared;
+module.exports.clientShowAlert = clientShowAlert;
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/app.js b/zefie_wtvp_minisrv/app.js
index ac1624bb..c7810f1b 100644
--- a/zefie_wtvp_minisrv/app.js
+++ b/zefie_wtvp_minisrv/app.js
@@ -8,13 +8,14 @@ const https = require('https');
const strftime = require('strftime'); // used externally by service scripts
const net = require('net');
const CryptoJS = require('crypto-js');
-const mime = require('mime-types');
const { crc16 } = require('easy-crc');
const process = require('process');
var WTVSec = require('./WTVSec.js');
var WTVLzpf = require('./WTVLzpf.js');
var WTVClientCapabilities = require('./WTVClientCapabilities.js');
var WTVClientSessionData = require('./WTVClientSessionData.js');
+var WTVMime = require("./WTVMime.js");
+var { WTVShared, clientShowAlert } = require("./WTVShared.js");
process
.on('SIGTERM', shutdown('SIGTERM'))
@@ -70,10 +71,6 @@ function getServiceString(service, overrides = {}) {
}
}
-function getFileExt(path) {
- return path.reverse().split(".")[0].reverse();
-}
-
function doErrorPage(code, data = null, pc_mode = false) {
var headers = null;
switch (code) {
@@ -105,99 +102,6 @@ function doErrorPage(code, data = null, pc_mode = false) {
return new Array(headers, data);
}
-
-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":
- wtv_mime_type = "audio/x-aif";
- break;
- case "aifc":
- wtv_mime_type = "audio/x-aifc";
- break;
- case "aiff":
- wtv_mime_type = "audio/x-aiff";
- break;
- case "ani":
- wtv_mime_type = "x-wtv-animation";
- break;
- case "brom":
- wtv_mime_type = "binary/x-wtv-bootrom";
- break;
- case "cdf":
- wtv_mime_type = "application/netcdf";
- break;
- case "dat":
- wtv_mime_type = "binary/cache-data";
- break;
- case "dl":
- wtv_mime_type = "wtv/download-list";
- break;
- case "gsm":
- wtv_mime_type = "audio/x-gsm";
- break;
- case "gz":
- wtv_mime_type = "application/gzip";
- break;
- case "ini":
- wtv_mime_type = "wtv/jack-configuration";
- break;
- case "mips-code":
- wtv_mime_type = "code/x-wtv-code-mips";
- break;
- case "o":
- wtv_mime_type = "binary/x-wtv-approm";
- break;
- case "ram":
- wtv_mime_type = "audio/x-pn-realaudio";
- break;
- case "rom":
- wtv_mime_type = "binary/x-wtv-flashblock";
- break;
- case "rsp":
- wtv_mime_type = "wtv/jack-response";
- break;
- case "swa":
- case "swf":
- wtv_mime_type = "application/x-shockwave-flash";
- break;
- case "srf":
- case "spl":
- wtv_mime_type = "wtv/jack-data";
- break;
- case "ttf":
- wtv_mime_type = "wtv/jack-fonts";
- break;
- case "tvch":
- wtv_mime_type = "wtv/tv-channels";
- break;
- case "tvl":
- wtv_mime_type = "wtv/tv-listings";
- break;
- case "tvsl":
- wtv_mime_type = "wtv/tv-smartlinks";
- break;
- case "wad":
- wtv_mime_type = "binary/doom-data";
- break;
- case "mp2":
- case "hsb":
- case "rmf":
- case "s3m":
- case "mod":
- case "xm":
- wtv_mime_type = "application/Music";
- break;
- }
-
- 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) {
var headers, data = null;
var request_is_async = false;
@@ -206,7 +110,7 @@ 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 = wtvshared.makeSafePath(service_vault_dir, service_path);
// deny access to catchall file name directly
var service_path_split = service_path.split("/");
@@ -230,8 +134,9 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
// 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 contypes = getConType(service_vault_file_path);
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * Found " + service_vault_file_path + " to handle request (Direct File Mode) [Socket " + socket.id + "]");
+ request_headers.service_file_path = service_vault_file_path;
+ var contypes = wtvmime.getContentType(service_vault_file_path);
headers = "200 OK\n"
headers += "Content-Type: " + contypes[0] + "\n";
headers += "wtv-modern-content-type" + contypes[1];
@@ -241,8 +146,9 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
} else if (fs.existsSync(service_vault_file_path + ".txt")) {
// raw text format, entire payload expected (headers and content)
service_vault_found = true;
- if (!zquiet) console.log(" * Found " + service_vault_file_path + ".txt to handle request (Raw TXT Mode) [Socket " + socket.id + "]");
request_is_async = true;
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * Found " + service_vault_file_path + ".txt to handle request (Raw TXT Mode) [Socket " + socket.id + "]");
+ request_headers.service_file_path = service_vault_file_path + ".txt";
fs.readFile(service_vault_file_path + ".txt", 'Utf-8', function (err, file_raw) {
if (file_raw.indexOf("\n\n") > 0) {
// split headers and data by newline (unix format)
@@ -272,18 +178,20 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
// In Asynchronous mode, you are expected to call sendToClient(socket,headers,data) by the end of your script
// `socket` is already defined and should be passed-through.
service_vault_found = true;
- if (!zquiet) console.log(" * Found " + service_vault_file_path + ".js to handle request (JS Interpreter mode) [Socket " + socket.id + "]");
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * Found " + service_vault_file_path + ".js to handle request (JS Interpreter mode) [Socket " + socket.id + "]");
+ request_headers.service_file_path = service_vault_file_path + ".js";
// expose var service_dir for script path to the root of the wtv-service
var service_dir = service_vault_dir + path.sep + service_name;
socket_sessions[socket.id].starttime = Math.floor(new Date().getTime() / 1000);
var jscript_eval = fs.readFileSync(service_vault_file_path + ".js").toString();
eval(jscript_eval);
- if (request_is_async && !zquiet) console.log(" * Script requested Asynchronous mode");
+ if (request_is_async && !minisrv_config.config.debug_flags.quiet) console.log(" * Script requested Asynchronous mode");
}
else if (fs.existsSync(service_vault_file_path + ".html")) {
// Standard HTML with no headers, WTV Style
service_vault_found = true;
- if (!zquiet) console.log(" * Found " + service_vault_file_path + ".html to handle request (HTML Mode) [Socket " + socket.id + "]");
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * Found " + service_vault_file_path + ".html to handle request (HTML Mode) [Socket " + socket.id + "]");
+ request_headers.service_file_path = service_vault_file_path + ".html";
request_is_async = true;
headers = "200 OK\n"
headers += "Content-Type: text/html"
@@ -303,12 +211,13 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
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 + "]");
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * Found catchall at " + catchall_file + " to handle request (JS Interpreter Mode) [Socket " + socket.id + "]");
+ request_headers.service_file_path = catchall_file;
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");
+ if (request_is_async && !minisrv_config.config.debug_flags.quiet) console.log(" * Script requested Asynchronous mode");
} else {
service_check_dir.pop();
}
@@ -345,47 +254,6 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
}
}
-function filterSSID(obj) {
- if (minisrv_config.config.hide_ssid_in_logs === true) {
- if (typeof (obj) == "string") {
- if (obj.substr(0, 8) == "MSTVSIMU") {
- return obj.substr(0, 10) + ('*').repeat(10) + obj.substr(20);
- } else if (obj.substr(0, 5) == "1SEGA") {
- return obj.substr(0, 6) + ('*').repeat(6) + obj.substr(13);
- } else {
- return obj.substr(0, 6) + ('*').repeat(9);
- }
- } else {
- 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") {
- obj["wtv-client-serial-number"] = ssid.substr(0, 6) + ('*').repeat(6) + ssid.substr(13);
- } else {
- obj["wtv-client-serial-number"] = ssid.substr(0, 6) + ('*').repeat(9);
- }
- }
- return obj;
- }
- } else {
- return 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);
- var targetPath = path.posix.normalize(target)
- return base + path.sep + targetPath;
-}
-
async function processURL(socket, request_headers) {
var shortURL, headers, data = "";
request_headers.query = new Array();
@@ -406,30 +274,36 @@ async function processURL(socket, request_headers) {
} else {
shortURL = unescape(request_headers.request_url);
}
+ if (request_headers['wtv-request-type']) socket_sessions[socket.id].wtv_request_type = request_headers['wtv-request-type'];
if (request_headers.post_data) {
- var post_data_string = request_headers.post_data.toString(CryptoJS.enc.Utf8).replace("\0", "");
- if (isUnencryptedString(post_data_string)) {
- if (post_data_string.indexOf('=')) {
- if (post_data_string.indexOf('&')) {
- var qraw = post_data_string.split('&');
- if (qraw.length > 0) {
- for (let i = 0; i < qraw.length; i++) {
- var qraw_split = qraw[i].split("=");
- if (qraw_split.length == 2) {
- var k = qraw_split[0];
- request_headers.query[k] = unescape(qraw[i].split("=")[1].replace(/\+/g, "%20"));
+ var post_data_string = '';
+ try {
+ post_data_string = request_headers.post_data.toString(CryptoJS.enc.Utf8).replace("\0", ""); // if not text this will probably throw an exception
+ if (isUnencryptedString(post_data_string)) {
+ if (post_data_string.indexOf('=')) {
+ if (post_data_string.indexOf('&')) {
+ var qraw = post_data_string.split('&');
+ if (qraw.length > 0) {
+ for (let i = 0; i < qraw.length; i++) {
+ var qraw_split = qraw[i].split("=");
+ if (qraw_split.length == 2) {
+ var k = qraw_split[0];
+ request_headers.query[k] = unescape(qraw[i].split("=")[1].replace(/\+/g, "%20"));
+ }
}
}
- }
- } else {
- var qraw_split = post_data_string.split("=");
- if (qraw_split.length == 2) {
- var k = qraw_split[0];
- request_headers.query[k] = unescape(qraw_split[1].replace(/\+/g, "%20"));
+ } else {
+ var qraw_split = post_data_string.split("=");
+ if (qraw_split.length == 2) {
+ var k = qraw_split[0];
+ request_headers.query[k] = unescape(qraw_split[1].replace(/\+/g, "%20"));
+ }
}
}
}
+ } catch (e) {
+ // do nothing
}
}
@@ -469,26 +343,22 @@ async function processURL(socket, request_headers) {
var ssid = socket.ssid;
if (ssid == null) {
// prevent possible injection attacks via SSID and filesystem SessionStore
- ssid = makeSafeSSID(request_headers["wtv-client-serial-number"]);
+ ssid = wtvshared.makeSafeSSID(request_headers["wtv-client-serial-number"]);
if (ssid == "") ssid = null;
}
var reqverb = "Request";
- if (request_headers.encrypted || request_headers.secure) {
- reqverb = "Encrypted " + reqverb;
- }
- if (request_headers.psuedo_encryption) {
- reqverb = "Psuedo-encrypted " + reqverb;
- }
+ if (request_headers.encrypted || request_headers.secure) reqverb = "Encrypted " + reqverb;
if (ssid != null) {
- console.log(" * " + reqverb + " for " + request_headers.request_url + " from WebTV SSID " + (await filterSSID(ssid)), 'on', socket.id);
+ console.log(" * " + reqverb + " for " + request_headers.request_url + " from WebTV SSID " + (await wtvshared.filterSSID(ssid)), 'on', socket.id);
} else {
console.log(" * " + reqverb + " for " + request_headers.request_url, 'on', socket.id);
}
// assume webtv since there is a :/ in the GET
var service_name = shortURL.split(':/')[0];
var urlToPath = service_name + path.sep + shortURL.split(':/')[1];
- if (zshowheaders) console.log(" * Incoming headers on socket ID", socket.id, (await filterSSID(request_headers)));
+ if (minisrv_config.config.debug_flags.show_headers) console.log(" * Incoming headers on socket ID", socket.id, (await wtvshared.filterSSID(request_headers)));
+ socket_sessions[socket.id].request_headers = request_headers;
processPath(socket, urlToPath, request_headers, service_name);
} else if (shortURL.indexOf('http://') >= 0 || shortURL.indexOf('https://') >= 0) {
doHTTPProxy(socket, request_headers);
@@ -505,7 +375,7 @@ async function processURL(socket, request_headers) {
async function doHTTPProxy(socket, request_headers) {
var request_type = (request_headers.request_url.substring(0, 5) == "https") ? "https" : "http";
- if (zshowheaders) console.log(request_type.toUpperCase() +" Proxy: Client Request Headers on socket ID", socket.id, (await filterSSID(request_headers)));
+ if (minisrv_config.config.debug_flags.show_headers) console.log(request_type.toUpperCase() +" Proxy: Client Request Headers on socket ID", socket.id, (await wtvshared.filterSSID(request_headers)));
switch (request_type) {
case "https":
var proxy_agent = https;
@@ -670,68 +540,6 @@ function headerStringToObj(headers, response = false) {
return headers_obj;
}
-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;
@@ -766,13 +574,39 @@ async function sendToClient(socket, headers_obj, data) {
delete headers_obj["Content-type"];
}
+ // Add last modified if not a dynamic script
+ if (socket_sessions[socket.id]) {
+ if (socket_sessions[socket.id].request_headers) {
+ if (wtvshared.getFileExt(socket_sessions[socket.id].request_headers.service_file_path).toLowerCase() !== "js") {
+ var last_modified = wtvshared.getFileLastModifiedUTCString(socket_sessions[socket.id].request_headers.service_file_path);
+ if (last_modified) headers_obj["Last-Modified"] = last_modified;
+ }
+ }
+ }
+
+ if (content_length > 0) {
+ if (socket_sessions[socket.id].wtv_request_type == "download") {
+ if (headers_obj['Content-Type'] != "wtv/download-list") {
+ if (wtvshared.getFileExt(socket_sessions[socket.id].request_headers.request_url).toLowerCase() == "gz") {
+ // we need the checksum of the uncompressed data
+ var gunzipped = zlib.gunzipSync(data);
+ headers_obj['wtv-checksum'] = CryptoJS.MD5(CryptoJS.lib.WordArray.create(gunzipped)).toString(CryptoJS.enc.Hex).toLowerCase();
+ headers_obj['wtv-uncompressed-size'] = gunzipped.byteLength;
+ gunzipped = null;
+ } else {
+ headers_obj['wtv-checksum'] = CryptoJS.MD5(CryptoJS.lib.WordArray.create(data)).toString(CryptoJS.enc.Hex).toLowerCase();
+ }
+ }
+ }
+ }
+
// if box can do compression, see if its worth enabling
// 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);
+ if (content_length >= 256) compression_type = wtvmime.shouldWeCompress(ssid_sessions[socket.ssid], headers_obj);
// compress if needed
- if (compression_type > 0 && content_length > 0 && headers_obj['http_response'].substring(0,3) == "200") {
+ 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:
@@ -801,21 +635,27 @@ async function sendToClient(socket, headers_obj, data) {
// 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);
+ var compression_ratio = (uncompressed_content_length / compressed_content_length).toFixed(2);
+ var compression_percentage = ((1 - (compressed_content_length / uncompressed_content_length)) * 100).toFixed(1);
+ if (uncompressed_content_length != compressed_content_length) if (minisrv_config.config.debug_flags.debug) console.log(" # Compression stats: Orig Size:", uncompressed_content_length, "~ Comp Size:", compressed_content_length, "~ Ratio:", compression_ratio, "Saved:", compression_percentage.toString() + "%");
}
// encrypt if needed
- if (socket_sessions[socket.id].secure == true) {
+ if (socket_sessions[socket.id].secure == true && !socket_sessions[socket.id].do_not_encrypt) {
headers_obj["wtv-encrypted"] = 'true';
headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj);
if (content_length > 0 && socket_sessions[socket.id].wtvsec) {
- if (!zquiet) console.log(" * Encrypting response to client ...")
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * Encrypting response to client ...")
var enc_data = socket_sessions[socket.id].wtvsec.Encrypt(1, data);
data = enc_data;
}
}
+ if (socket_sessions[socket.id].do_not_encrypt) {
+ if (headers_obj["wtv-encrypted"]) delete headers_obj["wtv-encrypted"];
+ if (headers_obj["secure"]) delete headers_obj["secure"];
+ }
+
// calculate content length
// make sure we are using our Content-length and not one set in a script.
if (headers_obj["Content-Length"]) delete headers_obj["Content-Length"];
@@ -841,8 +681,23 @@ async function sendToClient(socket, headers_obj, data) {
headers_obj['http_response'] = "HTTP/1.0 " + headers_obj['http_response'];
}
+/* // wtv-request-type download wants minimal headers?
+ if (data.byteLength > 0) {
+ if (socket_sessions[socket.id].wtv_request_type == "download") {
+ if (headers_obj['Content-Type'] != "wtv/download-list") {
+ // minimalize headers
+ var new_headers = { "http_response": headers_obj['http_response'].split(" ")[0] + " " }
+ if (headers_obj['wtv-encrypted']) new_headers['wtv-encrypted'] = headers_obj['wtv-encrypted'];
+ new_headers["content-type"] = headers_obj['Content-Type'];
+ new_headers["content-length"] = headers_obj['Content-length'];
+
+ headers_obj = new_headers;
+ }
+ }
+ }
+*/
// header object to string
- if (zshowheaders) console.log(" * Outgoing headers on socket ID", socket.id, (await filterSSID(headers_obj)));
+ if (minisrv_config.config.debug_flags.show_headers) console.log(" * Outgoing headers on socket ID", socket.id, (await wtvshared.filterSSID(headers_obj)));
Object.keys(headers_obj).forEach(function (k) {
if (k == "http_response") {
headers += headers_obj[k] + end_of_line;
@@ -856,40 +711,67 @@ async function sendToClient(socket, headers_obj, data) {
}
});
+ if (headers_obj["Connection"]) {
+ if (headers_obj["Connection"].toLowerCase() == "close" && wtv_connection_close == "true") {
+ socket_sessions[socket.id].destroy_me = true;
+ }
+ }
// send to client
var toClient = null;
if (typeof data == 'string') {
toClient = headers + end_of_line + data;
- socket.write(toClient);
+ sendToSocket(socket, Buffer.from(toClient));
} else if (typeof data == 'object') {
- if (zquiet) var verbosity_mod = (headers_obj["wtv-encrypted"] == 'true') ? " encrypted response" : "";
+ if (minisrv_config.config.debug_flags.quiet) var verbosity_mod = (headers_obj["wtv-encrypted"] == 'true') ? " encrypted response" : "";
if (socket_sessions[socket.id].secure_headers == true) {
// encrypt headers
- if (zquiet) verbosity_mod += " with encrypted headers";
+ if (minisrv_config.config.debug_flags.quiet) verbosity_mod += " with encrypted headers";
var enc_headers = socket_sessions[socket.id].wtvsec.Encrypt(1, headers + end_of_line);
- socket.write(new Uint8Array(concatArrayBuffer(enc_headers, data)));
+ sendToSocket(socket, new Buffer.from(concatArrayBuffer(enc_headers, data)));
} else {
- socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + end_of_line), data)));
+ sendToSocket(socket, new Buffer.from(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 (minisrv_config.config.debug_flags.quiet) 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;
- if (socket_sessions[socket.id].header_buffer) delete socket_sessions[socket.id].header_buffer;
- if (socket_sessions[socket.id].secure_buffer) delete socket_sessions[socket.id].secure_buffer;
- if (socket_sessions[socket.id].buffer) delete socket_sessions[socket.id].buffer;
- if (socket_sessions[socket.id].headers) delete socket_sessions[socket.id].headers;
- if (socket_sessions[socket.id].post_data) delete socket_sessions[socket.id].post_data;
- if (socket_sessions[socket.id].post_data_length) delete socket_sessions[socket.id].post_data_length;
- if (socket_sessions[socket.id].post_data_percents_shown) delete socket_sessions[socket.id].post_data_percents_shown;
+async function sendToSocket(socket, data) {
+ // buffer size = lesser of minisrv_config.config.chunk_size or size remaining
+ var chunk_size = 16384;
+ var can_write = true;
+ var expected_data_out = 0;
+ while ((socket.bytesWritten == 0 || socket.bytesWritten != expected_data_out) && can_write) {
+ if (expected_data_out === 0) expected_data_out = data.byteLength + (socket_sessions[socket.id].socket_total_written || 0);
+ if (socket.bytesWritten == expected_data_out) break;
- if (socket_sessions[socket.id].close_me) socket.end();
- if (headers_obj["Connection"]) {
- if (headers_obj["Connection"].toLowerCase() == "close" && wtv_connection_close == "true") {
- socket.destroy();
+ var data_left = (expected_data_out - socket.bytesWritten);
+ var buffer_size = (data_left >= chunk_size) ? chunk_size : data_left;
+ var offset = (data.byteLength - data_left);
+ var chunk = new Buffer.alloc(buffer_size);
+ data.copy(chunk, 0, offset, (offset + buffer_size));
+ can_write = socket.write(chunk);
+ if (!can_write) {
+ socket.once('drain', function () {
+ sendToSocket(socket, data);
+ });
+ break;
}
}
+ if (socket.bytesWritten == expected_data_out) {
+ socket_sessions[socket.id].socket_total_written = socket.bytesWritten;
+ if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
+ if (socket_sessions[socket.id].header_buffer) delete socket_sessions[socket.id].header_buffer;
+ if (socket_sessions[socket.id].secure_buffer) delete socket_sessions[socket.id].secure_buffer;
+ if (socket_sessions[socket.id].buffer) delete socket_sessions[socket.id].buffer;
+ if (socket_sessions[socket.id].headers) delete socket_sessions[socket.id].headers;
+ if (socket_sessions[socket.id].post_data) delete socket_sessions[socket.id].post_data;
+ if (socket_sessions[socket.id].post_data_length) delete socket_sessions[socket.id].post_data_length;
+ if (socket_sessions[socket.id].post_data_percents_shown) delete socket_sessions[socket.id].post_data_percents_shown;
+ socket.setTimeout(minisrv_config.config.socket_timeout * 1000);
+ if (socket_sessions[socket.id].close_me) socket.end();
+ if (socket_sessions[socket.id].destroy_me) socket.destroy();
+ }
}
function concatArrayBuffer(buffer1, buffer2) {
@@ -922,6 +804,89 @@ function moveObjectElement(currentKey, afterKey, obj) {
if (next !== -1) return result; else return obj;
}
+function checkSecurity(socket) {
+ var out = null;
+ var ip2long = function (ip) {
+ var components;
+
+ if (components = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)) {
+ var iplong = 0;
+ var power = 1;
+ for (var i = 4; i >= 1; i -= 1) {
+ iplong += power * parseInt(components[i]);
+ power *= 256;
+ }
+ return iplong;
+ }
+ else return -1;
+ };
+
+ var isInSubnet = function (ip, subnet) {
+ var mask, base_ip, long_ip = ip2long(ip);
+ if ((mask = subnet.match(/^(.*?)\/(\d{1,2})$/)) && ((base_ip = ip2long(mask[1])) >= 0)) {
+ var freedom = Math.pow(2, 32 - parseInt(mask[2]));
+ return (long_ip > base_ip) && (long_ip < base_ip + freedom - 1);
+ }
+ else return false;
+ };
+
+ var rejectSSIDConnection = function (ssid, blacklist) {
+ if (blacklist) console.log(" * Request from SSID", wtvshared.filterSSID(ssid), "(" + socket.remoteAddr + "), but that SSID is in the blacklist, rejecting.");
+ else console.log(" * Request from SSID", wtvshared.filterSSID(socket.ssid), "(" + socket.remoteAddress + "), but that SSID is not in the whitelist, rejecting.");
+
+ var errpage = doErrorPage(401, "Access to this service is denied.");
+ out = errpage;
+ }
+
+ var checkSSIDIPWhitelist = function (ssid, blacklist) {
+ var ssid_access_list_ip_override = false;
+ if (minisrv_config.config.ssid_ip_allow_list) {
+ if (minisrv_config.config.ssid_ip_allow_list[socket.ssid]) {
+ Object.keys(minisrv_config.config.ssid_ip_allow_list[socket.ssid]).forEach(function (k) {
+ if (minisrv_config.config.ssid_ip_allow_list[socket.ssid][k].indexOf('/') > 0) {
+ if (isInSubnet(socket.remoteAddress, minisrv_config.config.ssid_ip_allow_list[socket.ssid][k])) {
+ // remoteAddr is in allowed subnet
+ ssid_access_list_ip_override = true;
+ }
+ } else {
+ if (socket.remoteAddress == minisrv_config.config.ssid_ip_allow_list[socket.ssid][k]) {
+ // remoteAddr directly matches IP
+ ssid_access_list_ip_override = true;
+ }
+ }
+ });
+ if (!ssid_access_list_ip_override) rejectSSIDConnection(socket.ssid, blacklist);
+ } else {
+ rejectSSIDConnection(socket.ssid, blacklist);
+ }
+ } else {
+ rejectSSIDConnection(socket.ssid, blacklist);
+ }
+ if (ssid_access_list_ip_override && minisrv_config.config.debug_flags.debug) console.log(" * Request from disallowed SSID", wtvshared.filterSSID(ssid), "was allowed due to IP address whitelist");
+ }
+
+ // process whitelist first
+ if (socket.ssid && minisrv_config.config.ssid_allow_list) {
+ var ssid_is_in_whitelist = minisrv_config.config.ssid_allow_list.findIndex(element => element == socket.ssid);
+ if (ssid_is_in_whitelist == -1) {
+ // no whitelist match, but lets see if the remoteAddress is allowed
+ checkSSIDIPWhitelist(socket.ssid, false);
+ }
+ }
+
+ // now check blacklist
+ if (socket.ssid && minisrv_config.config.ssid_block_list) {
+ var ssid_is_in_blacklist = minisrv_config.config.ssid_block_list.findIndex(element => element == socket.ssid);
+ if (ssid_is_in_blacklist != -1) {
+ // blacklist match, but lets see if the remoteAddress is allowed
+ checkSSIDIPWhitelist(socket.ssid, true);
+ }
+ }
+
+ // Passed Security
+ return out;
+}
+
function isUnencryptedString(string, verbose = false) {
// a generic "isAscii" check is not sufficient, as the test will see the binary
// compressed / encrypted data as ASCII. This function checks for characters expected
@@ -931,11 +896,6 @@ function isUnencryptedString(string, verbose = false) {
return /^([A-Za-z0-9\+\/\=\-\.\,\ \"\;\:\?\&\r\n\(\)\%\<\>\_\~\*\@\#\\]{8,})$/.test(string);
}
-function filterSSID(ssid) {
- var WTVCSD = new WTVClientSessionData(null,minisrv_config.config.hide_ssid_in_logs);
- return WTVCSD.filterSSID(ssid);
-}
-
async function processRequest(socket, data_hex, skipSecure = false, encryptedRequest = false) {
// This function sucks and needs to be rewritten
@@ -971,8 +931,8 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
// its not a POST and it failed the isUnencryptedString test, so we think this is an encrypted blob
if (socket_sessions[socket.id].secure != true) {
// first time so reroll sessions
- if (zdebug) console.log(" # [ UNEXPECTED BINARY BLOCK ] First sign of encryption, re-creating RC4 sessions for socket id", socket.id);
- socket_sessions[socket.id].wtvsec = new WTVSec(1, zdebug);
+ if (minisrv_config.config.debug_flags.debug) 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(minisrv_config);
socket_sessions[socket.id].wtvsec.IssueChallenge();
socket_sessions[socket.id].wtvsec.SecureOn();
socket_sessions[socket.id].secure = true;
@@ -1003,10 +963,10 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
if (!headers) return;
if (headers["wtv-client-serial-number"] != null && socket.ssid == null) {
- socket.ssid = makeSafeSSID(headers["wtv-client-serial-number"]);
+ socket.ssid = wtvshared.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] = new WTVClientSessionData(minisrv_config, socket.ssid);
ssid_sessions[socket.ssid].SaveIfRegistered();
}
if (!ssid_sessions[socket.ssid].data_store.sockets) ssid_sessions[socket.ssid].data_store.sockets = new Set();
@@ -1015,96 +975,21 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
}
}
- var ip2long = function (ip) {
- var components;
-
- if (components = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)) {
- var iplong = 0;
- var power = 1;
- for (var i = 4; i >= 1; i -= 1) {
- iplong += power * parseInt(components[i]);
- power *= 256;
- }
- return iplong;
- }
- else return -1;
- };
-
- var isInSubnet = function (ip, subnet) {
- var mask, base_ip, long_ip = ip2long(ip);
- if ((mask = subnet.match(/^(.*?)\/(\d{1,2})$/)) && ((base_ip = ip2long(mask[1])) >= 0)) {
- var freedom = Math.pow(2, 32 - parseInt(mask[2]));
- return (long_ip > base_ip) && (long_ip < base_ip + freedom - 1);
- }
- else return false;
- };
-
- var rejectSSIDConnection = function (ssid, blacklist) {
- 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.");
-
- var errpage = doErrorPage(401, "Access to this service is denied.");
- headers = errpage[0];
- data = errpage[1];
+ var failed_security = checkSecurity(socket);
+ if (failed_security) {
socket_sessions[socket.id].close_me = true;
+ headers = failed_security[0];
+ data = failed_security[1];
}
- var checkSSIDIPWhitelist = function (ssid, blacklist) {
- var ssid_access_list_ip_override = false;
- if (minisrv_config.config.ssid_ip_allow_list) {
- if (minisrv_config.config.ssid_ip_allow_list[socket.ssid]) {
- Object.keys(minisrv_config.config.ssid_ip_allow_list[socket.ssid]).forEach(function (k) {
- if (minisrv_config.config.ssid_ip_allow_list[socket.ssid][k].indexOf('/') > 0) {
- if (isInSubnet(socket.remoteAddress, minisrv_config.config.ssid_ip_allow_list[socket.ssid][k])) {
- // remoteAddr is in allowed subnet
- ssid_access_list_ip_override = true;
- }
- } else {
- if (socket.remoteAddress == minisrv_config.config.ssid_ip_allow_list[socket.ssid][k]) {
- // remoteAddr directly matches IP
- ssid_access_list_ip_override = true;
- }
- }
- });
- if (!ssid_access_list_ip_override) rejectSSIDConnection(socket.ssid, blacklist);
- } else {
- rejectSSIDConnection(socket.ssid, blacklist);
- }
- } else {
- rejectSSIDConnection(socket.ssid, blacklist);
- }
- if (ssid_access_list_ip_override && zdebug) console.log(" * Request from disallowed SSID", filterSSID(ssid), "was allowed due to IP address whitelist");
- }
-
- // process whitelist first
- if (socket.ssid && minisrv_config.config.ssid_allow_list) {
- var ssid_is_in_whitelist = minisrv_config.config.ssid_allow_list.findIndex(element => element == socket.ssid);
- if (ssid_is_in_whitelist == -1) {
- // no whitelist match, but lets see if the remoteAddress is allowed
- checkSSIDIPWhitelist(socket.ssid, false);
- }
- }
-
- // now check blacklist
- if (socket.ssid && minisrv_config.config.ssid_block_list) {
- var ssid_is_in_blacklist = minisrv_config.config.ssid_block_list.findIndex(element => element == socket.ssid);
- if (ssid_is_in_blacklist != -1) {
- // blacklist match, but lets see if the remoteAddress is allowed
- checkSSIDIPWhitelist(socket.ssid, true);
- }
- }
-
- // Passed Security
-
if (headers["wtv-capability-flags"] != 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] = new WTVClientSessionData(minisrv_config, socket.ssid);
ssid_sessions[socket.ssid].SaveIfRegistered();
}
if (!ssid_sessions[socket.ssid].capabilities) ssid_sessions[socket.ssid].capabilities = new WTVClientCapabilities(headers["wtv-capability-flags"]);
}
-
// log all client wtv- headers to the SessionData for that SSID
// this way we can pull up client info such as wtv-client-rom-type or wtv-system-sysconfig
if (socket.ssid) {
@@ -1121,14 +1006,14 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
if (ssid_sessions[socket.ssid]) {
if (headers["wtv-ticket"]) {
if (!ssid_sessions[socket.ssid].data_store.wtvsec_login) {
- ssid_sessions[socket.ssid].data_store.wtvsec_login = new WTVSec();
+ ssid_sessions[socket.ssid].data_store.wtvsec_login = new WTVSec(minisrv_config);
ssid_sessions[socket.ssid].data_store.wtvsec_login.IssueChallenge();
ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(headers["wtv-incarnation"]);
ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 = headers["wtv-ticket"];
ssid_sessions[socket.ssid].data_store.wtvsec_login.DecodeTicket(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64);
} else {
if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 != headers["wtv-ticket"]) {
- if (zdebug) console.log(" # New ticket from client");
+ if (minisrv_config.config.debug_flags.debug) console.log(" # New ticket from client");
ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 = headers["wtv-ticket"];
ssid_sessions[socket.ssid].data_store.wtvsec_login.DecodeTicket(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64);
ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(headers["wtv-incarnation"]);
@@ -1140,11 +1025,11 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
if ((headers.secure === true || headers.encrypted === true) && !skipSecure) {
if (!socket_sessions[socket.id].wtvsec) {
- if (!zquiet) console.log(" * Starting new WTVSec instance on socket", socket.id);
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * Starting new WTVSec instance on socket", socket.id);
if (ssid_sessions[socket.ssid].get("wtv-incarnation")) {
- socket_sessions[socket.id].wtvsec = new WTVSec(ssid_sessions[socket.ssid].get("wtv-incarnation"), zdebug);
+ socket_sessions[socket.id].wtvsec = new WTVSec(minisrv_config, ssid_sessions[socket.ssid].get("wtv-incarnation"));
} else {
- socket_sessions[socket.id].wtvsec = new WTVSec(1, zdebug);
+ socket_sessions[socket.id].wtvsec = new WTVSec(minisrv_config);
}
socket_sessions[socket.id].wtvsec.DecodeTicket(headers["wtv-ticket"]);
socket_sessions[socket.id].wtvsec.ticket_b64 = headers["wtv-ticket"];
@@ -1152,7 +1037,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
}
if (socket_sessions[socket.id].secure != true) {
// first time so reroll sessions
- if (zdebug) console.log(" # [ SECURE ON BLOCK (" + socket.id + ") ]");
+ if (minisrv_config.config.debug_flags.debug) console.log(" # [ SECURE ON BLOCK (" + socket.id + ") ]");
socket_sessions[socket.id].secure = true;
}
if (!headers.request_url) {
@@ -1166,46 +1051,37 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
}
var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2));
if (enc_data.sigBytes > 0) {
- if (isUnencryptedString(enc_data.toString(CryptoJS.enc.Latin1), (!skipSecure && !encryptedRequest))) {
- // some builds (like our targeted 3833), send SECURE ON but then unencrypted headers
- if (zdebug) console.log(" # Psuedo-encrypted Request (SECURE ON)", "on", socket.id);
- // don't actually encrypt output
- headers.psuedo_encryption = true;
- ssid_sessions[socket.ssid].set("box-does-psuedo-encryption", true);
- socket_sessions[socket.id].secure = false;
- var secure_headers = await processRequest(socket, enc_data.toString(CryptoJS.enc.Hex), true, true);
- } else {
- // SECURE ON and detected encrypted data
- 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))
- if (!socket_sessions[socket.id].secure_buffer) socket_sessions[socket.id].secure_buffer = "";
- socket_sessions[socket.id].secure_buffer += dec_data.toString(CryptoJS.enc.Hex);
- var secure_headers = null;
- if (headers['request']) {
- if (headers['request'] == "GET") {
- if (socket_sessions[socket.id].secure_buffer.indexOf("0d0a0d0a") || socket_sessions[socket.id].secure_buffer.indexOf("0a0a")) {
- secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true);
- }
- } else {
- secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true);
+
+ // SECURE ON and detected encrypted data
+ var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data))
+ if (!socket_sessions[socket.id].secure_buffer) socket_sessions[socket.id].secure_buffer = "";
+ socket_sessions[socket.id].secure_buffer += dec_data.toString(CryptoJS.enc.Hex);
+ var secure_headers = null;
+ if (headers['request']) {
+ if (headers['request'] == "GET") {
+ if (socket_sessions[socket.id].secure_buffer.indexOf("0d0a0d0a") || socket_sessions[socket.id].secure_buffer.indexOf("0a0a")) {
+ secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true);
}
} else {
- secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true);
- }
- if (!secure_headers) return;
-
- delete socket_sessions[socket.id].secure_buffer;
- if (zdebug) console.log(" # Encrypted Request (SECURE ON)", "on", socket.id);
- if (zshowheaders) console.log(secure_headers);
- if (!secure_headers.request) {
- socket_sessions[socket.id].secure = false;
- var errpage = doErrorPage(400);
- headers = errpage[0];
- data = errpage[1];
- sendToClient(socket, headers, data);
- return;
+ secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true);
}
+ } else {
+ secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true);
}
+ if (!secure_headers) return;
+
+ delete socket_sessions[socket.id].secure_buffer;
+ if (minisrv_config.config.debug_flags.debug) console.log(" # Encrypted Request (SECURE ON)", "on", socket.id);
+ if (minisrv_config.config.debug_flags.show_headers) console.log(secure_headers);
+ if (!secure_headers.request) {
+ socket_sessions[socket.id].secure = false;
+ var errpage = doErrorPage(400);
+ headers = errpage[0];
+ data = errpage[1];
+ sendToClient(socket, headers, data);
+ return;
+ }
+
// Merge new headers into existing headers object
Object.keys(secure_headers).forEach(function (k) {
headers[k] = secure_headers[k];
@@ -1232,8 +1108,9 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
}
// handle POST
- if (headers['request']) {
+ if (headers['request'] && !socket_sessions[socket.id].expecting_post_data) {
if (headers['request'].substring(0, 4) == "POST") {
+ socket.setTimeout(minisrv_config.config.post_data_socket_timeout * 1000);
if (typeof socket_sessions[socket.id].post_data == "undefined") {
if (socket_sessions[socket.id].post_data_percents_shown) delete socket_sessions[socket.id].post_data_percents_shown;
socket_sessions[socket.id].post_data_length = headers['Content-length'] || headers['Content-Length'] || 0;
@@ -1241,35 +1118,36 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
socket_sessions[socket.id].post_data = "";
socket_sessions[socket.id].headers = headers;
var post_string = "POST";
- if (socket_sessions[socket.id].secure == true) {
- post_string = "Encrypted " + post_string;
- }
+ if (socket_sessions[socket.id].secure) post_string = "Encrypted " + post_string;
// the client may have just sent the data with the primary headers, so lets look for that.
if (data_hex.indexOf("0d0a0d0a") != -1) socket_sessions[socket.id].post_data = data_hex.substring(data_hex.indexOf("0d0a0d0a") + 8);
if (data_hex.indexOf("0a0a") != -1) socket_sessions[socket.id].post_data = data_hex.substring(data_hex.indexOf("0a0a") + 4);
-
}
+
if (socket_sessions[socket.id].post_data.length == (socket_sessions[socket.id].post_data_length * 2)) {
// got all expected data
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_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)");
+ console.log(" * Incoming", post_string, "request on", socket.id, "from", wtvshared.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);
- if (socket_sessions[socket.id].headers) delete socket_sessions[socket.id].headers;
+ delete socket_sessions[socket.id].headers;
+ delete socket_sessions[socket.id].post_data;
+ delete socket_sessions[socket.id].post_data_length;
processURL(socket, headers);
- } else {
- // expecting more data (see below)
- socket_sessions[socket.id].expecting_post_data = true;
- 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
Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length);
+ } else 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 (section 2)
+ var errpage = doErrorPage(400, "Received too much data in POST request
Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length) + " (2)";
headers = errpage[0];
data = errpage[1];
sendToClient(socket, headers, data);
return;
- }
+ } else {
+ // expecting more data (see below)
+ socket_sessions[socket.id].expecting_post_data = true;
+ if (!socket_sessions[socket.id].post_data) socket_sessions[socket.id].post_data = '';
+ socket_sessions[socket.id].post_data += CryptoJS.enc.Hex.parse(socket_sessions[socket.id].post_data);
+ console.log(" * Incoming", post_string, "request on", socket.id, "from", wtvshared.filterSSID(socket.ssid), "to", headers['request_url'], "(expecting", socket_sessions[socket.id].post_data_length, "bytes of data from client...)");
+ }
return;
} else {
delete socket_sessions[socket.id].headers;
@@ -1306,15 +1184,12 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
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 ]");
} else {
// calculate and display percentage of data received
- var getPercentage = function (partialValue, totalValue) {
- return Math.floor((100 * partialValue) / totalValue);
- }
- var postPercent = getPercentage(socket_sessions[socket.id].post_data.length, (socket_sessions[socket.id].post_data_length * 2));
+ var postPercent = wtvshared.getPercentage(socket_sessions[socket.id].post_data.length, (socket_sessions[socket.id].post_data_length * 2));
if (minisrv_config.config.post_percentages) {
if (minisrv_config.config.post_percentages.includes(postPercent)) {
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));
+ console.log(" * Received", postPercent, "% of", socket_sessions[socket.id].post_data_length, "bytes on", socket.id, "from", wtvshared.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;
@@ -1325,20 +1200,21 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
if (socket_sessions[socket.id].post_data.length == (socket_sessions[socket.id].post_data_length * 2)) {
// got all expected data
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
+ socket.setTimeout(minisrv_config.config.socket_timeout * 1000);
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 ]");
+ if (minisrv_config.config.debug_flags.debug) 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);
+ if (minisrv_config.config.debug_flags.debug) 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)) {
+ } else if (socket_sessions[socket.id].post_data.length > (socket_sessions[socket.id].post_data_length * 2)) {
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
+ socket.setTimeout(minisrv_config.config.socket_timeout * 1000);
// got too much data ? ... should not ever reach this code
var errpage = doErrorPage(400, "Received too much data in POST request
Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length);
headers = errpage[0];
@@ -1350,7 +1226,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
} else if (!skipSecure) {
if (!encryptedRequest) {
if (socket_sessions[socket.id].secure != true) {
- socket_sessions[socket.id].wtvsec = new WTVSec(1, zdebug);
+ socket_sessions[socket.id].wtvsec = new WTVSec(minisrv_config);
socket_sessions[socket.id].wtvsec.IssueChallenge();
socket_sessions[socket.id].wtvsec.SecureOn();
socket_sessions[socket.id].secure = true;
@@ -1414,7 +1290,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
async function cleanupSocket(socket) {
try {
if (socket_sessions[socket.id]) {
- if (!zquiet) console.log(" * Cleaning up disconnected socket", socket.id);
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * Cleaning up disconnected socket", socket.id);
delete socket_sessions[socket.id];
}
if (socket.ssid) {
@@ -1434,7 +1310,7 @@ async function cleanupSocket(socket) {
// 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");
+ if (!minisrv_config.config.debug_flags.quiet) console.log(" * WebTV SSID", wtvshared.filterSSID(ssid), " has not been seen in", (timeout / 1000), "seconds, cleaning up session data for this SSID");
delete ssid_sessions[ssid];
}
}, timeout, socket.ssid);
@@ -1453,21 +1329,25 @@ async function handleSocket(socket) {
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.setTimeout(minisrv_config.config.socket_timeout * 1000);
socket.on('data', function (data_hex) {
- if (!socket_sessions[socket.id].secure && !socket_sessions[socket.id].expecting_post_data) {
- // buffer unencrypted data until we see the classic double-newline, or get blank
- if (!socket_sessions[socket.id].header_buffer) socket_sessions[socket.id].header_buffer = "";
- socket_sessions[socket.id].header_buffer += data_hex;
- if (socket_sessions[socket.id].header_buffer.indexOf("0d0a0d0a") != -1 || socket_sessions[socket.id].header_buffer.indexOf("0a0a") != -1) {
- data_hex = socket_sessions[socket.id].header_buffer;
- delete socket_sessions[socket.id].header_buffer;
+ if (socket_sessions[socket.id]) {
+ if (!socket_sessions[socket.id].secure && !socket_sessions[socket.id].expecting_post_data) {
+ // buffer unencrypted data until we see the classic double-newline, or get blank
+ if (!socket_sessions[socket.id].header_buffer) socket_sessions[socket.id].header_buffer = "";
+ socket_sessions[socket.id].header_buffer += data_hex;
+ if (socket_sessions[socket.id].header_buffer.indexOf("0d0a0d0a") != -1 || socket_sessions[socket.id].header_buffer.indexOf("0a0a") != -1) {
+ data_hex = socket_sessions[socket.id].header_buffer;
+ delete socket_sessions[socket.id].header_buffer;
+ processRequest(this, data_hex);
+ }
+ } else {
+ // stream encrypted requests through the processor
+ if (socket_sessions[socket.id].header_buffer) delete socket_sessions[socket.id].header_buffer;
processRequest(this, data_hex);
}
} else {
- // stream encrypted requests through the processor
- if (socket_sessions[socket.id].header_buffer) delete socket_sessions[socket.id].header_buffer;
- processRequest(this, data_hex);
+ cleanupSocket(socket);
}
});
@@ -1563,7 +1443,7 @@ try {
}
}
} catch (e) {
- if (zdebug) console.error(" * Notice: Could not find user configuration (user_config.json). Using default configuration.");
+ if (minisrv_config.config.debug_flags.debug) console.error(" * Notice: Could not find user configuration (user_config.json). Using default configuration.");
}
if (throw_me) {
@@ -1645,40 +1525,41 @@ process.on('uncaughtException', function (err) {
});
// defaults
-var zdebug = false;
-var zquiet = true; // will squash zdebug even if its true
-var zshowheaders = false;
+minisrv_config.config.debug_flags = [];
+minisrv_config.config.debug_flags.debug = false;
+minisrv_config.config.debug_flags.quiet = true; // will squash minisrv_config.config.debug_flags.debug even if its true
+minisrv_config.config.debug_flags.show_headers = false;
if (minisrv_config.config.verbosity) {
switch (minisrv_config.config.verbosity) {
case 0:
- zdebug = false;
- zquiet = true;
- zshowheaders = false;
+ minisrv_config.config.debug_flags.debug = false;
+ minisrv_config.config.debug_flags.quiet = true;
+ minisrv_config.config.debug_flags.show_headers = false;
console.log(" * Console Verbosity level 0 (quietest)")
break;
case 1:
- zdebug = false;
- zquiet = true;
- zshowheaders = true;
+ minisrv_config.config.debug_flags.debug = false;
+ minisrv_config.config.debug_flags.quiet = true;
+ minisrv_config.config.debug_flags.show_headers = true;
console.log(" * Console Verbosity level 1 (headers shown)")
break;
case 2:
- zdebug = true;
- zquiet = true;
- zshowheaders = false;
+ minisrv_config.config.debug_flags.debug = true;
+ minisrv_config.config.debug_flags.quiet = true;
+ minisrv_config.config.debug_flags.show_headers = false;
console.log(" * Console Verbosity level 2 (verbose without headers)")
break;
case 3:
- zdebug = true;
- zquiet = true;
- zshowheaders = true;
+ minisrv_config.config.debug_flags.debug = true;
+ minisrv_config.config.debug_flags.quiet = true;
+ minisrv_config.config.debug_flags.show_headers = true;
console.log(" * Console Verbosity level 3 (verbose with headers)")
break;
default:
- zdebug = true;
- zquiet = false;
- zshowheaders = true;
+ minisrv_config.config.debug_flags.debug = true;
+ minisrv_config.config.debug_flags.quiet = false;
+ minisrv_config.config.debug_flags.show_headers = true;
console.log(" * Console Verbosity level 4 (debug verbosity)")
break;
}
@@ -1702,6 +1583,8 @@ bind_ports.forEach(function (v) {
initstring = initstring.substring(0, initstring.length - 2);
+const wtvshared = new WTVShared(minisrv_config);
+const wtvmime = new WTVMime(minisrv_config);
console.log(" * Started server on ports " + initstring + "...")
var listening_ip_string = (minisrv_config.config.bind_ip != "0.0.0.0") ? "IP: " + minisrv_config.config.bind_ip : "all interfaces";
diff --git a/zefie_wtvp_minisrv/config.json b/zefie_wtvp_minisrv/config.json
index 80bd772d..db14be70 100644
--- a/zefie_wtvp_minisrv/config.json
+++ b/zefie_wtvp_minisrv/config.json
@@ -13,12 +13,15 @@
"hide_ssid_in_logs": true,
"post_percentages": [ 0, 25, 50, 100 ],
"verbosity": 2,
+ "socket_timeout": 86400,
+ "post_data_socket_timeout": 30,
"error_log_file": "errors.log",
"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,
+ "show_diskmap": false,
"allow_guests": true
},
"services": {
diff --git a/zefie_wtvp_minisrv/package.json b/zefie_wtvp_minisrv/package.json
index f16d9473..3486c8d5 100644
--- a/zefie_wtvp_minisrv/package.json
+++ b/zefie_wtvp_minisrv/package.json
@@ -1,6 +1,6 @@
{
"name": "zefie_wtvp_minisrv",
- "version": "0.9.16",
+ "version": "0.9.18",
"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 17205247..29397b0b 100644
--- a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj
+++ b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj
@@ -52,6 +52,10 @@
Code
+
+
+ Code
+
Code
@@ -275,12 +279,18 @@
Code
+
+ Code
+
Code
Code
+
+ Code
+
Code
@@ -288,6 +298,9 @@
Code
+
+ Code
+