diff --git a/README.md b/README.md
index c5e0ea95..6a35a2f6 100644
--- a/README.md
+++ b/README.md
@@ -11,12 +11,12 @@ This open source server is in alpha status. Use at your own risk.
- Suports `.js` service files with synchronous or asynchronous requests
- Supports multiple simultaneous users
- WebTV-compatible HTTP(S) Proxy (via minisrv, or using an external proxy for enhanced features (such as [WebOne](https://github.com/atauenis/webone))
-- wtv-flashrom for LC2 and newer boxes (bf0app unsupported, need test unit)
+- Flashrom flashing support for all known units (including bf0app 'Old Classic')
- Can flash anything on [Ultra Willies](https://wtv.zefie.com/willie.php) with optional `use_zefie_server` flag set on `wtv-flashrom` service.
-- wtv-update:/sync for Download-o-Rama style file downloading
+- `wtv-update:/sync` for Download-o-Rama style file downloading
### Current issues:
-- ~~Occasionally, in certain circumstances, a specific SSID may be unable to reconnect to the server until the server is restarted~~ *Hopefully fixed in [v0.9.3](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.9.3)*
+- Satellite Receiver units reportedly cannot surf with http or https proxy.
- Mis-configuring wtv-update:/sync DiskMaps may cause units to delete contents of partitions (need more info)
### Won't fix:
@@ -24,12 +24,12 @@ This open source server is in alpha status. Use at your own risk.
- No intentions to support user accounts, registration, or any form of database system
### Feature Todo:
-- ~~Implement HTTP proxy (needs to be able to defluff most of the web, think retro WAP converter)~~ ***Done [v0.7.1](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.7.1)***
-- ~~Flashrom flashing functionality (at least for LC2 and higher)~~ ***Done [v0.8.0](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.8.0)***
-- ~~SSID/IP black/whitelisting (including tying SSID to an IP or multiple IPs)~~ ***Done [v0.9.4](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.9.4)***
-- Flashrom flashing for bf0app old classic (need donor unit)
- wtv-lzpf support
-- (maybe) wtvchat stuff
+- TellyScript generation and/or manipulation (needed for Name Server configuration)
+- ~~Flashrom flashing for bf0app old classic~~ ***Done [v0.9.9](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.9.9)***
+- ~~SSID/IP black/whitelisting (including tying SSID to an IP or multiple IPs)~~ ***Done [v0.9.4](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.9.4)***
+- ~~Flashrom flashing functionality (at least for LC2 and higher)~~ ***Done [v0.8.0](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.8.0)***
+- ~~Implement HTTP proxy (needs to be able to defluff most of the web, think retro WAP converter)~~ ***Done [v0.7.1](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.7.1)***
### How To Use:
- Install [node.js](https://nodejs.org/en/download/). Be sure to say `Yes` when asked about `Chocolatey`.
diff --git a/README_bf0app_flashrom.txt b/README_bf0app_flashrom.txt
new file mode 100644
index 00000000..5b13af36
--- /dev/null
+++ b/README_bf0app_flashrom.txt
@@ -0,0 +1,5 @@
+The bf0app flashing system requires a two things that you must be aware of, that are different from a typical setup:
+1) Your PPP system MUST accept auth, a noauth setup will not work for the 2nd dialing phase
+2) You must have a clean dialup. DreamPi voltage-hacked lines, and unstable VoIP systems are known
+ to cause errors, leaving the box in a 'braindead' state with no flash. MiniSrv can help recover
+ from this but you will need to provide a stable dialup connection. This was tested with my Cisco 3825 setup.
\ No newline at end of file
diff --git a/zefie_wtvp_minisrv/ServiceDeps/premade_tellyscripts/BF0APP/bf0app_boot_uncompressed.tok b/zefie_wtvp_minisrv/ServiceDeps/premade_tellyscripts/BF0APP/bf0app_boot_uncompressed.tok
new file mode 100644
index 00000000..958257d6
Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceDeps/premade_tellyscripts/BF0APP/bf0app_boot_uncompressed.tok differ
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/noflash.js.meh b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/noflash.js
similarity index 88%
rename from zefie_wtvp_minisrv/ServiceVault/wtv-1800/noflash.js.meh
rename to zefie_wtvp_minisrv/ServiceVault/wtv-1800/noflash.js
index 89b09d45..89438f2a 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/noflash.js.meh
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/noflash.js
@@ -12,11 +12,12 @@ if (wtvsec_login) {
headers = `200 OK
Connection: Keep-Alive
+minisrv-use-carriage-return: false
wtv-initial-key: ` + wtvsec_login.challenge_key.toString(CryptoJS.enc.Base64) + `
Content-Type: text/tellyscript
wtv-service: reset
` + getServiceString('wtv-head-waiter') + `
-` + getServiceString('wtv-star') + `
+` + getServiceString('wtv-star', { "no_star_word": true }) + `
` + getServiceString('wtv-flashrom') + `
wtv-boot-url: wtv-head-waiter:/login?
wtv-visit: wtv-head-waiter:/login?
@@ -24,22 +25,16 @@ wtv-client-time-zone: GMT -0000
wtv-client-time-dst-rule: GMT
wtv-client-date: `+ strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString())) + ` GMT`;
- var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/bf0app/bf0app_production_braindead";
- //var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/LC2/LC2_OISP_5555732_56k.tok";
+ var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/BF0APP/bf0app_boot_uncompressed.tok";
if (file_path) {
request_is_async = true;
fs.readFile(file_path, null, function (err, file_read_data) {
if (err) {
-
headers=`500 Some error occurred...`
}
sendToClient(socket, headers, file_read_data);
});
-
-
-
-
}
} else {
console.log(" * Something bad happened (we don't know the client ssid???)");
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js
index 0a544efc..4d3be5f2 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js
@@ -1,6 +1,5 @@
var gourl = "wtv-head-waiter:/login?";
if (request_headers.query.relogin) gourl += "relogin=true";
-var send_initial_key = true;
if (socket.ssid) {
if (ssid_sessions[socket.ssid].data_store) {
@@ -103,30 +102,37 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
// assume old classic in flash mode, override user setting and send tellyscript
// because it is required to proceed in flash mode
prereg_contype = "text/tellyscript";
- var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/bf0app/bf0app_production_braindead.tok";
- bf0app_update = true;
+ var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/BF0APP/bf0app_boot_uncompressed.tok";
+ var bf0app_update = true;
+ ssid_sessions[socket.ssid].set("bf0app_update", bf0app_update);
}
if (request_headers["wtv-ticket"]) {
gourl = "wtv-head-waiter:/login-stage-two?relogin=true";
- send_initial_key = false;
}
headers = "200 OK\n"
+ if (bf0app_update) headers += "minisrv-use-carriage-return: false\n";
headers += "Connection: Keep-Alive\n";
- if (send_initial_key) headers += "wtv-initial-key: " + ssid_sessions[socket.ssid].data_store.wtvsec_login.challenge_key.toString(CryptoJS.enc.Base64) + "\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";
- headers += getServiceString('wtv-1800') + "\n";
- headers += getServiceString('wtv-star') + "\n";
- if (!bf0app_update) headers += getServiceString('wtv-head-waiter') + "\n";
+ if (!bf0app_update) headers += getServiceString('wtv-1800') + "\n";
+
+ if (bf0app_update) headers += getServiceString('wtv-head-waiter', { "flags": "0x00000001" }) + "\n";
+ else headers += getServiceString('wtv-head-waiter') + "\n";
+
+ if (bf0app_update) headers += getServiceString('wtv-star', { "no_star_word": true }) + "\n";
+ else headers += getServiceString('wtv-star') + "\n";
+
headers += getServiceString('wtv-flashrom') + "\n";
- if (!bf0app_update) headers += "wtv-boot-url: wtv-1800:/preregister?relogin=true\n"
+ if (bf0app_update) headers += "wtv-boot-url: " + gourl + "\n";
+ else headers += "wtv-boot-url: wtv-1800:/preregister?relogin=true\n";
+ headers += "wtv-visit: " + gourl + "\n";
if (!bf0app_update) headers += "wtv-open-isp-disabled: false\n";
- if (!bf0app_update) headers += "wtv-visit: "+gourl+"\n";
- if (!bf0app_update) headers += "wtv-client-time-zone: GMT -0000\n";
- if (!bf0app_update) headers += "wtv-client-time-dst-rule: GMT\n"
- if (!bf0app_update) headers += "wtv-client-date: " + strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString())) + " GMT";
+ headers += "wtv-client-time-zone: GMT -0000\n";
+ headers += "wtv-client-time-dst-rule: GMT\n"
+ headers += "wtv-client-date: " + strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString())) + " GMT";
if (file_path) {
request_is_async = true;
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/current-noflash.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/current-noflash.js
new file mode 100644
index 00000000..3afc0834
--- /dev/null
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/current-noflash.js
@@ -0,0 +1,114 @@
+// this build can be local or on zefie's server
+// to get the path from zefie's server, browse
+// https://archive.midnightchannel.net/zefie/files/wtv-flashrom/content/artemis-webtv-000/
+// and put everything from 'content/' onwards, including the part000.rom filename
+// example is below
+var default_build_to_send = minisrv_config.services[service_name].bf0app_default_rom || "content/artemis-webtv-000/build7181/daily-nondebug/bf0app-part000.rom";
+
+headers = "200 OK\n";
+var request_path = "";
+var bf0app_update = true;
+if (request_headers.query.path) request_path = unescape(request_headers.query.path);
+else request_path = default_build_to_send;
+request_is_async = true;
+
+if (ssid_sessions[socket.ssid].get("wtv-client-rom-type") == "bf0app" && ssid_sessions[socket.ssid].get("wtv-client-bootrom-version") == "105") {
+ // assume old classic in flash mode, override user setting and send tellyscript
+ // because it is required to proceed in flash mode
+ bf0app_update = true;
+ ssid_sessions[socket.ssid].set("bf0app_update", bf0app_update);
+ headers += "minisrv-use-carriage-return: false\n";
+}
+
+function doLocalFlashROM(flashrom_file_path) {
+ // use local flashrom files;
+ try {
+ fs.readFile(flashrom_file_path, null, function (err, data) {
+ if (err) {
+ errpage = doErrorPage(400)
+ headers = errpage[0];
+ data = err.toString();
+ }
+ sendToClient(socket, headers, data);
+ });
+ } catch (e) {
+ var errpage = doErrorPage(404, "The service could not find the requested ROM.")
+ headers = errpage[0];
+ data = errpage[1];
+ sendToClient(socket, headers, data);
+ }
+}
+
+function calculatedPath(data, path, numparts = null) {
+ var data_128 = new Buffer.alloc(128);
+ data.copy(data_128, 0, 0, 128);
+ var flashrom_numparts = null;
+ var flashrom_message = new Buffer.from(data_128.toString('hex').substring(36 * 2, 68 * 2), 'hex').toString('ascii').replace(/[^0-9a-z\ \.\-]/gi, "");
+
+ if (numparts != null) flashrom_numparts = parseInt(numparts);
+ if (!flashrom_numparts) flashrom_numparts = flashrom_message.substring(flashrom_message.length - 4).replace(/\D/g, '');
+
+ var ind = new Array();
+ ind[0] = (path.indexOf("part") + 4);
+ ind[1] = (path.indexOf(".", ind[0]) + 1);
+ var flashrom_part_num = path.substr(ind[0], (path.length - ind[1]));
+ var flashrom_lastpart = (flashrom_numparts == (parseInt(flashrom_part_num) + 1)) ? true : false;
+ var flashrom_rompath = 'wtv-flashrom:/get-by-path?path=' + path;
+ if (flashrom_lastpart) {
+ flashrom_next_rompath = "wtv-flashrom:/lc2-download-complete?";
+ } else {
+ var flashrom_next_part_num = (parseInt(flashrom_part_num) + 1);
+ if (flashrom_next_part_num < 10) flashrom_next_part_num = "00" + flashrom_next_part_num; // 1s
+ else if (flashrom_next_part_num >= 10 && flashrom_next_part_num < 100) flashrom_next_part_num = "0" + flashrom_next_part_num; // 10s
+ var flashrom_next_rompath = flashrom_rompath.replace("part" + flashrom_part_num, "part" + flashrom_next_part_num) + "&numparts=" + parseInt(flashrom_numparts);
+ }
+ return flashrom_next_rompath;
+}
+
+if ((/\.brom$/).test(request_path)) headers += "Content-Type: binary/x-wtv-bootrom"; // maybe?
+else headers += "Content-Type: binary/x-wtv-flashblock";
+
+var flashrom_file_path = null;
+Object.keys(service_vaults).forEach(function (g) {
+ if (flashrom_file_path != null) return;
+ flashrom_file_path = service_vaults[g] + "/" + service_name + "/" + request_path;
+ if (!fs.existsSync(flashrom_file_path)) flashrom_file_path = null;
+});
+if (minisrv_config.services[service_name].use_zefie_server && !flashrom_file_path) {
+ // get flashrom files from archive.midnightchannel.net
+ var options = {
+ host: "archive.midnightchannel.net",
+ path: "/zefie/files/wtv-flashrom/" + request_path,
+ timeout: 5000,
+ method: 'GET'
+ }
+ const req = https.request(options, function (res) {
+ var data_hex = '';
+ res.setEncoding('hex');
+
+ res.on('data', d => {
+ data_hex += d;
+ })
+
+ res.on('end', function () {
+ if (!zquiet) console.log(` * Zefie's FlashROM Server HTTP Status: ${res.statusCode} ${res.statusMessage}`)
+ if (res.statusCode == 200) {
+ data = Buffer.from(data_hex, 'hex');
+ } else if (res.statusCode == 404) {
+ var errpage = doErrorPage(404, "The service could not find the requested ROM on zefie's server.")
+ headers = errpage[0];
+ data = errpage[1];
+ } else {
+ var errpage = doErrorPage(400)
+ headers = errpage[0];
+ data = errpage[1];
+ }
+ headers += "\nwtv-visit: " + calculatedPath(data, request_path);
+ sendToClient(socket, headers, data);
+ });
+ });
+ req.end();
+} else {
+ doLocalFlashROM(flashrom_file_path);
+}
+
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 004221d5..00c88d30 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js
@@ -1,5 +1,7 @@
request_is_async = true;
+
+var bf0app_update = false;
var request_path = unescape(request_headers.query.path);
headers = "200 OK\n"
@@ -22,11 +24,44 @@ function doLocalFlashROM(flashrom_file_path) {
}
}
-var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
+if (ssid_sessions[socket.ssid].get("wtv-client-rom-type") == "bf0app" && ssid_sessions[socket.ssid].get("wtv-client-bootrom-version") == "105") {
+ // assume old classic in flash mode, override user setting and send tellyscript
+ // because it is required to proceed in flash mode
+ bf0app_update = true;
+ ssid_sessions[socket.ssid].set("bf0app_update", bf0app_update);
+ headers += "minisrv-use-carriage-return: false\n";
+}
-if (request_headers.query.raw || romtype == "bf0app") {
+
+function calculatedPath(data, path, numparts = null) {
+ var data_128 = new Buffer.alloc(128);
+ data.copy(data_128, 0, 0, 128);
+ var flashrom_numparts = null;
+ var flashrom_message = new Buffer.from(data_128.toString('hex').substring(36 * 2, 68 * 2), 'hex').toString('ascii').replace(/[^0-9a-z\ \.\-]/gi, "");
+
+ if (numparts != null) flashrom_numparts = parseInt(numparts);
+ if (!flashrom_numparts) flashrom_numparts = flashrom_message.substring(flashrom_message.length - 4).replace(/\D/g, '');
+
+ var ind = new Array();
+ ind[0] = (path.indexOf("part") + 4);
+ ind[1] = (path.indexOf(".", ind[0]) + 1);
+ var flashrom_part_num = path.substr(ind[0], (path.length - ind[1]));
+ var flashrom_lastpart = (flashrom_numparts == (parseInt(flashrom_part_num) + 1)) ? true : false;
+ var flashrom_rompath = 'wtv-flashrom:/get-by-path?path=' + path;
+ if (flashrom_lastpart) flashrom_next_rompath = null;
+ else {
+ var flashrom_next_part_num = (parseInt(flashrom_part_num) + 1);
+ if (flashrom_next_part_num < 10) flashrom_next_part_num = "00" + flashrom_next_part_num; // 1s
+ else if (flashrom_next_part_num >= 10 && flashrom_next_part_num < 100) flashrom_next_part_num = "0" + flashrom_next_part_num; // 10s
+ var flashrom_next_rompath = flashrom_rompath.replace("part" + flashrom_part_num, "part" + flashrom_next_part_num) + "&numparts=" + parseInt(flashrom_numparts);
+ }
+ return flashrom_next_rompath;
+}
+
+if (request_headers.query.raw || bf0app_update) {
if ((/\.brom$/).test(request_path)) headers += "Content-Type: binary/x-wtv-bootrom"; // maybe?
else headers += "Content-Type: binary/x-wtv-flashblock";
+
var flashrom_file_path = null;
Object.keys(service_vaults).forEach(function (g) {
if (flashrom_file_path != null) return;
@@ -62,6 +97,11 @@ if (request_headers.query.raw || romtype == "bf0app") {
headers = errpage[0];
data = errpage[1];
}
+ if (bf0app_update) {
+ var nextpath = calculatedPath(data, request_path, (request_headers.query.numparts || null));
+ if (nextpath != null) headers += "\nwtv-visit: " + nextpath;
+ }
+ else headers += "\nwtv-connection-close: true";
sendToClient(socket, headers, data);
});
});
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 63e2d198..2338c10f 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js
@@ -89,7 +89,8 @@ if (!request_headers.query.path) {
}
async function processLC2DownloadPage(path, flashrom_message, numparts = null) {
- if (numparts != null) var flashrom_numparts = parseInt(numparts);
+ var flashrom_numparts = null;
+ if (numparts != null) flashrom_numparts = parseInt(numparts);
if (!flashrom_numparts) flashrom_numparts = flashrom_message.substring(flashrom_message.length - 4).replace(/\D/g, '');
var ind = new Array();
ind[0] = (path.indexOf("part") + 4);
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 8ba45429..b22756f3 100644
--- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js
@@ -1,9 +1,10 @@
if (request_headers.query.path) {
var url = "wtv-flashrom:/get-lc2-page?path=" + request_headers.query.path;
var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
-if (romtype == "bf0app") {
- url = "client:updateflash?ipaddr="+minisrv_config.services[service_name].host+"&port="+minisrv_config.services[service_name].port+"&path=" + request_headers.query.path;
-}
+ if (romtype == "bf0app") {
+ url = "client:updateflash?ipaddr=" + minisrv_config.services[service_name].host + "&port=" + minisrv_config.services[service_name].port + "&path=" + escape(url.replace("get-lc2-page", "get-by-path"));
+ if (request_headers.query.numparts) url += escape("&numparts=" + request_headers.query.numparts);
+ }
headers = "300 OK\n";
headers += "wtv-visit: " + url + "\n";
headers += "Location: " + url + "\n";
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/noflash.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/noflash.js
new file mode 100644
index 00000000..3afc0834
--- /dev/null
+++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/noflash.js
@@ -0,0 +1,114 @@
+// this build can be local or on zefie's server
+// to get the path from zefie's server, browse
+// https://archive.midnightchannel.net/zefie/files/wtv-flashrom/content/artemis-webtv-000/
+// and put everything from 'content/' onwards, including the part000.rom filename
+// example is below
+var default_build_to_send = minisrv_config.services[service_name].bf0app_default_rom || "content/artemis-webtv-000/build7181/daily-nondebug/bf0app-part000.rom";
+
+headers = "200 OK\n";
+var request_path = "";
+var bf0app_update = true;
+if (request_headers.query.path) request_path = unescape(request_headers.query.path);
+else request_path = default_build_to_send;
+request_is_async = true;
+
+if (ssid_sessions[socket.ssid].get("wtv-client-rom-type") == "bf0app" && ssid_sessions[socket.ssid].get("wtv-client-bootrom-version") == "105") {
+ // assume old classic in flash mode, override user setting and send tellyscript
+ // because it is required to proceed in flash mode
+ bf0app_update = true;
+ ssid_sessions[socket.ssid].set("bf0app_update", bf0app_update);
+ headers += "minisrv-use-carriage-return: false\n";
+}
+
+function doLocalFlashROM(flashrom_file_path) {
+ // use local flashrom files;
+ try {
+ fs.readFile(flashrom_file_path, null, function (err, data) {
+ if (err) {
+ errpage = doErrorPage(400)
+ headers = errpage[0];
+ data = err.toString();
+ }
+ sendToClient(socket, headers, data);
+ });
+ } catch (e) {
+ var errpage = doErrorPage(404, "The service could not find the requested ROM.")
+ headers = errpage[0];
+ data = errpage[1];
+ sendToClient(socket, headers, data);
+ }
+}
+
+function calculatedPath(data, path, numparts = null) {
+ var data_128 = new Buffer.alloc(128);
+ data.copy(data_128, 0, 0, 128);
+ var flashrom_numparts = null;
+ var flashrom_message = new Buffer.from(data_128.toString('hex').substring(36 * 2, 68 * 2), 'hex').toString('ascii').replace(/[^0-9a-z\ \.\-]/gi, "");
+
+ if (numparts != null) flashrom_numparts = parseInt(numparts);
+ if (!flashrom_numparts) flashrom_numparts = flashrom_message.substring(flashrom_message.length - 4).replace(/\D/g, '');
+
+ var ind = new Array();
+ ind[0] = (path.indexOf("part") + 4);
+ ind[1] = (path.indexOf(".", ind[0]) + 1);
+ var flashrom_part_num = path.substr(ind[0], (path.length - ind[1]));
+ var flashrom_lastpart = (flashrom_numparts == (parseInt(flashrom_part_num) + 1)) ? true : false;
+ var flashrom_rompath = 'wtv-flashrom:/get-by-path?path=' + path;
+ if (flashrom_lastpart) {
+ flashrom_next_rompath = "wtv-flashrom:/lc2-download-complete?";
+ } else {
+ var flashrom_next_part_num = (parseInt(flashrom_part_num) + 1);
+ if (flashrom_next_part_num < 10) flashrom_next_part_num = "00" + flashrom_next_part_num; // 1s
+ else if (flashrom_next_part_num >= 10 && flashrom_next_part_num < 100) flashrom_next_part_num = "0" + flashrom_next_part_num; // 10s
+ var flashrom_next_rompath = flashrom_rompath.replace("part" + flashrom_part_num, "part" + flashrom_next_part_num) + "&numparts=" + parseInt(flashrom_numparts);
+ }
+ return flashrom_next_rompath;
+}
+
+if ((/\.brom$/).test(request_path)) headers += "Content-Type: binary/x-wtv-bootrom"; // maybe?
+else headers += "Content-Type: binary/x-wtv-flashblock";
+
+var flashrom_file_path = null;
+Object.keys(service_vaults).forEach(function (g) {
+ if (flashrom_file_path != null) return;
+ flashrom_file_path = service_vaults[g] + "/" + service_name + "/" + request_path;
+ if (!fs.existsSync(flashrom_file_path)) flashrom_file_path = null;
+});
+if (minisrv_config.services[service_name].use_zefie_server && !flashrom_file_path) {
+ // get flashrom files from archive.midnightchannel.net
+ var options = {
+ host: "archive.midnightchannel.net",
+ path: "/zefie/files/wtv-flashrom/" + request_path,
+ timeout: 5000,
+ method: 'GET'
+ }
+ const req = https.request(options, function (res) {
+ var data_hex = '';
+ res.setEncoding('hex');
+
+ res.on('data', d => {
+ data_hex += d;
+ })
+
+ res.on('end', function () {
+ if (!zquiet) console.log(` * Zefie's FlashROM Server HTTP Status: ${res.statusCode} ${res.statusMessage}`)
+ if (res.statusCode == 200) {
+ data = Buffer.from(data_hex, 'hex');
+ } else if (res.statusCode == 404) {
+ var errpage = doErrorPage(404, "The service could not find the requested ROM on zefie's server.")
+ headers = errpage[0];
+ data = errpage[1];
+ } else {
+ var errpage = doErrorPage(400)
+ headers = errpage[0];
+ data = errpage[1];
+ }
+ headers += "\nwtv-visit: " + calculatedPath(data, request_path);
+ sendToClient(socket, headers, data);
+ });
+ });
+ req.end();
+} else {
+ doLocalFlashROM(flashrom_file_path);
+}
+
diff --git a/zefie_wtvp_minisrv/app.js b/zefie_wtvp_minisrv/app.js
index e3691b90..4761b422 100644
--- a/zefie_wtvp_minisrv/app.js
+++ b/zefie_wtvp_minisrv/app.js
@@ -31,19 +31,19 @@ if (!String.prototype.reverse) {
}
}
-function getServiceString(service) {
+function getServiceString(service, overrides = null) {
// used externally by service scripts
if (service === "all") {
var out = "";
Object.keys(minisrv_config.services).forEach(function (k) {
- out += minisrv_config.services[k].toString() + "\n";
+ out += minisrv_config.services[k].toString(overrides) + "\n";
});
return out;
} else {
if (!minisrv_config.services[service]) {
throw ("SERVICE ERROR: Attempted to provision unconfigured service: " + service)
} else {
- return minisrv_config.services[service].toString();
+ return minisrv_config.services[service].toString(overrides);
}
}
}
@@ -469,9 +469,9 @@ async function sendToClient(socket, headers_obj, data) {
// calculate content length
if (typeof data.length !== 'undefined') {
- headers_obj["Content-Length"] = data.length;
+ headers_obj["Content-length"] = data.length;
} else if (typeof data.byteLength !== 'undefined') {
- headers_obj["Content-Length"] = data.byteLength;
+ headers_obj["Content-length"] = data.byteLength;
}
if (ssid_sessions[socket.ssid]) {
@@ -486,17 +486,23 @@ async function sendToClient(socket, headers_obj, data) {
}
}
+ var end_of_line = "\n";
+ if (!headers_obj['minisrv-use-carriage-return'] || headers_obj['minisrv-use-carriage-return'] != "false") end_of_line = "\r\n";
+ if (headers_obj['minisrv-use-carriage-return']) delete headers_obj['minisrv-use-carriage-return'];
+
+ if (end_of_line == "\n" && zdebug) console.log(" * Script requested to send headers without carriage return (bf0app hack)");
+
// header object to string
if (zshowheaders) console.log(" * Outgoing headers on socket ID", socket.id, (await filterSSID(headers_obj)));
Object.keys(headers_obj).forEach(function (k) {
if (k == "http_response") {
- headers += headers_obj[k] + "\r\n";
+ headers += headers_obj[k] + end_of_line;
} else {
if (k.indexOf('_') >= 0) {
var j = k.split('_')[0];
- headers += j + ": " + headers_obj[k] + "\r\n";
+ headers += j + ": " + headers_obj[k] + end_of_line;
} else {
- headers += k + ": " + headers_obj[k] + "\r\n";
+ headers += k + ": " + headers_obj[k] + end_of_line;
}
}
});
@@ -505,17 +511,17 @@ async function sendToClient(socket, headers_obj, data) {
// send to client
var toClient = null;
if (typeof data == 'string') {
- toClient = headers + "\r\n" + data;
+ toClient = headers + end_of_line + data;
socket.write(toClient);
} else if (typeof data == 'object') {
if (zquiet) 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";
- var enc_headers = socket_sessions[socket.id].wtvsec.Encrypt(1, headers + "\r\n");
+ var enc_headers = socket_sessions[socket.id].wtvsec.Encrypt(1, headers + end_of_line);
socket.write(new Uint8Array(concatArrayBuffer(enc_headers, data)));
} else {
- socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + "\r\n"), data)));
+ socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + end_of_line), data)));
}
if (zquiet) console.log(" * Sent" + verbosity_mod + " " + headers_obj.http_response + " to client (Content-Type:", headers_obj['Content-Type'], "~", headers_obj['Content-Length'], "bytes)");
}
@@ -1217,15 +1223,26 @@ Object.keys(minisrv_config.services).forEach(function (k) {
if (minisrv_config.services[k].port && !minisrv_config.services[k].nobind) {
ports.push(minisrv_config.services[k].port);
}
-
- minisrv_config.services[k].toString = function () {
- var outstr = "wtv-service: name=" + this.name + " host=" + this.host + " port=" + this.port;
- if (this.flags) outstr += " flags=" + this.flags;
- if (this.connections) outstr += " connections=" + this.connections;
+ // minisrv_config service toString
+ minisrv_config.services[k].toString = function (overrides) {
+ var self = this;
+ if (overrides != null) {
+ if (typeof (overrides) == 'object') {
+ Object.keys(overrides).forEach(function (k) {
+ self[k] = overrides[k];
+ });
+ }
+ }
+ if ((k == "wtv-star" && self.no_star_word != true) || k != "wtv-star") {
+ var outstr = "wtv-service: name=" + self.name + " host=" + self.host + " port=" + self.port;
+ if (self.flags) outstr += " flags=" + self.flags;
+ if (self.connections) outstr += " connections=" + self.connections;
+ }
if (k == "wtv-star") {
- outstr += "\nwtv-service: name=wtv-* host=" + this.host + " port=" + this.port;
- if (this.flags) outstr += " flags=" + this.flags;
- if (this.connections) outstr += " connections=" + this.connections;
+ outstr += "\nwtv-service: name=wtv-* host=" + self.host + " port=" + self.port;
+ if (self.flags) outstr += " flags=" + self.flags;
+ if (self.connections) outstr += " connections=" + self.connections;
+ if (self['no_star_word']) delete self['no_star_word'];
}
return outstr;
}
diff --git a/zefie_wtvp_minisrv/config.json b/zefie_wtvp_minisrv/config.json
index 4c69fe7a..1fb88b65 100644
--- a/zefie_wtvp_minisrv/config.json
+++ b/zefie_wtvp_minisrv/config.json
@@ -47,7 +47,8 @@
"wtv-flashrom": {
"port": 1618,
"flags": "0x00000040",
- "use_zefie_server": true
+ "use_zefie_server": true,
+ "bf0app_default_rom": "content/artemis-webtv-000/build7181/daily-nondebug/bf0app-part000.rom"
},
"wtv-music": {
"port": 1656,
@@ -68,7 +69,8 @@
"use_external_proxy": false,
"external_proxy_is_socks": false,
"external_proxy_host": "127.0.0.1",
- "external_proxy_port": 1080
+ "external_proxy_port": 1080,
+ "flags": "0x00000001"
},
"https": {
"port": 1650,
@@ -76,7 +78,8 @@
"use_external_proxy": false,
"external_proxy_is_socks": false,
"external_proxy_host": "127.0.0.1",
- "external_proxy_port": 1080
+ "external_proxy_port": 1080,
+ "flags": "0x00000001"
}
}
}
diff --git a/zefie_wtvp_minisrv/package.json b/zefie_wtvp_minisrv/package.json
index 2feae443..7ee6b090 100644
--- a/zefie_wtvp_minisrv/package.json
+++ b/zefie_wtvp_minisrv/package.json
@@ -1,6 +1,6 @@
{
"name": "zefie_wtvp_minisrv",
- "version": "0.9.8",
+ "version": "0.9.9",
"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 b40cd310..6b73bcde 100644
--- a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj
+++ b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj
@@ -32,12 +32,17 @@
+
+
+
+ Code
+
Code
@@ -47,6 +52,7 @@
+