v0.9.21
- numerous bug fixes - add UTV tellyscripts - BREAKING CHANGE: doErrorPage moved to wtvshared.doErrorPage - but I fixed flashrom error handling.. - added a passthrough for old scripts - added eMac's lzpf compression - Bump vm2 from 3.9.3 to 3.9.5 in /zefie_wtvp_minisrv
This commit is contained in:
12
README.md
12
README.md
@@ -1,7 +1,7 @@
|
|||||||
# wtv minisrv node.js
|
# wtv minisrv node.js
|
||||||
|
|
||||||
The ***wtv minisrv***, or "***zefie_wtvp_minisrv***" project is a node.js project that provides a mini WebTV Server, aiming for full WTVP (WebTV Protocol) support.
|
The ***wtv minisrv***, or "***zefie_wtvp_minisrv***" project is a node.js project that provides a mini WebTV Server, aiming for full WTVP (WebTV Protocol) support.
|
||||||
This open source server is in alpha status. Use at your own risk.
|
This open source server is in beta status. Use at your own risk.
|
||||||
|
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||||
|
|
||||||
@@ -14,22 +14,20 @@ This open source server is in alpha status. Use at your own risk.
|
|||||||
- WebTV cookie support (wtv-cookie) for HTTP(s)
|
- WebTV cookie support (wtv-cookie) for HTTP(s)
|
||||||
- Flashrom flashing support for all known units (including bf0app 'Old Classic')
|
- 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.
|
- 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-disk:/sync` for Download-o-Rama style file downloading
|
||||||
- Custom Tellyscripts *(not yet customizable though)*
|
- Custom Tellyscripts *(not yet customizable though)*
|
||||||
- Flat file client session store and registration system
|
- Flat file client session store and registration system
|
||||||
|
- wtv-lzpf compression support by eMac (99.9%)
|
||||||
|
|
||||||
### Current issues:
|
### Current issues:
|
||||||
- wtv-cookie implementation is still partial
|
- Mis-configuring wtv-disk:/sync DiskMaps may cause units to delete contents of partitions (need more info)
|
||||||
- wtv-lzpf compression support is not yet reliable
|
|
||||||
- Mis-configuring wtv-update:/sync DiskMaps may cause units to delete contents of partitions (need more info)
|
|
||||||
- Satellite Receiver units reportedly cannot surf with http or https proxy. *(May be fixed by current partial wtv-cookie implementation)*
|
|
||||||
|
|
||||||
### Won't fix:
|
### Won't fix:
|
||||||
- wtv-encryption stream breaks when two different sessions have the same SSID (eg spoofing, won't fix (production did it too))
|
- wtv-encryption stream breaks when two different sessions have the same SSID (eg spoofing, won't fix (production did it too))
|
||||||
- ~~No intentions to support user accounts, registration, or any form of database system~~ *(I guess this was a lie, but we still don't use a database!)*
|
- ~~No intentions to support user accounts, registration, or any form of database system~~ *(I guess this was a lie, but we still don't use a database!)*
|
||||||
|
|
||||||
### Feature Todo:
|
### Feature Todo:
|
||||||
- wtv-lzpf support *(Milestone v1.0)*
|
- wtv-setup and bgm support
|
||||||
- TellyScript generation and/or manipulation without external dependancies
|
- TellyScript generation and/or manipulation without external dependancies
|
||||||
- ~~wtv-cookie full support~~ ***Done [v0.9.13](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.9.13)***
|
- ~~wtv-cookie full support~~ ***Done [v0.9.13](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.9.13)***
|
||||||
- ~~Flashrom flashing for bf0app old classic~~ ***Done [v0.9.9](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.9.9)***
|
- ~~Flashrom flashing for bf0app old classic~~ ***Done [v0.9.9](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.9.9)***
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (request_headers.query.url) {
|
if (request_headers.query.url) {
|
||||||
if (request_headers.query.url.indexOf(":/") > 0) {
|
if (request_headers.query.url.indexOf(":/") > 0) {
|
||||||
var service_request = request_headers.query.url.split(":/")[0];
|
var service_request = request_headers.query.url.split(":/")[0];
|
||||||
@@ -31,7 +33,7 @@ if (request_headers.query.url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!headers) {
|
if (!headers) {
|
||||||
var errpage = doErrorPage(500)
|
var errpage = wtvshared.doErrorPage(500)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Content-Type: text/html`
|
Content-Type: text/html`
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (socket.ssid != null && !ssid_sessions[socket.ssid].get("wtvsec_login")) {
|
if (socket.ssid != null && !ssid_sessions[socket.ssid].get("wtvsec_login")) {
|
||||||
var wtvsec_login = new WTVSec(minisrv_config);
|
var wtvsec_login = new WTVSec(minisrv_config);
|
||||||
wtvsec_login.IssueChallenge();
|
wtvsec_login.IssueChallenge();
|
||||||
wtvsec_login.set_incarnation(request_headers["wtv-incarnation"]);
|
if (request_headers["wtv-incarnation"]) wtvsec_login.set_incarnation(request_headers["wtv-incarnation"]);
|
||||||
ssid_sessions[socket.ssid].set("wtvsec_login", wtvsec_login);
|
ssid_sessions[socket.ssid].set("wtvsec_login", wtvsec_login);
|
||||||
} else if (socket.ssid != null) {
|
} else if (socket.ssid != null) {
|
||||||
var wtvsec_login = ssid_sessions[socket.ssid].get("wtvsec_login");
|
var wtvsec_login = ssid_sessions[socket.ssid].get("wtvsec_login");
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
var gourl = "wtv-1800:/finish-prereg?";
|
var gourl = "wtv-1800:/finish-prereg?";
|
||||||
if (request_headers.query.relogin) gourl += "relogin=true";
|
if (request_headers.query.relogin) gourl += "relogin=true";
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
var gourl = "wtv-head-waiter:/login?";
|
var gourl = "wtv-head-waiter:/login?";
|
||||||
|
|
||||||
if (socket.ssid) {
|
if (socket.ssid) {
|
||||||
@@ -30,10 +32,10 @@
|
|||||||
|
|
||||||
ssid_sessions[socket.ssid].data_store.wtvsec_login = new WTVSec(minisrv_config);
|
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.IssueChallenge();
|
||||||
ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(request_headers["wtv-incarnation"] || 1);
|
if (request_headers["wtv-incarnation"]) ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(request_headers["wtv-incarnation"]);
|
||||||
} else {
|
} else {
|
||||||
console.log(" * Something bad happened (we don't know the client ssid???)");
|
console.log(" * Something bad happened (we don't know the client ssid???)");
|
||||||
var errpage = doErrorPage(400)
|
var errpage = wtvshared.doErrorPage(400)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -66,7 +68,7 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
|||||||
} else {
|
} else {
|
||||||
romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
|
romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
|
||||||
}
|
}
|
||||||
|
var file_path = null;
|
||||||
switch (romtype) {
|
switch (romtype) {
|
||||||
case "US-LC2-disk-0MB-8MB":
|
case "US-LC2-disk-0MB-8MB":
|
||||||
case "US-LC2-disk-0MB-8MB-softmodem-CPU5230":
|
case "US-LC2-disk-0MB-8MB-softmodem-CPU5230":
|
||||||
@@ -75,15 +77,30 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
|||||||
case "US-WEBSTAR-disk-0MB-16MB-softmodem-CPU5230":
|
case "US-WEBSTAR-disk-0MB-16MB-softmodem-CPU5230":
|
||||||
prereg_contype = "text/tellyscript";
|
prereg_contype = "text/tellyscript";
|
||||||
// if wtv-open-access: true then client expects OpenISP
|
// if wtv-open-access: true then client expects OpenISP
|
||||||
if (ssid_sessions[socket.ssid].get("wtv-open-access")) var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/LC2/LC2_OpenISP_56k.tok";
|
if (ssid_sessions[socket.ssid].get("wtv-open-access")) file_path = __dirname + "/ServiceDeps/premade_tellyscripts/LC2/LC2_OpenISP_56k.tok";
|
||||||
else var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/LC2/LC2_WTV_18006138199.tok";
|
else var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/LC2/LC2_WTV_18006138199.tok";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "US-DTV-disk-0MB-32MB-softmodem-CPU5230":
|
||||||
|
if (wtvshared.isMiniBrowser()) {
|
||||||
|
prereg_contype = "text/tellyscript";
|
||||||
|
if (ssid_sessions[socket.ssid].get("wtv-open-access")) file_path = __dirname + "/ServiceDeps/premade_tellyscripts/LC2/LC2_OpenISP_56k.tok";
|
||||||
|
else file_path = __dirname + "/ServiceDeps/premade_tellyscripts/LC2/LC2_WTV_18006138199.tok";
|
||||||
|
} else {
|
||||||
|
prereg_contype = "text/dialscript";
|
||||||
|
if (ssid_sessions[socket.ssid].get("wtv-lan") == "true") {
|
||||||
|
file_path = __dirname + "/ServiceDeps/premade_tellyscripts/UTV/utv_hsd.tok";
|
||||||
|
} else {
|
||||||
|
// todo OpenISP telly
|
||||||
|
file_path = __dirname + "/ServiceDeps/premade_tellyscripts/UTV/utv_normal.tok";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case "bf0app":
|
case "bf0app":
|
||||||
prereg_contype = "text/tellyscript";
|
prereg_contype = "text/tellyscript";
|
||||||
// if wtv-open-access: true then client expects OpenISP
|
// if wtv-open-access: true then client expects OpenISP
|
||||||
if (ssid_sessions[socket.ssid].get("wtv-open-access")) var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/bf0app/bf0app_OISP.tok";
|
if (ssid_sessions[socket.ssid].get("wtv-open-access")) file_path = __dirname + "/ServiceDeps/premade_tellyscripts/bf0app/bf0app_OISP.tok";
|
||||||
else var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/bf0app/bf0app_WTV_18006138199.tok";
|
else file_path = __dirname + "/ServiceDeps/premade_tellyscripts/bf0app/bf0app_WTV_18006138199.tok";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// the following are not yet zefie generated and may have an unknown username/password attached
|
// the following are not yet zefie generated and may have an unknown username/password attached
|
||||||
@@ -99,6 +116,11 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
|||||||
data = '';
|
data = '';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (socket.ssid.substr(0, 8) == "MSTVSIMU") {
|
||||||
|
prereg_contype = "text/dialscript";
|
||||||
|
var file_path = __dirname + "/ServiceDeps/premade_tellyscripts/UTV/utv_hsd.tok";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -157,7 +179,7 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
|||||||
request_is_async = true;
|
request_is_async = true;
|
||||||
fs.readFile(file_path, null, function (err, file_read_data) {
|
fs.readFile(file_path, null, function (err, file_read_data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
var errmsg = doErrorPage(400);
|
var errmsg = wtvshared.doErrorPage(400);
|
||||||
headers = errmsg[0];
|
headers = errmsg[0];
|
||||||
file_read_data = errmsg[1] + "\n" + err.toString();
|
file_read_data = errmsg[1] + "\n" + err.toString();
|
||||||
}
|
}
|
||||||
@@ -165,7 +187,7 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = "200 OK";
|
headers = "200 OK";
|
||||||
if (request_headers.query.nick) headers += "\n" + ssid_sessions[socket.ssid].setIRCNick(request_headers.query.nick);
|
if (request_headers.query.nick) headers += "\n" + ssid_sessions[socket.ssid].setIRCNick(request_headers.query.nick);
|
||||||
headers += "\nContent-Type: text/html";
|
headers += "\nContent-Type: text/html";
|
||||||
@@ -148,7 +150,7 @@ ${request_headers.query.channel}
|
|||||||
</body>
|
</body>
|
||||||
</html>`;
|
</html>`;
|
||||||
} else {
|
} else {
|
||||||
var errpage = doErrorPage("400 Chat requires host, port and channel arguments. Do not use the # on channels.");
|
var errpage = wtvshared.doErrorPage("400 Chat requires host, port and channel arguments. Do not use the # on channels.");
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
var irc_nick = "";
|
var irc_nick = "";
|
||||||
headers = "200 OK";
|
headers = "200 OK";
|
||||||
if (request_headers.query.nick) headers += "\n" + ssid_sessions[socket.ssid].setIRCNick(request_headers.query.nick);
|
if (request_headers.query.nick) headers += "\n" + ssid_sessions[socket.ssid].setIRCNick(request_headers.query.nick);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (socket.ssid) {
|
if (socket.ssid) {
|
||||||
if (request_headers.post_data) {
|
if (request_headers.post_data) {
|
||||||
if (ssid_sessions[socket.ssid]) {
|
if (ssid_sessions[socket.ssid]) {
|
||||||
@@ -9,7 +11,7 @@ if (socket.ssid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!headers) {
|
if (!headers) {
|
||||||
var errpage = doErrorPage(400)
|
var errpage = wtvshared.doErrorPage(400)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (request_headers.post_data) {
|
if (request_headers.post_data) {
|
||||||
if (request_headers.query.domain && request_headers.query.path) {
|
if (request_headers.query.domain && request_headers.query.path) {
|
||||||
if (socket.ssid) {
|
if (socket.ssid) {
|
||||||
@@ -11,7 +13,7 @@ if (request_headers.post_data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!headers) {
|
if (!headers) {
|
||||||
var errpage = doErrorPage(400)
|
var errpage = wtvshared.doErrorPage(400)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (socket.ssid) {
|
if (socket.ssid) {
|
||||||
if (ssid_sessions[socket.ssid]) {
|
if (ssid_sessions[socket.ssid]) {
|
||||||
|
|
||||||
@@ -8,7 +10,7 @@ if (socket.ssid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!headers) {
|
if (!headers) {
|
||||||
var errpage = doErrorPage(400)
|
var errpage = wtvshared.doErrorPage(400)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (socket.ssid) {
|
if (socket.ssid) {
|
||||||
if (ssid_sessions[socket.ssid]) {
|
if (ssid_sessions[socket.ssid]) {
|
||||||
ssid_sessions[socket.ssid].resetCookies();
|
ssid_sessions[socket.ssid].resetCookies();
|
||||||
@@ -19,7 +21,7 @@ Redirecting shortly... <a href="client:goback">Go Back</a>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!headers) {
|
if (!headers) {
|
||||||
var errpage = doErrorPage(400)
|
var errpage = wtvshared.doErrorPage(400)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (request_headers.query.group) {
|
if (request_headers.query.group) {
|
||||||
const WTVDownloadList = require("./WTVDownloadList.js");
|
const WTVDownloadList = require("./WTVDownloadList.js");
|
||||||
var wtvdl = new WTVDownloadList(minisrv_config, service_name);
|
var wtvdl = new WTVDownloadList(minisrv_config, service_name);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
const WTVDownloadList = require("./WTVDownloadList.js");
|
const WTVDownloadList = require("./WTVDownloadList.js");
|
||||||
var wtvdl = new WTVDownloadList(minisrv_config, service_name);
|
var wtvdl = new WTVDownloadList(minisrv_config, service_name);
|
||||||
|
|
||||||
@@ -212,9 +214,7 @@ if (request_headers['wtv-request-type'] == 'download') {
|
|||||||
Object.keys(service_vaults).forEach(function (g) {
|
Object.keys(service_vaults).forEach(function (g) {
|
||||||
if (diskmap_data_file != null) return;
|
if (diskmap_data_file != null) return;
|
||||||
diskmap_data_file = service_vaults[g] + "/" + service_name + "/" + diskmap_group_data.files[k].location;
|
diskmap_data_file = service_vaults[g] + "/" + service_name + "/" + diskmap_group_data.files[k].location;
|
||||||
if (!fs.existsSync(diskmap_data_file)) {
|
if (!fs.existsSync(diskmap_data_file)) diskmap_data_file = null;
|
||||||
console.error("Could not find a file for", diskmap_group_data.files[k].location, "(Last tried SV:", diskmap_data_file, ")");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var diskmap_file_stat = fs.lstatSync(diskmap_data_file);
|
var diskmap_file_stat = fs.lstatSync(diskmap_data_file);
|
||||||
@@ -298,20 +298,20 @@ if (request_headers['wtv-request-type'] == 'download') {
|
|||||||
|
|
||||||
headers = "200 OK\nContent-Type: wtv/download-list";
|
headers = "200 OK\nContent-Type: wtv/download-list";
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
console.error(" # " + service_name+":/sync error", e);
|
console.error(" # " + service_name+":/sync error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var errpage = doErrorPage(404, "The requested DiskMap does not exist.");
|
var errpage = wtvshared.doErrorPage(404, "The requested DiskMap does not exist.");
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
if (minisrv_config.config.debug_flags.debug) 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 {
|
} else {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
if (minisrv_config.config.debug_flags.debug) 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");
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (request_headers.post_data) {
|
if (request_headers.post_data) {
|
||||||
if (request_headers.query.partialPath || request_headers.query.path) {
|
if (request_headers.query.partialPath || request_headers.query.path) {
|
||||||
if (socket.ssid) {
|
if (socket.ssid) {
|
||||||
@@ -15,7 +17,7 @@ if (request_headers.post_data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!headers) {
|
if (!headers) {
|
||||||
var errpage = doErrorPage(400)
|
var errpage = wtvshared.doErrorPage(400)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
const WTVFlashrom = require("./WTVFlashrom.js");
|
const WTVFlashrom = require("./WTVFlashrom.js");
|
||||||
request_is_async = true;
|
request_is_async = true;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
const WTVFlashrom = require("./WTVFlashrom.js");
|
const WTVFlashrom = require("./WTVFlashrom.js");
|
||||||
request_is_async = true;
|
request_is_async = true;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
const WTVFlashrom = require("./WTVFlashrom.js");
|
const WTVFlashrom = require("./WTVFlashrom.js");
|
||||||
request_is_async = true;
|
request_is_async = true;
|
||||||
|
|
||||||
@@ -28,7 +30,7 @@ if (request_headers.query.raw || bf0app_update) {
|
|||||||
headers += "Content-type: text/html"
|
headers += "Content-type: text/html"
|
||||||
data = '';
|
data = '';
|
||||||
} else {
|
} else {
|
||||||
var errpage = doErrorPage(404)
|
var errpage = wtvshared.doErrorPage(404)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
const WTVFlashrom = require("./WTVFlashrom.js");
|
const WTVFlashrom = require("./WTVFlashrom.js");
|
||||||
var wtvflashrom;
|
var wtvflashrom;
|
||||||
request_is_async = true;
|
request_is_async = true;
|
||||||
|
|
||||||
if (!request_headers.query.path) {
|
if (!request_headers.query.path) {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
} else {
|
} else {
|
||||||
@@ -21,7 +22,7 @@ async function processLC2DownloadPage(path, flashrom_info, numparts = null) {
|
|||||||
if (numparts != null) flashrom_info.part_count = parseInt(numparts);
|
if (numparts != null) flashrom_info.part_count = parseInt(numparts);
|
||||||
if (!flashrom_info.part_count) flashrom_info.part_count = parseInt(flashrom_info.message.substring(flashrom_info.message.length - 4).replace(/\D/g, ''));
|
if (!flashrom_info.part_count) flashrom_info.part_count = parseInt(flashrom_info.message.substring(flashrom_info.message.length - 4).replace(/\D/g, ''));
|
||||||
if (!flashrom_info.part_number || !flashrom_info.is_last_part || !flashrom_info.rompath || !flashrom_info.next_rompath || !flashrom_info.is_bootrom) {
|
if (!flashrom_info.part_number || !flashrom_info.is_last_part || !flashrom_info.rompath || !flashrom_info.next_rompath || !flashrom_info.is_bootrom) {
|
||||||
if (!flashrom_info.is_last_part || request_headers.query.last_part) {
|
if (!flashrom_info.is_last_part) {
|
||||||
flashrom_info.next_rompath = request_headers.request_url.replace(escape(request_headers.query.path), escape(flashrom_info.next_rompath.replace(service_name+":/","")));
|
flashrom_info.next_rompath = request_headers.request_url.replace(escape(request_headers.query.path), escape(flashrom_info.next_rompath.replace(service_name+":/","")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,8 +93,7 @@ data += `
|
|||||||
<upgradeblock width=280 height=15
|
<upgradeblock width=280 height=15
|
||||||
nexturl="${flashrom_info.next_rompath}"
|
nexturl="${flashrom_info.next_rompath}"
|
||||||
errorurl="${service_name}:/lc2-download-failed?"
|
errorurl="${service_name}:/lc2-download-failed?"
|
||||||
`
|
blockurl="${flashrom_info.rompath}"`;
|
||||||
if (!flashrom_info.is_last_part) data += `blockurl = "${flashrom_info.rompath}"`;
|
|
||||||
|
|
||||||
data += `
|
data += `
|
||||||
lastblock="${flashrom_info.is_last_part}"
|
lastblock="${flashrom_info.is_last_part}"
|
||||||
@@ -144,7 +144,7 @@ ${flashrom_info.message}
|
|||||||
</body>
|
</body>
|
||||||
</html>`;
|
</html>`;
|
||||||
} else {
|
} else {
|
||||||
var errpage = doErrorPage(400)
|
var errpage = wtvshared.doErrorPage(400)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (request_headers.query.path) {
|
if (request_headers.query.path) {
|
||||||
var url = service_name + ":/get-lc2-page?path=" + request_headers.query.path;
|
var url = service_name + ":/get-lc2-page?path=" + request_headers.query.path;
|
||||||
var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
|
var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
|
||||||
if (romtype == "bf0app") {
|
if (romtype == "bf0app") {
|
||||||
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);
|
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);
|
if (request_headers.query.numparts) url += escape("?numparts=" + request_headers.query.numparts);
|
||||||
}
|
}
|
||||||
headers = "300 OK\n";
|
headers = "300 OK\n";
|
||||||
headers += "wtv-visit: " + url + "\n";
|
headers += "wtv-visit: " + url + "\n";
|
||||||
@@ -11,7 +13,7 @@ var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
|
|||||||
headers += "Content-type: text/html";
|
headers += "Content-type: text/html";
|
||||||
data = '';
|
data = '';
|
||||||
} else {
|
} else {
|
||||||
var errpage = doErrorPage(400)
|
var errpage = wtvshared.doErrorPage(400)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Connection: Close
|
Connection: Close
|
||||||
wtv-connection-close: true
|
wtv-connection-close: true
|
||||||
@@ -43,6 +45,7 @@ Updating complete
|
|||||||
<img src="${service_name}:/ROMCache/S40H1.gif" width=560 height=6>
|
<img src="${service_name}:/ROMCache/S40H1.gif" width=560 height=6>
|
||||||
<tr>
|
<tr>
|
||||||
<td width=104 height=10 valign=top align=left>
|
<td width=104 height=10 valign=top align=left>
|
||||||
|
|
||||||
<td width=20 valign=top align=left>
|
<td width=20 valign=top align=left>
|
||||||
<td width=67 valign=top align=left>
|
<td width=67 valign=top align=left>
|
||||||
<td width=20 valign=top align=left>
|
<td width=20 valign=top align=left>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
var error = '';
|
var error = '';
|
||||||
if (request_headers.query.error) {
|
if (request_headers.query.error) {
|
||||||
switch (request_headers.query.error) {
|
switch (request_headers.query.error) {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
const WTVFlashrom = require("./WTVFlashrom.js");
|
const WTVFlashrom = require("./WTVFlashrom.js");
|
||||||
request_is_async = true;
|
request_is_async = true;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
// willie is just a graphical frontend to a list of ROMs
|
// willie is just a graphical frontend to a list of ROMs
|
||||||
// the rest of the scripts should work if you manually link to a ROM, and actually have it.
|
// the rest of the scripts should work if you manually link to a ROM, and actually have it.
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@ const req = https.request(options, function (res) {
|
|||||||
|
|
||||||
res.on('error', function (e) {
|
res.on('error', function (e) {
|
||||||
if (!minisrv_config.config.debug_flags.quiet) 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)
|
var errpage = wtvshared.doErrorPage(400)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
sendToClient(socket, headers, data);
|
sendToClient(socket, headers, data);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
var challenge_response, challenge_header = '';
|
var challenge_response, challenge_header = '';
|
||||||
var gourl;
|
var gourl;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
var challenge_response, challenge_header = '';
|
var challenge_response, challenge_header = '';
|
||||||
var gourl;
|
var gourl;
|
||||||
|
|
||||||
@@ -61,7 +63,7 @@ else {
|
|||||||
if (request_headers.query.skip_splash) var home_url = "wtv-home:/home?";
|
if (request_headers.query.skip_splash) var home_url = "wtv-home:/home?";
|
||||||
else var home_url = "wtv-home:/splash?";
|
else var home_url = "wtv-home:/splash?";
|
||||||
} else if (!ssid_sessions[socket.ssid].getSessionData("registered")) {
|
} else if (!ssid_sessions[socket.ssid].getSessionData("registered")) {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
var challenge_response, challenge_header = "";
|
var challenge_response, challenge_header = "";
|
||||||
|
|
||||||
var gourl = "wtv-head-waiter:/login-stage-two?";
|
var gourl = "wtv-head-waiter:/login-stage-two?";
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
var gourl = "wtv-1800:/preregister?";
|
var gourl = "wtv-1800:/preregister?";
|
||||||
if (request_headers.query.relogin) gourl += "relogin=true";
|
if (request_headers.query.relogin) gourl += "relogin=true";
|
||||||
else if (request_headers.query.reconnect) gourl += "reconnect=true";
|
else if (request_headers.query.reconnect) gourl += "reconnect=true";
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers =`200 OK
|
headers =`200 OK
|
||||||
Connection: Keep-Alive
|
Connection: Keep-Alive
|
||||||
wtv-expire-all: wtv-home:/splash
|
wtv-expire-all: wtv-home:/splash
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Connection: Keep-Alive
|
Connection: Keep-Alive
|
||||||
wtv-expire-all: wtv-
|
wtv-expire-all: wtv-
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
// write posted log data to disk. should be decrypted by this point (if it was encrypted) if the crypto stream didn't break
|
// write posted log data to disk. should be decrypted by this point (if it was encrypted) if the crypto stream didn't break
|
||||||
|
|
||||||
request_is_async = true;
|
request_is_async = true;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Content-Type: text/html`;
|
Content-Type: text/html`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (minisrv_config.config.allow_guests) {
|
if (minisrv_config.config.allow_guests) {
|
||||||
headers = `300 Moved
|
headers = `300 Moved
|
||||||
Connection: Close
|
Connection: Close
|
||||||
@@ -20,7 +22,7 @@ wtv-reconnect-url: wtv-1800:/preregister?guest_login=true&reconnect=true
|
|||||||
wtv-boot-url: wtv-1800:/preregister?guest_login=true
|
wtv-boot-url: wtv-1800:/preregister?guest_login=true
|
||||||
Location: client:relogin`;
|
Location: client:relogin`;
|
||||||
} else {
|
} else {
|
||||||
var errpage = doErrorPage(400, "Guest mode is not enabled on this service.");
|
var errpage = wtvshared.doErrorPage(400, "Guest mode is not enabled on this service.");
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `300 Moved
|
headers = `300 Moved
|
||||||
Connection: Close
|
Connection: Close
|
||||||
wtv-noback-all: wtv-register:
|
wtv-noback-all: wtv-register:
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (!request_headers.query.registering) {
|
if (!request_headers.query.registering) {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
} else {
|
} else {
|
||||||
const WTVRegister = require("./WTVRegister.js")
|
const WTVRegister = require("./WTVRegister.js")
|
||||||
var wtvr = new WTVRegister(minisrv_config, SessionStore);
|
var wtvr = new WTVRegister(minisrv_config, SessionStore);
|
||||||
var errpage = null;
|
var errpage = null;
|
||||||
if (!request_headers.query.registering) errpage = doErrorPage(400);
|
if (!request_headers.query.registering) errpage = wtvshared.doErrorPage(400);
|
||||||
else if (!request_headers.query.subscriber_name) errpage = doErrorPage(400, "Please enter your name. This can be your real name, or your well-known online alias.");
|
else if (!request_headers.query.subscriber_name) errpage = wtvshared.doErrorPage(400, "Please enter your name. This can be your real name, or your well-known online alias.");
|
||||||
else if (!request_headers.query.subscriber_username) errpage = doErrorPage(400, "Please enter a username.");
|
else if (!request_headers.query.subscriber_username) errpage = wtvshared.doErrorPage(400, "Please enter a username.");
|
||||||
else if (request_headers.query.subscriber_username.length < 5) errpage = doErrorPage(400, "Please choose a username with 5 or more characters.");
|
else if (request_headers.query.subscriber_username.length < 5) errpage = wtvshared.doErrorPage(400, "Please choose a username with 5 or more characters.");
|
||||||
else if (request_headers.query.subscriber_username.length > 16) errpage = doErrorPage(400, "Please choose a username with 16 or less characters.");
|
else if (request_headers.query.subscriber_username.length > 16) errpage = wtvshared.doErrorPage(400, "Please choose a username with 16 or less characters.");
|
||||||
else if (!wtvr.checkUsernameSanity(request_headers.query.subscriber_username)) errpage = doErrorPage(400, "The username you have chosen contains invalid characters. Please choose a username with only <b>letters</b>, <b>numbers</b>, <b>_</b> or <b>-</b>. Also, please be sure your username begins with a letter.");
|
else if (!wtvr.checkUsernameSanity(request_headers.query.subscriber_username)) errpage = wtvshared.doErrorPage(400, "The username you have chosen contains invalid characters. Please choose a username with only <b>letters</b>, <b>numbers</b>, <b>_</b> or <b>-</b>. Also, please be sure your username begins with a letter.");
|
||||||
else if (!wtvr.checkUsernameAvailable(request_headers.query.subscriber_username, ssid_sessions)) errpage = doErrorPage(400, "The username you have selected is already in use. Please select another username.");
|
else if (!wtvr.checkUsernameAvailable(request_headers.query.subscriber_username, ssid_sessions)) errpage = wtvshared.doErrorPage(400, "The username you have selected is already in use. Please select another username.");
|
||||||
else if (!request_headers.query.subscriber_contact) errpage = doErrorPage(400, "Please enter your contact information.");
|
else if (!request_headers.query.subscriber_contact) errpage = wtvshared.doErrorPage(400, "Please enter your contact information.");
|
||||||
else if (request_headers.query.subscriber_contact_method == "") errpage = doErrorPage(400, "Please select the type of contact information you provided.");
|
else if (request_headers.query.subscriber_contact_method == "") errpage = wtvshared.doErrorPage(400, "Please select the type of contact information you provided.");
|
||||||
|
|
||||||
|
|
||||||
if (errpage) {
|
if (errpage) {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (!request_headers.query.registering) {
|
if (!request_headers.query.registering) {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
if (!request_headers.query.registering ||
|
if (!request_headers.query.registering ||
|
||||||
!request_headers.query.subscriber_name ||
|
!request_headers.query.subscriber_name ||
|
||||||
!request_headers.query.subscriber_username ||
|
!request_headers.query.subscriber_username ||
|
||||||
@@ -7,7 +9,7 @@ if (!request_headers.query.registering ||
|
|||||||
!ssid_sessions[socket.ssid] ||
|
!ssid_sessions[socket.ssid] ||
|
||||||
!socket.ssid
|
!socket.ssid
|
||||||
) {
|
) {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
} else {
|
} else {
|
||||||
@@ -18,7 +20,7 @@ if (!request_headers.query.registering ||
|
|||||||
ssid_sessions[socket.ssid].setSessionData("subscriber_userid", '1' + Math.floor(Math.random() * 1000000000000000000));
|
ssid_sessions[socket.ssid].setSessionData("subscriber_userid", '1' + Math.floor(Math.random() * 1000000000000000000));
|
||||||
ssid_sessions[socket.ssid].setSessionData("registered", true);
|
ssid_sessions[socket.ssid].setSessionData("registered", true);
|
||||||
if (!ssid_sessions[socket.ssid].storeSessionData(true)) {
|
if (!ssid_sessions[socket.ssid].storeSessionData(true)) {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Content-Type: text/html`;
|
Content-Type: text/html`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Connection: Keep-Alive
|
Connection: Keep-Alive
|
||||||
wtv-expire-all: wtv-
|
wtv-expire-all: wtv-
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
wtv-backgroundmusic-load-playlist: wtv-music:/get-playlist
|
wtv-backgroundmusic-load-playlist: wtv-music:/get-playlist
|
||||||
wtv-printer-model: -1,-1
|
wtv-printer-model: -1,-1
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
// Allow URL access outside our trusted minisrv
|
// Allow URL access outside our trusted minisrv
|
||||||
|
|
||||||
if (request_headers.query.url) var url = request_headers.query.url;
|
if (request_headers.query.url) var url = request_headers.query.url;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
wtv-expire-all: wtv-
|
wtv-expire-all: wtv-
|
||||||
wtv-expire-all: http
|
wtv-expire-all: http
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
wtv-noback-all: wtv-
|
wtv-noback-all: wtv-
|
||||||
wtv-expire-all: wtv-
|
wtv-expire-all: wtv-
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
var client_caps = null;
|
var client_caps = null;
|
||||||
|
|
||||||
@@ -167,7 +168,7 @@ ${wtv_system_sysconfig_str}
|
|||||||
|
|
||||||
</body> </html>`;
|
</body> </html>`;
|
||||||
} else {
|
} else {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Content-Type: text/html`;
|
Content-Type: text/html`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Content-Type: text/html`
|
Content-Type: text/html`
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
var minisrv_service_file = true;
|
||||||
|
|
||||||
headers = `200 OK
|
headers = `200 OK
|
||||||
Content-Type: text/html`;
|
Content-Type: text/html`;
|
||||||
|
|
||||||
|
|||||||
@@ -8,51 +8,27 @@ class WTVFlashrom {
|
|||||||
no_debug = false;
|
no_debug = false;
|
||||||
service_name = "";
|
service_name = "";
|
||||||
minisrv_config = [];
|
minisrv_config = [];
|
||||||
|
wtvshared = null;
|
||||||
|
|
||||||
|
|
||||||
constructor(minisrv_config, service_vaults, service_name, use_zefie_server = true, bf0app_update = false, no_debug = false) {
|
constructor(minisrv_config, service_vaults, service_name, use_zefie_server = true, bf0app_update = false, no_debug = false) {
|
||||||
|
var { WTVShared } = require('./WTVShared.js');
|
||||||
this.service_vaults = service_vaults;
|
this.service_vaults = service_vaults;
|
||||||
this.service_name = service_name;
|
this.service_name = service_name;
|
||||||
this.use_zefie_server = use_zefie_server;
|
this.use_zefie_server = use_zefie_server;
|
||||||
this.bf0app_update = bf0app_update;
|
this.bf0app_update = bf0app_update;
|
||||||
this.no_debug = no_debug;
|
this.no_debug = no_debug;
|
||||||
this.minisrv_config = minisrv_config;
|
this.minisrv_config = minisrv_config;
|
||||||
|
this.wtvshared = new WTVShared(minisrv_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
doErrorPage(code, data = null) {
|
|
||||||
var headers = null;
|
|
||||||
switch (code) {
|
|
||||||
case 404:
|
|
||||||
if (data === null) data = "The service could not find the requested page.";
|
|
||||||
headers = "404 " + data + "\r\n";
|
|
||||||
headers += "Content-Type: text/html\r\n";
|
|
||||||
break;
|
|
||||||
case 400:
|
|
||||||
if (data === null) data = "HackTV ran into a technical problem.";
|
|
||||||
headers = "400 " + data + "\r\n";
|
|
||||||
headers += "Content-Type: text/html\r\n";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// what we send when we did not detect a wtv-url.
|
|
||||||
// e.g. when a pc browser connects
|
|
||||||
headers = "HTTP/1.1 200 OK\r\n";
|
|
||||||
headers += "Content-Type: text/html\r\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
console.error("doErrorPage Called:", code, data);
|
|
||||||
return new Array(headers, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async doLocalFlashROM(flashrom_file_path, request_path, callback, info_only = false) {
|
async doLocalFlashROM(flashrom_file_path, request_path, callback, info_only = false) {
|
||||||
// use local flashrom files;
|
// use local flashrom files;
|
||||||
console.log(info_only);
|
|
||||||
var self = this;
|
var self = this;
|
||||||
try {
|
try {
|
||||||
this.fs.readFile(flashrom_file_path, null, function (err, data) {
|
this.fs.readFile(flashrom_file_path, null, function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
errpage = doErrorPage(400)
|
errpage = wtvshared.doErrorPage(400)
|
||||||
var headers = errpage[0];
|
var headers = errpage[0];
|
||||||
data = err.toString();
|
data = err.toString();
|
||||||
callback(data, headers);
|
callback(data, headers);
|
||||||
@@ -65,7 +41,7 @@ class WTVFlashrom {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
var errpage = doErrorPage(404, "The service could not find the requested ROM.")
|
var errpage = wtvshared.doErrorPage(404, "The service could not find the requested ROM.")
|
||||||
var headers = errpage[0];
|
var headers = errpage[0];
|
||||||
var data = errpage[1];
|
var data = errpage[1];
|
||||||
callback(data, headers);
|
callback(data, headers);
|
||||||
@@ -107,24 +83,25 @@ class WTVFlashrom {
|
|||||||
flashrom_info.total_parts_size = data.readUInt32BE(32);
|
flashrom_info.total_parts_size = data.readUInt32BE(32);
|
||||||
flashrom_info.percent_complete = ((((flashrom_info.byte_progress + flashrom_info.part_total_size) / flashrom_info.total_parts_size)) * 100).toFixed(1);
|
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.minisrv_config.config.debug_flags.quiet && !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.minisrv_config.config.debug_flags.quiet && !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.minisrv_config.config.debug_flags.quiet && !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);
|
if (this.minisrv_config.config.debug_flags.debug && !this.minisrv_config.config.debug_flags.quiet && !this.no_debug) console.log(" # Flashrom Total Size :", flashrom_info.total_parts_size);
|
||||||
|
|
||||||
// read current part number bit from part header
|
// read current part number bit from part header
|
||||||
flashrom_info.part_number = data.readUInt16BE(28);
|
flashrom_info.part_number = data.readUInt16BE(28);
|
||||||
|
|
||||||
if (this.minisrv_config.config.debug_flags.debug && !this.no_debug) console.log(" # Flashrom Curr Part Number :", flashrom_info.part_number);
|
if (this.minisrv_config.config.debug_flags.debug && !this.minisrv_config.config.debug_flags.quiet && !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;
|
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 (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);
|
if (this.minisrv_config.config.debug_flags.debug && !this.minisrv_config.config.debug_flags.quiet && !this.no_debug) console.log(" # Flashrom Curr Part is Last:", flashrom_info.is_last_part);
|
||||||
} else {
|
} else {
|
||||||
flashrom_info.next_part_number = flashrom_info.part_number + 1;
|
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);
|
if (this.minisrv_config.config.debug_flags.debug && !this.minisrv_config.config.debug_flags.quiet && !this.no_debug) console.log(" # Flashrom Next Part Number :", flashrom_info.next_part_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.minisrv_config.config.debug_flags.debug && this.minisrv_config.config.debug_flags.quiet) console.log(" # Sending", (flashrom_info.is_last_part) ? "Last Flashrom" : "Flashrom", "Part", flashrom_info.part_number, "- Bytes Sent:", flashrom_info.byte_progress + flashrom_info.part_total_size, "of", flashrom_info.total_parts_size, "(" + flashrom_info.percent_complete + " % complete)");
|
||||||
// read current part display message from part header
|
// 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.message = new Buffer.from(part_header.toString('hex').substring(36 * 2, 68 * 2), 'hex').toString('ascii').replace(/[^0-9a-z\ \.\-]/gi, "");
|
||||||
flashrom_info.rompath = `wtv-flashrom:/${path}`;
|
flashrom_info.rompath = `wtv-flashrom:/${path}`;
|
||||||
@@ -142,7 +119,6 @@ class WTVFlashrom {
|
|||||||
|
|
||||||
async sendToClient(data, request_path, callback) {
|
async sendToClient(data, request_path, callback) {
|
||||||
var headers = "200 OK\n";
|
var headers = "200 OK\n";
|
||||||
if (this.bf0app_update) headers += "minisrv-use-carriage-return: false\n";
|
|
||||||
var flashrom_info = this.getFlashromInfo(data, request_path)
|
var flashrom_info = this.getFlashromInfo(data, request_path)
|
||||||
if (flashrom_info.is_bootrom) headers += "Content-Type: binary/x-wtv-bootrom"; // maybe?
|
if (flashrom_info.is_bootrom) headers += "Content-Type: binary/x-wtv-bootrom"; // maybe?
|
||||||
else headers += "Content-Type: binary/x-wtv-flashblock";
|
else headers += "Content-Type: binary/x-wtv-flashblock";
|
||||||
@@ -193,15 +169,16 @@ class WTVFlashrom {
|
|||||||
} else if (res.statusCode == 206) {
|
} else if (res.statusCode == 206) {
|
||||||
var data = self.getFlashromInfo(Buffer.from(data_hex, 'hex'), request_path);
|
var data = self.getFlashromInfo(Buffer.from(data_hex, 'hex'), request_path);
|
||||||
} else if (res.statusCode == 404) {
|
} else if (res.statusCode == 404) {
|
||||||
var errpage = doErrorPage(404, "The service could not find the requested ROM on zefie's server.")
|
console.log(request_path);
|
||||||
|
var errpage = self.wtvshared.doErrorPage(404, "The service could not find the requested ROM on zefie's server.")
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
var data = errpage[1];
|
var data = errpage[1];
|
||||||
} else {
|
} else {
|
||||||
var errpage = doErrorPage(400)
|
var errpage = self.wtvshared.doErrorPage(400)
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
var data = errpage[1];
|
var data = errpage[1];
|
||||||
}
|
}
|
||||||
if (res.statusCode != 206) {
|
if (!headers && res.statusCode != 206) {
|
||||||
self.sendToClient(data, request_path, callback);
|
self.sendToClient(data, request_path, callback);
|
||||||
} else {
|
} else {
|
||||||
callback(data, headers);
|
callback(data, headers);
|
||||||
|
|||||||
@@ -1,118 +1,154 @@
|
|||||||
/**
|
/**
|
||||||
* Pure-JS implementation of WebTV's LZPF compression
|
* Pure-JS implementation of WebTV's LZPF compression
|
||||||
*
|
*
|
||||||
* This is a port of my Lzpf compression code from my ROMFS Python tool
|
* This compression algorithm is based on LZP by Charles Bloom and was originally written for server to client communication by Andy McFadden
|
||||||
* Originally reverse engineered from the box
|
* This uses a (static) Huffman dictionary that was tuned for character occurances in a typical HTML page at the time (around 1996-1997).
|
||||||
*
|
*
|
||||||
* By: Eric MacDonald (eMac)
|
* Andy McFadden:
|
||||||
|
* https://fadden.com/
|
||||||
|
* LZP:
|
||||||
|
* https://cbloom.com/src/index_lz.html
|
||||||
|
* https://en.wikibooks.org/wiki/Data_Compression/Dictionary_compression#LZP
|
||||||
|
*
|
||||||
|
* I wouldn't recommend using LZPF on anything but HTML and other text-based data (unless the data has many repeating bytes)
|
||||||
|
* LZPF can be replaced with gzip for LC2 and newer boxes. Classic is stuck with LZPF.
|
||||||
|
*
|
||||||
|
* Reverse engineered and ported by: Eric MacDonald (eMac)
|
||||||
* Modified By: zefie
|
* Modified By: zefie
|
||||||
*/
|
**/
|
||||||
|
|
||||||
class WTVLzpf {
|
class WTVLzpf {
|
||||||
// Note: currentlty doesn't offer optimal streaming support but this is good enough to meet perf demands at the scale we're at.
|
// Note: currentlty doesn't offer optimal streaming support but this is good enough to meet perf demands at the scale we're at.
|
||||||
|
|
||||||
current_length = 0;
|
current_bit_length = 0;
|
||||||
current_literal = 0;
|
current_bits = 0;
|
||||||
flag = 0xFFFF;
|
ring_bufer_index = 0xFFFF;
|
||||||
working_data = 0;
|
working_data = 0;
|
||||||
match_index = 0;
|
match_index = 0;
|
||||||
type_index = 0;
|
compression_mode = 0;
|
||||||
checksum = 0;
|
checksum = 0;
|
||||||
flag_table = new Uint16Array(0x1000)
|
filler_byte = 0x20
|
||||||
|
hash_table = new Uint16Array(0x1000)
|
||||||
ring_buffer = new Uint8Array(0x2000)
|
ring_buffer = new Uint8Array(0x2000)
|
||||||
encoded_data = [];
|
encoded_data = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used to encode (one-byte) literals with no previous tracked occurence.
|
||||||
|
*
|
||||||
|
* - Bytes with best compression: SPACE and LF and e"/<>Tainoprst
|
||||||
|
* - Bytes with good compression: TAB and ,-.1=ABCDEFGHILNOPRSbcdfghlmuw
|
||||||
|
* - Bytes that don't change the length of the bit stream: 024:MW_kvy
|
||||||
|
* - The rest will increase the length of bit stream
|
||||||
|
*
|
||||||
|
* I don't know what process they used to build this table. I assume they
|
||||||
|
* frequency-scanned a bunch of HTML files they had.
|
||||||
|
*
|
||||||
|
* Using Windows-1252 (based off of ISO-8859-1) chracter encoding to fill in this table. Didn't
|
||||||
|
* seem like they used a different table for Japan builds (ISO-2022-JP).
|
||||||
|
**/
|
||||||
nomatchEncode = [
|
nomatchEncode = [
|
||||||
|
/* [FLATTENED HUFFMAN CODE, CODE BIT LENGTH] */
|
||||||
[0x0000, 0x10], [0x0001, 0x10], [0x0002, 0x10],
|
[0x0000, 0x10] /* NUL */, [0x0001, 0x10] /* SOH */, [0x0002, 0x10] /* STX */,
|
||||||
[0x0003, 0x10], [0x0004, 0x10], [0x009A, 0x0F],
|
[0x0003, 0x10] /* ETX */, [0x0004, 0x10] /* EOT */, [0x009A, 0x0F] /* ENQ */,
|
||||||
[0x0005, 0x10], [0x009C, 0x0F], [0x009E, 0x0F],
|
[0x0005, 0x10] /* ACK */, [0x009C, 0x0F] /* BEL */, [0x009E, 0x0F] /* BS */,
|
||||||
[0x3400, 0x06], [0x7000, 0x05], [0x00A0, 0x0F],
|
[0x3400, 0x06] /* TAB */, [0x7000, 0x05] /* LF */, [0x00A0, 0x0F] /* VT */,
|
||||||
[0x0006, 0x10], [0x0380, 0x09], [0x0007, 0x10],
|
[0x0006, 0x10] /* FF */, [0x0380, 0x09] /* CR */, [0x0007, 0x10] /* SO */,
|
||||||
[0x0008, 0x10], [0x0009, 0x10], [0x000A, 0x10],
|
[0x0008, 0x10] /* SI */, [0x0009, 0x10] /* DLE */, [0x000A, 0x10] /* DC1 */,
|
||||||
[0x000B, 0x10], [0x000C, 0x10], [0x000D, 0x10],
|
[0x000B, 0x10] /* DC2 */, [0x000C, 0x10] /* DC3 */, [0x000D, 0x10] /* DC4 */,
|
||||||
[0x000E, 0x10], [0x000F, 0x10], [0x00A2, 0x0F],
|
[0x000E, 0x10] /* NAK */, [0x000F, 0x10] /* SYN */, [0x00A2, 0x0F] /* BTB */,
|
||||||
[0x0010, 0x10], [0x0011, 0x10], [0x0012, 0x10],
|
[0x0010, 0x10] /* CAN */, [0x0011, 0x10] /* EM */, [0x0012, 0x10] /* SUB */,
|
||||||
[0x0013, 0x10], [0x0014, 0x10], [0x0015, 0x10],
|
[0x0013, 0x10] /* ESC */, [0x0014, 0x10] /* FS */, [0x0015, 0x10] /* GS */,
|
||||||
[0x0016, 0x10], [0x0017, 0x10], [0xE000, 0x04],
|
[0x0016, 0x10] /* RS */, [0x0017, 0x10] /* US */, [0xE000, 0x04] /* SPACE */,
|
||||||
[0x0200, 0x0A], [0x7800, 0x05], [0x0400, 0x09],
|
[0x0200, 0x0A] /* ! */, [0x7800, 0x05] /* " */, [0x0400, 0x09] /* # */,
|
||||||
[0x00B0, 0x0E], [0x0018, 0x10], [0x0120, 0x0B],
|
[0x00B0, 0x0E] /* $ */, [0x0018, 0x10] /* % */, [0x0120, 0x0B] /* & */,
|
||||||
[0x0480, 0x09], [0x0140, 0x0B], [0x0160, 0x0B],
|
[0x0480, 0x09] /* ' */, [0x0140, 0x0B] /* ( */, [0x0160, 0x0B] /* ) */,
|
||||||
[0x0240, 0x0A], [0x00B8, 0x0D], [0x1400, 0x07],
|
[0x0240, 0x0A] /* * */, [0x00B8, 0x0D] /* + */, [0x1400, 0x07] /* , */,
|
||||||
[0x1600, 0x07], [0x3800, 0x06], [0x8000, 0x05],
|
[0x1600, 0x07] /* - */, [0x3800, 0x06] /* . */, [0x8000, 0x05] /* / */,
|
||||||
[0x0A00, 0x08], [0x1800, 0x07], [0x0B00, 0x08],
|
[0x0A00, 0x08] /* 0 */, [0x1800, 0x07] /* 1 */, [0x0B00, 0x08] /* 2 */,
|
||||||
[0x0500, 0x09], [0x0C00, 0x08], [0x0580, 0x09],
|
[0x0500, 0x09] /* 3 */, [0x0C00, 0x08] /* 4 */, [0x0580, 0x09] /* 5 */,
|
||||||
[0x0600, 0x09], [0x0680, 0x09], [0x0700, 0x09],
|
[0x0600, 0x09] /* 6 */, [0x0680, 0x09] /* 7 */, [0x0700, 0x09] /* 8 */,
|
||||||
[0x0780, 0x09], [0x0D00, 0x08], [0x0180, 0x0B],
|
[0x0780, 0x09] /* 9 */, [0x0D00, 0x08] /* : */, [0x0180, 0x0B] /* ; */,
|
||||||
[0x8800, 0x05], [0x3C00, 0x06], [0x9000, 0x05],
|
[0x8800, 0x05] /* < */, [0x3C00, 0x06] /* = */, [0x9000, 0x05] /* > */,
|
||||||
[0x0280, 0x0A], [0x00B4, 0x0E], [0x4000, 0x06],
|
[0x0280, 0x0A] /* ? */, [0x00B4, 0x0E] /* @ */, [0x4000, 0x06] /* A */,
|
||||||
[0x1A00, 0x07], [0x1C00, 0x07], [0x1E00, 0x07],
|
[0x1A00, 0x07] /* B */, [0x1C00, 0x07] /* C */, [0x1E00, 0x07] /* D */,
|
||||||
[0x4400, 0x06], [0x2000, 0x07], [0x2200, 0x07],
|
[0x4400, 0x06] /* E */, [0x2000, 0x07] /* F */, [0x2200, 0x07] /* G */,
|
||||||
[0x2400, 0x07], [0x4800, 0x06], [0x01A0, 0x0B],
|
[0x2400, 0x07] /* H */, [0x4800, 0x06] /* I */, [0x01A0, 0x0B] /* J */,
|
||||||
[0x02C0, 0x0A], [0x2600, 0x07], [0x0E00, 0x08],
|
[0x02C0, 0x0A] /* K */, [0x2600, 0x07] /* L */, [0x0E00, 0x08] /* M */,
|
||||||
[0x4C00, 0x06], [0x5000, 0x06], [0x2800, 0x07],
|
[0x4C00, 0x06] /* N */, [0x5000, 0x06] /* O */, [0x2800, 0x07] /* P */,
|
||||||
[0x00C0, 0x0C], [0x5400, 0x06], [0x2A00, 0x07],
|
[0x00C0, 0x0C] /* Q */, [0x5400, 0x06] /* R */, [0x2A00, 0x07] /* S */,
|
||||||
[0x9800, 0x05], [0x0800, 0x09], [0x0880, 0x09],
|
[0x9800, 0x05] /* T */, [0x0800, 0x09] /* U */, [0x0880, 0x09] /* V */,
|
||||||
[0x0F00, 0x08], [0x00D0, 0x0C], [0x0300, 0x0A],
|
[0x0F00, 0x08] /* W */, [0x00D0, 0x0C] /* X */, [0x0300, 0x0A] /* Y */,
|
||||||
[0x0900, 0x09], [0x0019, 0x10], [0x001A, 0x10],
|
[0x0900, 0x09] /* Z */, [0x0019, 0x10] /* [ */, [0x001A, 0x10] /* \ */,
|
||||||
[0x001B, 0x10], [0x001C, 0x10], [0x1000, 0x08],
|
[0x001B, 0x10] /* ] */, [0x001C, 0x10] /* ^ */, [0x1000, 0x08] /* _ */,
|
||||||
[0x001D, 0x10], [0xA000, 0x05], [0x2C00, 0x07],
|
[0x001D, 0x10] /* ` */, [0xA000, 0x05] /* a */, [0x2C00, 0x07] /* b */,
|
||||||
[0x5800, 0x06], [0x5C00, 0x06], [0xF000, 0x04],
|
[0x5800, 0x06] /* c */, [0x5C00, 0x06] /* d */, [0xF000, 0x04] /* e */,
|
||||||
[0x2E00, 0x07], [0x3000, 0x07], [0x6000, 0x06],
|
[0x2E00, 0x07] /* f */, [0x3000, 0x07] /* g */, [0x6000, 0x06] /* h */,
|
||||||
[0xA800, 0x05], [0x01C0, 0x0B], [0x1100, 0x08],
|
[0xA800, 0x05] /* i */, [0x01C0, 0x0B] /* j */, [0x1100, 0x08] /* k */,
|
||||||
[0x6400, 0x06], [0x6800, 0x06], [0xB000, 0x05],
|
[0x6400, 0x06] /* l */, [0x6800, 0x06] /* m */, [0xB000, 0x05] /* n */,
|
||||||
[0xB800, 0x05], [0xC000, 0x05], [0x01E0, 0x0B],
|
[0xB800, 0x05] /* o */, [0xC000, 0x05] /* p */, [0x01E0, 0x0B] /* q */,
|
||||||
[0xC800, 0x05], [0xD000, 0x05], [0xD800, 0x05],
|
[0xC800, 0x05] /* r */, [0xD000, 0x05] /* s */, [0xD800, 0x05] /* t */,
|
||||||
[0x3200, 0x07], [0x1200, 0x08], [0x6C00, 0x06],
|
[0x3200, 0x07] /* u */, [0x1200, 0x08] /* v */, [0x6C00, 0x06] /* w */,
|
||||||
[0x0980, 0x09], [0x1300, 0x08], [0x0340, 0x0A],
|
[0x0980, 0x09] /* x */, [0x1300, 0x08] /* y */, [0x0340, 0x0A] /* z */,
|
||||||
[0x00E0, 0x0C], [0x00F0, 0x0C], [0x0100, 0x0C],
|
[0x00E0, 0x0C] /* { */, [0x00F0, 0x0C] /* | */, [0x0100, 0x0C] /* } */,
|
||||||
[0x0110, 0x0C], [0x001E, 0x10], [0x001F, 0x10],
|
[0x0110, 0x0C] /* ~ */, [0x001E, 0x10] /* DEL */, [0x001F, 0x10] /* <20> */,
|
||||||
[0x0020, 0x10], [0x0021, 0x10], [0x0022, 0x10],
|
[0x0020, 0x10] /* */, [0x0021, 0x10] /* <20> */, [0x0022, 0x10] /* <20> */,
|
||||||
[0x0023, 0x10], [0x0024, 0x10], [0x0025, 0x10],
|
[0x0023, 0x10] /* <20> */, [0x0024, 0x10] /* <20> */, [0x0025, 0x10] /* <20> */,
|
||||||
[0x0026, 0x10], [0x0027, 0x10], [0x0028, 0x10],
|
[0x0026, 0x10] /* <20> */, [0x0027, 0x10] /* <20> */, [0x0028, 0x10] /* <20> */,
|
||||||
[0x0029, 0x10], [0x002A, 0x10], [0x002B, 0x10],
|
[0x0029, 0x10] /* <20> */, [0x002A, 0x10] /* <20> */, [0x002B, 0x10] /* <20> */,
|
||||||
[0x002C, 0x10], [0x002D, 0x10], [0x002E, 0x10],
|
[0x002C, 0x10] /* */, [0x002D, 0x10] /* <20> */, [0x002E, 0x10] /* */,
|
||||||
[0x002F, 0x10], [0x00A4, 0x0F], [0x00A6, 0x0F],
|
[0x002F, 0x10] /* */, [0x00A4, 0x0F] /* <20> */, [0x00A6, 0x0F] /* <20> */,
|
||||||
[0x00A8, 0x0F], [0x0030, 0x10], [0x0031, 0x10],
|
[0x00A8, 0x0F] /* <20> */, [0x0030, 0x10] /* <20> */, [0x0031, 0x10] /* <20> */,
|
||||||
[0x0032, 0x10], [0x0033, 0x10], [0x0034, 0x10],
|
[0x0032, 0x10] /* <20> */, [0x0033, 0x10] /* <20> */, [0x0034, 0x10] /* <20> */,
|
||||||
[0x0035, 0x10], [0x0036, 0x10], [0x0037, 0x10],
|
[0x0035, 0x10] /* <20> */, [0x0036, 0x10] /* <20> */, [0x0037, 0x10] /* <20> */,
|
||||||
[0x0038, 0x10], [0x0039, 0x10], [0x003A, 0x10],
|
[0x0038, 0x10] /* <20> */, [0x0039, 0x10] /* */, [0x003A, 0x10] /* <20> */,
|
||||||
[0x003B, 0x10], [0x003C, 0x10], [0x003D, 0x10],
|
[0x003B, 0x10] /* <20> */, [0x003C, 0x10] /* NBSP*/, [0x003D, 0x10] /* <20> */,
|
||||||
[0x003E, 0x10], [0x003F, 0x10], [0x0040, 0x10],
|
[0x003E, 0x10] /* <20> */, [0x003F, 0x10] /* <20> */, [0x0040, 0x10] /* <20> */,
|
||||||
[0x0041, 0x10], [0x0042, 0x10], [0x0043, 0x10],
|
[0x0041, 0x10] /* <20> */, [0x0042, 0x10] /* <20> */, [0x0043, 0x10] /* <20> */,
|
||||||
[0x0044, 0x10], [0x0045, 0x10], [0x0046, 0x10],
|
[0x0044, 0x10] /* <20> */, [0x0045, 0x10] /* <20> */, [0x0046, 0x10] /* <20> */,
|
||||||
[0x0047, 0x10], [0x0048, 0x10], [0x0049, 0x10],
|
[0x0047, 0x10] /* <20> */, [0x0048, 0x10] /* <20> */, [0x0049, 0x10] /* SHY */,
|
||||||
[0x004A, 0x10], [0x004B, 0x10], [0x004C, 0x10],
|
[0x004A, 0x10] /* <20> */, [0x004B, 0x10] /* <20> */, [0x004C, 0x10] /* <20> */,
|
||||||
[0x004D, 0x10], [0x004E, 0x10], [0x004F, 0x10],
|
[0x004D, 0x10] /* <20> */, [0x004E, 0x10] /* <20> */, [0x004F, 0x10] /* <20> */,
|
||||||
[0x0050, 0x10], [0x0051, 0x10], [0x0052, 0x10],
|
[0x0050, 0x10] /* <20> */, [0x0051, 0x10] /* <20> */, [0x0052, 0x10] /* <20> */,
|
||||||
[0x0053, 0x10], [0x0054, 0x10], [0x0055, 0x10],
|
[0x0053, 0x10] /* <20> */, [0x0054, 0x10] /* <20> */, [0x0055, 0x10] /* <20> */,
|
||||||
[0x0056, 0x10], [0x0057, 0x10], [0x0058, 0x10],
|
[0x0056, 0x10] /* <20> */, [0x0057, 0x10] /* <20> */, [0x0058, 0x10] /* <20> */,
|
||||||
[0x0059, 0x10], [0x005A, 0x10], [0x005B, 0x10],
|
[0x0059, 0x10] /* <20> */, [0x005A, 0x10] /* <20> */, [0x005B, 0x10] /* <20> */,
|
||||||
[0x005C, 0x10], [0x005D, 0x10], [0x005E, 0x10],
|
[0x005C, 0x10] /* <20> */, [0x005D, 0x10] /* <20> */, [0x005E, 0x10] /* <20> */,
|
||||||
[0x005F, 0x10], [0x0060, 0x10], [0x0061, 0x10],
|
[0x005F, 0x10] /* <20> */, [0x0060, 0x10] /* <20> */, [0x0061, 0x10] /* <20> */,
|
||||||
[0x0062, 0x10], [0x00AA, 0x0F], [0x0063, 0x10],
|
[0x0062, 0x10] /* <20> */, [0x00AA, 0x0F] /* <20> */, [0x0063, 0x10] /* <20> */,
|
||||||
[0x0064, 0x10], [0x0065, 0x10], [0x0066, 0x10],
|
[0x0064, 0x10] /* <20> */, [0x0065, 0x10] /* <20> */, [0x0066, 0x10] /* <20> */,
|
||||||
[0x0067, 0x10], [0x0068, 0x10], [0x0069, 0x10],
|
[0x0067, 0x10] /* <20> */, [0x0068, 0x10] /* <20> */, [0x0069, 0x10] /* <20> */,
|
||||||
[0x006A, 0x10], [0x006B, 0x10], [0x006C, 0x10],
|
[0x006A, 0x10] /* <20> */, [0x006B, 0x10] /* <20> */, [0x006C, 0x10] /* <20> */,
|
||||||
[0x006D, 0x10], [0x006E, 0x10], [0x006F, 0x10],
|
[0x006D, 0x10] /* <20> */, [0x006E, 0x10] /* <20> */, [0x006F, 0x10] /* <20> */,
|
||||||
[0x0070, 0x10], [0x0071, 0x10], [0x0072, 0x10],
|
[0x0070, 0x10] /* <20> */, [0x0071, 0x10] /* <20> */, [0x0072, 0x10] /* <20> */,
|
||||||
[0x0073, 0x10], [0x0074, 0x10], [0x0075, 0x10],
|
[0x0073, 0x10] /* <20> */, [0x0074, 0x10] /* <20> */, [0x0075, 0x10] /* <20> */,
|
||||||
[0x0076, 0x10], [0x0077, 0x10], [0x0078, 0x10],
|
[0x0076, 0x10] /* <20> */, [0x0077, 0x10] /* <20> */, [0x0078, 0x10] /* <20> */,
|
||||||
[0x0079, 0x10], [0x007A, 0x10], [0x007B, 0x10],
|
[0x0079, 0x10] /* <20> */, [0x007A, 0x10] /* <20> */, [0x007B, 0x10] /* <20> */,
|
||||||
[0x007C, 0x10], [0x007D, 0x10], [0x007E, 0x10],
|
[0x007C, 0x10] /* <20> */, [0x007D, 0x10] /* <20> */, [0x007E, 0x10] /* <20> */,
|
||||||
[0x007F, 0x10], [0x0080, 0x10], [0x0081, 0x10],
|
[0x007F, 0x10] /* <20> */, [0x0080, 0x10] /* <20> */, [0x0081, 0x10] /* <20> */,
|
||||||
[0x0082, 0x10], [0x0083, 0x10], [0x0084, 0x10],
|
[0x0082, 0x10] /* <20> */, [0x0083, 0x10] /* <20> */, [0x0084, 0x10] /* <20> */,
|
||||||
[0x0085, 0x10], [0x0086, 0x10], [0x0087, 0x10],
|
[0x0085, 0x10] /* <20> */, [0x0086, 0x10] /* <20> */, [0x0087, 0x10] /* <20> */,
|
||||||
[0x0088, 0x10], [0x0089, 0x10], [0x008A, 0x10],
|
[0x0088, 0x10] /* <20> */, [0x0089, 0x10] /* <20> */, [0x008A, 0x10] /* <20> */,
|
||||||
[0x008B, 0x10], [0x008C, 0x10], [0x008D, 0x10],
|
[0x008B, 0x10] /* <20> */, [0x008C, 0x10] /* <20> */, [0x008D, 0x10] /* <20> */,
|
||||||
[0x00AC, 0x0F], [0x008E, 0x10], [0x008F, 0x10],
|
[0x00AC, 0x0F] /* <20> */, [0x008E, 0x10] /* <20> */, [0x008F, 0x10] /* <20> */,
|
||||||
[0x0090, 0x10], [0x0091, 0x10], [0x0092, 0x10],
|
[0x0090, 0x10] /* <20> */, [0x0091, 0x10] /* <20> */, [0x0092, 0x10] /* <20> */,
|
||||||
[0x0093, 0x10], [0x00AE, 0x0F], [0x0094, 0x10],
|
[0x0093, 0x10] /* <20> */, [0x00AE, 0x0F] /* <20> */, [0x0094, 0x10] /* <20> */,
|
||||||
[0x0095, 0x10], [0x0096, 0x10], [0x0097, 0x10],
|
[0x0095, 0x10] /* <20> */, [0x0096, 0x10] /* <20> */, [0x0097, 0x10] /* <20> */,
|
||||||
[0x0098, 0x10], [0x0099, 0x10]
|
[0x0098, 0x10] /* <20> */, [0x0099, 0x10]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the table that reduces the size based on repeated patterns in the file.
|
||||||
|
*
|
||||||
|
* When we find a byte match in the ring buffer we use this table to encode the length of the matched bytes.
|
||||||
|
*
|
||||||
|
* - These are intentionally 32-bit. The leftmost flag bit is 1 in each of these to tell the decoder to use match decoding.
|
||||||
|
* - LZP hash bits are used to encode the position where the matched bytes start.
|
||||||
|
* - We're allowed to match up to 298 bytes before we can't encode more (we need an entry in this table for each byte more).
|
||||||
|
* - We can reach for matches 65KB behind the current LZ cursor (65KB is the ring buffer size and highest a 16-bit hash can reach).
|
||||||
|
**/
|
||||||
matchEncode = [
|
matchEncode = [
|
||||||
|
/* [MATCH CODE, MATCH CODE BIT LENGTH] */
|
||||||
[0x80000000, 0x01], [0x80000000, 0x03],
|
[0x80000000, 0x01], [0x80000000, 0x03],
|
||||||
[0xA0000000, 0x03], [0xC0000000, 0x03],
|
[0xA0000000, 0x03], [0xC0000000, 0x03],
|
||||||
[0xE0000000, 0x06], [0xE4000000, 0x06],
|
[0xE0000000, 0x06], [0xE4000000, 0x06],
|
||||||
@@ -262,6 +298,7 @@ class WTVLzpf {
|
|||||||
[0xFFFF4000, 0x13], [0xFFFF6000, 0x13],
|
[0xFFFF4000, 0x13], [0xFFFF6000, 0x13],
|
||||||
[0xFFFF8000, 0x13], [0xFFFFA000, 0x13],
|
[0xFFFF8000, 0x13], [0xFFFFA000, 0x13],
|
||||||
[0xFFFFC000, 0x13], [0xFFFFE000, 0x13],
|
[0xFFFFC000, 0x13], [0xFFFFE000, 0x13],
|
||||||
|
// We never should select these. These were in the original executable so including them here.
|
||||||
[0x00000000, 0x00], [0x00000000, 0x00]
|
[0x00000000, 0x00], [0x00000000, 0x00]
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -271,7 +308,7 @@ class WTVLzpf {
|
|||||||
* @returns {undefined}
|
* @returns {undefined}
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
this.clear();
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -279,16 +316,16 @@ class WTVLzpf {
|
|||||||
*
|
*
|
||||||
* @returns {undefined}
|
* @returns {undefined}
|
||||||
*/
|
*/
|
||||||
clear() {
|
reset() {
|
||||||
this.current_length = 0;
|
this.current_bit_length = 0;
|
||||||
this.current_literal = 0;
|
this.current_bits = 0;
|
||||||
this.flag = 0xFFFF;
|
this.ring_bufer_index = 0xFFFF;
|
||||||
this.working_data = 0;
|
this.working_data = 0;
|
||||||
this.match_index = 0;
|
this.match_index = 0;
|
||||||
this.type_index = 0;
|
this.compression_mode = 0;
|
||||||
this.checksum = 0;
|
this.checksum = 0;
|
||||||
this.ring_buffer.fill(0x00, 0, 0x2000)
|
this.ring_buffer.fill(this.filler_byte, 0, 0x2000)
|
||||||
this.flag_table.fill(0xFFFF, 0, 0x1000);
|
this.hash_table.fill(0xFFFF, 0, 0x1000);
|
||||||
this.encoded_data = [];
|
this.encoded_data = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,24 +341,24 @@ class WTVLzpf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes a literal onto the compressed byte array.
|
* Add bits onto the compressed bit stream.
|
||||||
*
|
*
|
||||||
* @param code_length {Number} bit length of the code
|
* When we reach 8 bits we push a byte onto the compressed byte array.
|
||||||
* @param code {Number} code to be encoded
|
*
|
||||||
|
* @param bits {Number} bits to add
|
||||||
|
* @param bit_length {Number} bit length
|
||||||
*
|
*
|
||||||
* @returns {undefined}
|
* @returns {undefined}
|
||||||
*/
|
*/
|
||||||
EncodeLiteral(code_length, code) {
|
AddBits(bits, bit_length) {
|
||||||
// Using >>> to stick with unsigned integers without making a mess with casting.
|
this.current_bits |= bits >>> (this.current_bit_length & 0x1F);
|
||||||
|
this.current_bit_length += bit_length;
|
||||||
|
|
||||||
this.current_literal |= code >>> (this.current_length & 0x1F);
|
while (this.current_bit_length > 7) {
|
||||||
this.current_length += code_length;
|
this.AddByte((this.current_bits >>> 0x18) & 0xFF);
|
||||||
|
|
||||||
while (this.current_length > 7) {
|
this.current_bit_length -= 8;
|
||||||
this.AddByte((this.current_literal >>> 0x18) & 0xFF);
|
this.current_bits = (this.current_bits << 8) & 0xFFFFFFFF;
|
||||||
|
|
||||||
this.current_length -= 8;
|
|
||||||
this.current_literal = (this.current_literal << 8) & 0xFFFFFFFF;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,7 +368,7 @@ class WTVLzpf {
|
|||||||
* @returns {undefined} Lzpf compression data
|
* @returns {undefined} Lzpf compression data
|
||||||
*/
|
*/
|
||||||
Begin() {
|
Begin() {
|
||||||
this.clear();
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -347,7 +384,7 @@ class WTVLzpf {
|
|||||||
var uncompressed_len = unencoded_data.byteLength;
|
var uncompressed_len = unencoded_data.byteLength;
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
var flags_index = 0;
|
var hash_index = 0;
|
||||||
while (i < uncompressed_len) {
|
while (i < uncompressed_len) {
|
||||||
var code_length = -1;
|
var code_length = -1;
|
||||||
var code = -1;
|
var code = -1;
|
||||||
@@ -356,48 +393,58 @@ class WTVLzpf {
|
|||||||
this.ring_buffer[i & 0x1FFF] = byte;
|
this.ring_buffer[i & 0x1FFF] = byte;
|
||||||
|
|
||||||
if (this.match_index > 0) {
|
if (this.match_index > 0) {
|
||||||
if (byte != this.ring_buffer[this.flag] || this.match_index > 0x0127) {
|
// Cozy time
|
||||||
|
if (byte != this.ring_buffer[this.ring_bufer_index] || this.match_index > 0x0127) {
|
||||||
|
// End of matching. Either we no longer match or we reached out limit.
|
||||||
code_length = this.matchEncode[this.match_index][1];
|
code_length = this.matchEncode[this.match_index][1];
|
||||||
code = this.matchEncode[this.match_index][0];
|
code = this.matchEncode[this.match_index][0];
|
||||||
this.match_index = 0;
|
this.match_index = 0;
|
||||||
this.type_index = 3;
|
this.compression_mode = 3;
|
||||||
} else {
|
} else {
|
||||||
|
// Previous iteration found a match so we continue matching until we can't.
|
||||||
this.match_index = (this.match_index + 1) & 0x1FFF;
|
this.match_index = (this.match_index + 1) & 0x1FFF;
|
||||||
this.flag = (this.flag + 1) & 0x1FFF;
|
this.ring_bufer_index = (this.ring_bufer_index + 1) & 0x1FFF;
|
||||||
this.checksum = (this.checksum + byte) & 0xFFFF;
|
this.checksum = (this.checksum + byte) & 0xFFFF;
|
||||||
this.working_data = ((this.working_data * 0x0100) + byte) & 0xFFFFFFFF;
|
this.working_data = ((this.working_data * 0x0100) + byte) & 0xFFFFFFFF;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.flag = 0xFFFF;
|
this.ring_bufer_index = 0xFFFF;
|
||||||
|
|
||||||
if (i >= 3) {
|
if (i >= 3) {
|
||||||
flags_index = (this.working_data >>> 0x0B ^ this.working_data) & 0x0FFF;
|
// Start recoding data so we can lookup matches.
|
||||||
this.flag = this.flag_table[flags_index];
|
hash_index = (this.working_data >>> 0x0B ^ this.working_data) & 0x0FFF;
|
||||||
this.flag_table[flags_index] = i & 0x1FFF;
|
this.ring_bufer_index = this.hash_table[hash_index];
|
||||||
|
this.hash_table[hash_index] = i & 0x1FFF;
|
||||||
} else {
|
} else {
|
||||||
this.type_index++;
|
// The first three uncompressed bytes aren't used for the matching algorithm.
|
||||||
|
this.compression_mode++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.flag == 0xFFFF) {
|
if (this.ring_bufer_index == 0xFFFF) {
|
||||||
|
// We never seen this byte before so we encode it with our Huffman table.
|
||||||
code_length = this.nomatchEncode[byte][1];
|
code_length = this.nomatchEncode[byte][1];
|
||||||
code = this.nomatchEncode[byte][0] << 0x10;
|
code = this.nomatchEncode[byte][0] << 0x10;
|
||||||
} else if (byte == this.ring_buffer[this.flag] && compress_data) {
|
} else if (byte == this.ring_buffer[this.ring_bufer_index] && compress_data) {
|
||||||
|
// Wow dude, a match has been found. Let's switch get our own room in the next iteration to see if we match further.
|
||||||
this.match_index = 1;
|
this.match_index = 1;
|
||||||
this.flag = (this.flag + 1) & 0x1FFF;
|
this.ring_bufer_index = (this.ring_bufer_index + 1) & 0x1FFF;
|
||||||
this.type_index = 4;
|
this.compression_mode = 4;
|
||||||
} else {
|
} else {
|
||||||
|
// We've seen these bytes before but the index in the ring buffer doesn't match so we revert to our neat Huffman table
|
||||||
|
// We add 1 flag bit of 0 to account for the fact we've had a hash table hit but no hit in the ring buffer.
|
||||||
code_length = this.nomatchEncode[byte][1] + 1;
|
code_length = this.nomatchEncode[byte][1] + 1;
|
||||||
code = this.nomatchEncode[byte][0] << 0x0F;
|
code = this.nomatchEncode[byte][0] << 0x0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.checksum = (this.checksum + byte) & 0xFFFF;
|
this.checksum = (this.checksum + byte) & 0xFFFF;
|
||||||
|
// We work on a 2-byte context so we store the last two bytes so we can do cool lookups with it
|
||||||
this.working_data = ((this.working_data * 0x0100) + byte) & 0xFFFFFFFF;
|
this.working_data = ((this.working_data * 0x0100) + byte) & 0xFFFFFFFF;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code_length > 0) {
|
if (code_length > 0) {
|
||||||
this.EncodeLiteral(code_length, code);
|
this.AddBits(code, code_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -405,7 +452,7 @@ class WTVLzpf {
|
|||||||
/**
|
/**
|
||||||
* Ends a compression stream.
|
* Ends a compression stream.
|
||||||
*
|
*
|
||||||
* @param type_index {Number} the end type used to finalize
|
* @param compression_mode {Number} the end type used to finalize
|
||||||
*
|
*
|
||||||
* @returns {Buffer} Lzpf compression data
|
* @returns {Buffer} Lzpf compression data
|
||||||
*/
|
*/
|
||||||
@@ -413,33 +460,34 @@ class WTVLzpf {
|
|||||||
var code_length = -1;
|
var code_length = -1;
|
||||||
var code = -1;
|
var code = -1;
|
||||||
|
|
||||||
if (this.type_index == 2) {
|
if (this.compression_mode == 2) {
|
||||||
this.EncodeLiteral(0x10, 0x00990000);
|
this.AddBits(0x00990000, 0x10);
|
||||||
} else if (this.type_index >= 3) {
|
} else if (this.compression_mode >= 3) {
|
||||||
if (this.type_index == 4) {
|
if (this.compression_mode == 4) {
|
||||||
code_length = this.matchEncode[this.match_index][1];
|
code_length = this.matchEncode[this.match_index][1];
|
||||||
code = this.matchEncode[this.match_index][0];
|
code = this.matchEncode[this.match_index][0];
|
||||||
this.EncodeLiteral(code_length, code);
|
this.AddBits(code, code_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
var flags_index = (this.working_data >>> 0x0B ^ this.working_data) & 0x0FFF;
|
var hash_index = (this.working_data >>> 0x0B ^ this.working_data) & 0x0FFF;
|
||||||
var flag = this.flag_table[flags_index];
|
var ring_bufer_index = this.hash_table[hash_index];
|
||||||
if (flag == 0xFFFF) {
|
if (ring_bufer_index == 0xFFFF) {
|
||||||
this.EncodeLiteral(0x10, 0x00990000);
|
this.AddBits(0x00990000, 0x10);
|
||||||
} else {
|
} else {
|
||||||
this.EncodeLiteral(0x11, 0x004c8000);
|
this.AddBits(0x004C8000, 0x11);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Below is just metadata. The compressed block is complete.
|
// Add checksum bits
|
||||||
|
this.AddBits((this.checksum << 0x10) & 0xFFFFFFFF, 0x08);
|
||||||
|
this.AddBits((this.checksum << 0x18) & 0xFFFFFFFF, 0x08);
|
||||||
|
|
||||||
// Encode checksum
|
// If we have leftover bits then add it.
|
||||||
this.EncodeLiteral(0x08, (this.checksum << 0x10) & 0xFFFFFFFF);
|
if (this.current_bit_length > 0) {
|
||||||
this.EncodeLiteral(0x08, (this.checksum << 0x18) & 0xFFFFFFFF);
|
this.AddByte((this.current_bits >>> 0x18) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
// End
|
this.AddByte(this.filler_byte);
|
||||||
this.AddByte((this.current_literal >>> 0x18) & 0xFF);
|
|
||||||
this.AddByte(0x20);
|
|
||||||
|
|
||||||
return Buffer.from(this.encoded_data);
|
return Buffer.from(this.encoded_data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class WTVMime {
|
|||||||
// gzip only
|
// gzip only
|
||||||
if (content_type.match(/^audio\/(x-)?(s3m|mod|xm)$/)) compress_data = true; // s3m, mod, xm
|
if (content_type.match(/^audio\/(x-)?(s3m|mod|xm)$/)) compress_data = true; // s3m, mod, xm
|
||||||
if (content_type.match(/^audio\/(x-)?(midi|wav|wave|aif(f)?)$/)) compress_data = true; // midi & wav
|
if (content_type.match(/^audio\/(x-)?(midi|wav|wave|aif(f)?)$/)) compress_data = true; // midi & wav
|
||||||
|
if (content_type.match(/^application\/karaoke$/)) compress_data = true; // midi karaoke
|
||||||
if (content_type.match(/^binary\/x-wtv-approm$/)) compress_data = true; // approms
|
if (content_type.match(/^binary\/x-wtv-approm$/)) compress_data = true; // approms
|
||||||
if (content_type.match(/^binary\/doom-data$/)) compress_data = true; // DOOM WADs
|
if (content_type.match(/^binary\/doom-data$/)) compress_data = true; // DOOM WADs
|
||||||
if (content_type.match(/^wtv\/download-list$/)) compress_data = true; // WebTV Download List
|
if (content_type.match(/^wtv\/download-list$/)) compress_data = true; // WebTV Download List
|
||||||
@@ -179,6 +180,9 @@ class WTVMime {
|
|||||||
case "wad":
|
case "wad":
|
||||||
wtv_mime_type = "binary/doom-data";
|
wtv_mime_type = "binary/doom-data";
|
||||||
break;
|
break;
|
||||||
|
case "kar":
|
||||||
|
wtv_mime_type = "application/karaoke";
|
||||||
|
break;
|
||||||
case "mp2":
|
case "mp2":
|
||||||
case "hsb":
|
case "hsb":
|
||||||
case "rmf":
|
case "rmf":
|
||||||
@@ -190,6 +194,7 @@ class WTVMime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
modern_mime_type = this.mime.lookup(path);
|
modern_mime_type = this.mime.lookup(path);
|
||||||
|
if (modern_mime_type === false) modern_mime_type = "application/octet-stream";
|
||||||
if (wtv_mime_type == "") wtv_mime_type = modern_mime_type;
|
if (wtv_mime_type == "") wtv_mime_type = modern_mime_type;
|
||||||
return new Array(wtv_mime_type, modern_mime_type);
|
return new Array(wtv_mime_type, modern_mime_type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,6 +199,68 @@ class WTVShared {
|
|||||||
return path.reverse().split(".")[0].reverse();
|
return path.reverse().split(".")[0].reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLineFromFile(filename, line_no, callback) {
|
||||||
|
var stream = this.fs.createReadStream(filename, {
|
||||||
|
flags: 'r',
|
||||||
|
encoding: 'utf-8',
|
||||||
|
fd: null,
|
||||||
|
bufferSize: 64 * 1024
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var fileData = '';
|
||||||
|
stream.on('data', function (data) {
|
||||||
|
fileData += data;
|
||||||
|
|
||||||
|
// The next lines should be improved
|
||||||
|
var lines = fileData.split("\n");
|
||||||
|
|
||||||
|
if (lines.length >= +line_no) {
|
||||||
|
stream.destroy();
|
||||||
|
callback(null, lines[+line_no]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('error', function () {
|
||||||
|
callback('Error', null);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('end', function () {
|
||||||
|
callback('File end reached without finding line', null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
doErrorPage(code, data = null, pc_mode = false) {
|
||||||
|
var headers = null;
|
||||||
|
switch (code) {
|
||||||
|
case 404:
|
||||||
|
if (data === null) data = "The service could not find the requested page.";
|
||||||
|
if (pc_mode) headers = "404 Not Found\n";
|
||||||
|
else headers = code + " " + data + "\n";
|
||||||
|
headers += "Content-Type: text/html\n";
|
||||||
|
break;
|
||||||
|
case 400:
|
||||||
|
case 500:
|
||||||
|
if (data === null) data = "HackTV ran into a technical problem.";
|
||||||
|
if (pc_mode) headers = "500 Internal Server Error\n";
|
||||||
|
else headers = code + " " + data + "\n";
|
||||||
|
headers += "Content-Type: text/html\n";
|
||||||
|
break;
|
||||||
|
case 401:
|
||||||
|
if (data === null) data = "Access Denied.";
|
||||||
|
if (pc_mode) headers = "401 Access Denied\n";
|
||||||
|
else headers = code + " " + data + "\n";
|
||||||
|
headers += "Content-Type: text/html\n";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
headers = code + " " + data + "\n";
|
||||||
|
headers += "Content-Type: text/html\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
console.error(" * doErrorPage Called:", code, data);
|
||||||
|
return new Array(headers, data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strips bad things from paths
|
* Strips bad things from paths
|
||||||
* @param {string} base Base path
|
* @param {string} base Base path
|
||||||
|
|||||||
@@ -71,47 +71,31 @@ function getServiceString(service, overrides = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// passthrough for old scripts
|
||||||
function doErrorPage(code, data = null, pc_mode = false) {
|
function doErrorPage(code, data = null, pc_mode = false) {
|
||||||
var headers = null;
|
return wtvshared.doErrorPage(code, data, pc_mode);
|
||||||
switch (code) {
|
|
||||||
case 404:
|
|
||||||
if (data === null) data = "The service could not find the requested page.";
|
|
||||||
if (pc_mode) headers = "404 Not Found\n";
|
|
||||||
else headers = code + " "+ data + "\n";
|
|
||||||
headers += "Content-Type: text/html\n";
|
|
||||||
break;
|
|
||||||
case 400:
|
|
||||||
case 500:
|
|
||||||
if (data === null) data = "HackTV ran into a technical problem.";
|
|
||||||
if (pc_mode) headers = "500 Internal Server Error\n";
|
|
||||||
else headers = code + " " + data + "\n";
|
|
||||||
headers += "Content-Type: text/html\n";
|
|
||||||
break;
|
|
||||||
case 401:
|
|
||||||
if (data === null) data = "Access Denied.";
|
|
||||||
if (pc_mode) headers = "401 Access Denied\n";
|
|
||||||
else headers = code + " " + data + "\n";
|
|
||||||
headers += "Content-Type: text/html\n";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
headers = code + " " + data + "\n";
|
|
||||||
headers += "Content-Type: text/html\n";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
console.error(" * doErrorPage Called:", code, data);
|
|
||||||
return new Array(headers, data);
|
async function sendRawFile(socket, path) {
|
||||||
|
if (!minisrv_config.config.debug_flags.quiet) console.log(" * Found " + path + " to handle request (Direct File Mode) [Socket " + socket.id + "]");
|
||||||
|
var contypes = wtvmime.getContentType(path);
|
||||||
|
var headers = "200 OK\n"
|
||||||
|
headers += "Content-Type: " + contypes[0] + "\n";
|
||||||
|
headers += "wtv-modern-content-type" + contypes[1];
|
||||||
|
fs.readFile(path, null, function (err, data) {
|
||||||
|
sendToClient(socket, headers, data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processPath(socket, service_vault_file_path, request_headers = new Array(), service_name) {
|
async function processPath(socket, service_vault_file_path, request_headers = new Array(), service_name) {
|
||||||
var headers, data = null;
|
var headers, data = null;
|
||||||
var request_is_async = false;
|
var request_is_async = false;
|
||||||
var service_vault_found = false;
|
var service_vault_found = false;
|
||||||
var service_path = service_vault_file_path;
|
var service_path = unescape(service_vault_file_path);
|
||||||
try {
|
try {
|
||||||
service_vaults.forEach(function (service_vault_dir) {
|
service_vaults.forEach(function (service_vault_dir) {
|
||||||
if (service_vault_found) return;
|
if (service_vault_found) return;
|
||||||
service_vault_file_path = wtvshared.makeSafePath(service_vault_dir, service_path);
|
service_vault_file_path = wtvshared.makeSafePath(service_vault_dir, service_path);
|
||||||
|
|
||||||
// deny access to catchall file name directly
|
// deny access to catchall file name directly
|
||||||
var service_path_split = service_path.split("/");
|
var service_path_split = service_path.split("/");
|
||||||
var service_path_request_file = service_path_split[service_path_split.length - 1];
|
var service_path_request_file = service_path_split[service_path_split.length - 1];
|
||||||
@@ -121,28 +105,66 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
|
|||||||
else minisrv_catchall = minisrv_config.config.catchall_file_name || null;
|
else minisrv_catchall = minisrv_config.config.catchall_file_name || null;
|
||||||
if (minisrv_catchall) {
|
if (minisrv_catchall) {
|
||||||
if (service_path_request_file == minisrv_catchall) {
|
if (service_path_request_file == minisrv_catchall) {
|
||||||
var errpage = doErrorPage(401, "Access Denied");
|
request_is_async = true;
|
||||||
headers = errpage[0];
|
var errpage = wtvshared.doErrorPage(401, "Access Denied");
|
||||||
data = errpage[1];
|
sendToClient(socket, errpage[0], errpage[1]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var is_dir = false;
|
||||||
|
var file_exists = false;
|
||||||
minisrv_catchall, service_path_split, service_path_request_file = null;
|
minisrv_catchall, service_path_split, service_path_request_file = null;
|
||||||
|
|
||||||
if (fs.existsSync(service_vault_file_path)) {
|
if (fs.existsSync(service_vault_file_path)) {
|
||||||
|
file_exists = true;
|
||||||
|
is_dir = fs.lstatSync(service_vault_file_path).isDirectory()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists && !is_dir) {
|
||||||
// file exists, read it and return it
|
// file exists, read it and return it
|
||||||
service_vault_found = true;
|
service_vault_found = true;
|
||||||
request_is_async = true;
|
request_is_async = true;
|
||||||
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;
|
request_headers.service_file_path = service_vault_file_path;
|
||||||
var contypes = wtvmime.getContentType(service_vault_file_path);
|
request_headers.raw_file = true;
|
||||||
headers = "200 OK\n"
|
|
||||||
headers += "Content-Type: " + contypes[0] + "\n";
|
// service parsed files, we might not want to expose our service source files so we can protect them with a flag on the first line
|
||||||
headers += "wtv-modern-content-type" + contypes[1];
|
if (wtvshared.getFileExt(service_vault_file_path).toLowerCase() == "js" || wtvshared.getFileExt(service_vault_file_path).toLowerCase() == "txt") {
|
||||||
fs.readFile(service_vault_file_path, null, function (err, data) {
|
if (wtvshared.getFileExt(service_vault_file_path).toLowerCase() == "js") {
|
||||||
sendToClient(socket, headers, data);
|
wtvshared.getLineFromFile(service_vault_file_path, 0, function (status, line) {
|
||||||
|
if (!status) {
|
||||||
|
if (line.match(/minisrv\_service\_file.*true/i)) {
|
||||||
|
var errpage = wtvshared.doErrorPage(403, "Access Denied");
|
||||||
|
sendToClient(socket, errpage[0], errpage[1]);
|
||||||
|
} else {
|
||||||
|
sendRawFile(socket, service_vault_file_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
|
sendToClient(socket, errpage[0], errpage[1]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wtvshared.getFileExt(service_vault_file_path).toLowerCase() == "txt") {
|
||||||
|
wtvshared.getLineFromFile(service_vault_file_path, 0, function (status, line) {
|
||||||
|
if (!status) {
|
||||||
|
if (line.match(/^#!minisrv/i)) {
|
||||||
|
var errpage = wtvshared.doErrorPage(403, "Access Denied");
|
||||||
|
sendToClient(socket, errpage[0], errpage[1]);
|
||||||
|
} else {
|
||||||
|
sendRawFile(socket, service_vault_file_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
|
sendToClient(socket, errpage[0], errpage[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// not a potential service file, so save to send
|
||||||
|
sendRawFile(socket, service_vault_file_path);
|
||||||
|
}
|
||||||
|
|
||||||
} else if (fs.existsSync(service_vault_file_path + ".txt")) {
|
} else if (fs.existsSync(service_vault_file_path + ".txt")) {
|
||||||
// raw text format, entire payload expected (headers and content)
|
// raw text format, entire payload expected (headers and content)
|
||||||
service_vault_found = true;
|
service_vault_found = true;
|
||||||
@@ -211,6 +233,7 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
|
|||||||
while (service_check_dir.join(path.sep) != service_vault_dir) {
|
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;
|
var catchall_file = service_check_dir.join(path.sep) + path.sep + minisrv_catchall_file_name;
|
||||||
if (fs.existsSync(catchall_file)) {
|
if (fs.existsSync(catchall_file)) {
|
||||||
|
service_vault_found = true;
|
||||||
if (!minisrv_config.config.debug_flags.quiet) console.log(" * Found catchall at " + catchall_file + " to handle request (JS Interpreter 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;
|
request_headers.service_file_path = catchall_file;
|
||||||
var jscript_eval = fs.readFileSync(catchall_file).toString();
|
var jscript_eval = fs.readFileSync(catchall_file).toString();
|
||||||
@@ -228,7 +251,7 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
|
|||||||
// either `request_is_async`, or `headers` and `data` MUST be defined by this point!
|
// either `request_is_async`, or `headers` and `data` MUST be defined by this point!
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1] + "<br><br>The interpreter said:<br><pre>" + e.toString() + "</pre>";
|
data = errpage[1] + "<br><br>The interpreter said:<br><pre>" + e.toString() + "</pre>";
|
||||||
console.error(" * Scripting error:",e);
|
console.error(" * Scripting error:",e);
|
||||||
@@ -236,12 +259,12 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
|
|||||||
if (!request_is_async) {
|
if (!request_is_async) {
|
||||||
if (!service_vault_found) {
|
if (!service_vault_found) {
|
||||||
console.error(" * Could not find a Service Vault for " + service_name + ":/" + service_path.replace(service_name + path.sep, ""));
|
console.error(" * Could not find a Service Vault for " + service_name + ":/" + service_path.replace(service_name + path.sep, ""));
|
||||||
var errpage = doErrorPage(404, null, socket.minisrv_pc_mode);
|
var errpage = wtvshared.doErrorPage(404, null, socket.minisrv_pc_mode);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
}
|
}
|
||||||
if (headers == null && !request_is_async) {
|
if (headers == null && !request_is_async) {
|
||||||
var errpage = doErrorPage(400, null, socket.minisrv_pc_mode);
|
var errpage = wtvshared.doErrorPage(400, null, socket.minisrv_pc_mode);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
console.error(" * Scripting or Data error: Headers were not defined. (headers,data) as follows:")
|
console.error(" * Scripting or Data error: Headers were not defined. (headers,data) as follows:")
|
||||||
@@ -316,7 +339,7 @@ async function processURL(socket, request_headers) {
|
|||||||
shortURL_split.shift();
|
shortURL_split.shift();
|
||||||
var shortURL_service_path = shortURL_split.join(":");
|
var shortURL_service_path = shortURL_split.join(":");
|
||||||
shortURL = shortURL_service_name + ":/" + shortURL_service_path;
|
shortURL = shortURL_service_name + ":/" + shortURL_service_path;
|
||||||
} else if (shortURL.indexOf(":") == -1 && request_headers.request.indexOf("HTTP/1") > 0) {
|
} else if (shortURL.indexOf(":") == -1 && request_headers.request.indexOf("HTTP/1") > 0 && socket.ssid == null) {
|
||||||
if (request_headers.Host) {
|
if (request_headers.Host) {
|
||||||
if (minisrv_config.config.pc_server_hidden_service_enabled) {
|
if (minisrv_config.config.pc_server_hidden_service_enabled) {
|
||||||
// browsers typically send a Host header
|
// browsers typically send a Host header
|
||||||
@@ -329,7 +352,7 @@ async function processURL(socket, request_headers) {
|
|||||||
} else {
|
} else {
|
||||||
// minimal pc mode to send error
|
// minimal pc mode to send error
|
||||||
socket.minisrv_pc_mode = true;
|
socket.minisrv_pc_mode = true;
|
||||||
var errpage = doErrorPage(401, "PC services are disabled on this server", socket.minisrv_pc_mode);
|
var errpage = wtvshared.doErrorPage(401, "PC services are disabled on this server", socket.minisrv_pc_mode);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1]
|
data = errpage[1]
|
||||||
socket_sessions[socket.id].close_me = true;
|
socket_sessions[socket.id].close_me = true;
|
||||||
@@ -356,7 +379,7 @@ async function processURL(socket, request_headers) {
|
|||||||
}
|
}
|
||||||
// assume webtv since there is a :/ in the GET
|
// assume webtv since there is a :/ in the GET
|
||||||
var service_name = shortURL.split(':/')[0];
|
var service_name = shortURL.split(':/')[0];
|
||||||
var urlToPath = service_name + path.sep + shortURL.split(':/')[1];
|
var urlToPath = wtvshared.fixPathSlashes(service_name + path.sep + shortURL.split(':/')[1]);
|
||||||
if (minisrv_config.config.debug_flags.show_headers) console.log(" * Incoming headers on socket ID", socket.id, (await wtvshared.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;
|
socket_sessions[socket.id].request_headers = request_headers;
|
||||||
processPath(socket, urlToPath, request_headers, service_name);
|
processPath(socket, urlToPath, request_headers, service_name);
|
||||||
@@ -364,7 +387,7 @@ async function processURL(socket, request_headers) {
|
|||||||
doHTTPProxy(socket, request_headers);
|
doHTTPProxy(socket, request_headers);
|
||||||
} else {
|
} else {
|
||||||
// error reading headers (no request_url provided)
|
// error reading headers (no request_url provided)
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1]
|
data = errpage[1]
|
||||||
socket_sessions[socket.id].close_me = true;
|
socket_sessions[socket.id].close_me = true;
|
||||||
@@ -465,11 +488,11 @@ async function doHTTPProxy(socket, request_headers) {
|
|||||||
});
|
});
|
||||||
}).on('error', function (err) {
|
}).on('error', function (err) {
|
||||||
var errpage, headers, data = null;
|
var errpage, headers, data = null;
|
||||||
if (err.code == "ENOTFOUND") errpage = doErrorPage(400, `The publisher ${request_data.host} is unknown.`);
|
if (err.code == "ENOTFOUND") errpage = wtvshared.doErrorPage(400, `The publisher ${request_data.host} is unknown.`);
|
||||||
else if (err.message.indexOf("HostUnreachable") > 0) errpage = doErrorPage(400, `The publisher ${request_data.host} could not be reached.`);
|
else if (err.message.indexOf("HostUnreachable") > 0) errpage = wtvshared.doErrorPage(400, `The publisher ${request_data.host} could not be reached.`);
|
||||||
else {
|
else {
|
||||||
console.log(" * Unhandled Proxy Request Error:", err);
|
console.log(" * Unhandled Proxy Request Error:", err);
|
||||||
errpage = doErrorPage(400);
|
errpage = wtvshared.doErrorPage(400);
|
||||||
}
|
}
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
@@ -521,7 +544,18 @@ function headerStringToObj(headers, response = false) {
|
|||||||
headers_obj.http_response = d.replace("\r", "");
|
headers_obj.http_response = d.replace("\r", "");
|
||||||
} else if (/^(GET |PUT |POST)$/.test(d.substring(0, 4)) && !response) {
|
} else if (/^(GET |PUT |POST)$/.test(d.substring(0, 4)) && !response) {
|
||||||
headers_obj.request = d.replace("\r", "");
|
headers_obj.request = d.replace("\r", "");
|
||||||
headers_obj.request_url = decodeURI(d.split(' ')[1]).replace("\r", "");
|
var request_url = d.split(' ');
|
||||||
|
if (request_url.length > 2) {
|
||||||
|
request_url.shift();
|
||||||
|
request_url = request_url.join(" ");
|
||||||
|
if (request_url.indexOf("HTTP/") > 0) {
|
||||||
|
var index = request_url.indexOf(" HTTP/");
|
||||||
|
request_url = request_url.substring(0, index);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
request_url = request_url[1];
|
||||||
|
}
|
||||||
|
headers_obj.request_url = decodeURI(request_url).replace("\r", "");
|
||||||
} else if (d.indexOf(":") > 0) {
|
} else if (d.indexOf(":") > 0) {
|
||||||
var d_split = d.split(':');
|
var d_split = d.split(':');
|
||||||
var header_name = d_split[0];
|
var header_name = d_split[0];
|
||||||
@@ -578,7 +612,7 @@ async function sendToClient(socket, headers_obj, data) {
|
|||||||
if (socket_sessions[socket.id]) {
|
if (socket_sessions[socket.id]) {
|
||||||
if (socket_sessions[socket.id].request_headers) {
|
if (socket_sessions[socket.id].request_headers) {
|
||||||
if (socket_sessions[socket.id].request_headers.service_file_path) {
|
if (socket_sessions[socket.id].request_headers.service_file_path) {
|
||||||
if (wtvshared.getFileExt(socket_sessions[socket.id].request_headers.service_file_path).toLowerCase() !== "js") {
|
if (wtvshared.getFileExt(socket_sessions[socket.id].request_headers.service_file_path).toLowerCase() !== "js" || socket_sessions[socket.id].request_headers.raw_file === true) {
|
||||||
var last_modified = wtvshared.getFileLastModifiedUTCString(socket_sessions[socket.id].request_headers.service_file_path);
|
var last_modified = wtvshared.getFileLastModifiedUTCString(socket_sessions[socket.id].request_headers.service_file_path);
|
||||||
if (last_modified) headers_obj["Last-Modified"] = last_modified;
|
if (last_modified) headers_obj["Last-Modified"] = last_modified;
|
||||||
}
|
}
|
||||||
@@ -836,7 +870,7 @@ function checkSecurity(socket) {
|
|||||||
if (blacklist) console.log(" * Request from SSID", wtvshared.filterSSID(ssid), "(" + socket.remoteAddr + "), but that SSID is in the blacklist, rejecting.");
|
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.");
|
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.");
|
var errpage = wtvshared.doErrorPage(401, "Access to this service is denied.");
|
||||||
out = errpage;
|
out = errpage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,7 +976,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
|||||||
var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2));
|
var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2));
|
||||||
if (enc_data.sigBytes > 0) {
|
if (enc_data.sigBytes > 0) {
|
||||||
if (!socket_sessions[socket.id].wtvsec) {
|
if (!socket_sessions[socket.id].wtvsec) {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
headers += "wtv-visit: client:relog\n";
|
headers += "wtv-visit: client:relog\n";
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
@@ -1010,7 +1044,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
|||||||
if (!ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
if (!ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
||||||
ssid_sessions[socket.ssid].data_store.wtvsec_login = new WTVSec(minisrv_config);
|
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.IssueChallenge();
|
||||||
ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(headers["wtv-incarnation"]);
|
if (headers["wtv-incarnation"]) 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.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.DecodeTicket(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64);
|
||||||
} else {
|
} else {
|
||||||
@@ -1018,7 +1052,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
|||||||
if (minisrv_config.config.debug_flags.debug) 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.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.DecodeTicket(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64);
|
||||||
ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(headers["wtv-incarnation"]);
|
if (headers["wtv-incarnation"]) ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(headers["wtv-incarnation"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1077,7 +1111,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
|||||||
if (minisrv_config.config.debug_flags.show_headers) console.log(secure_headers);
|
if (minisrv_config.config.debug_flags.show_headers) console.log(secure_headers);
|
||||||
if (!secure_headers.request) {
|
if (!secure_headers.request) {
|
||||||
socket_sessions[socket.id].secure = false;
|
socket_sessions[socket.id].secure = false;
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
sendToClient(socket, headers, data);
|
sendToClient(socket, headers, data);
|
||||||
@@ -1138,7 +1172,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
|||||||
processURL(socket, headers);
|
processURL(socket, headers);
|
||||||
} else 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)) {
|
||||||
// got too much data ? ... should not ever reach this code (section 2)
|
// got too much data ? ... should not ever reach this code (section 2)
|
||||||
var errpage = doErrorPage(400, "Received too much data in POST request<br>Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length) + " (2)";
|
var errpage = wtvshared.doErrorPage(400, "Received too much data in POST request<br>Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length) + " (2)";
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
sendToClient(socket, headers, data);
|
sendToClient(socket, headers, data);
|
||||||
@@ -1220,7 +1254,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
|||||||
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_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);
|
socket.setTimeout(minisrv_config.config.socket_timeout * 1000);
|
||||||
// got too much data ? ... should not ever reach this code
|
// got too much data ? ... should not ever reach this code
|
||||||
var errpage = doErrorPage(400, "Received too much data in POST request<br>Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length);
|
var errpage = wtvshared.doErrorPage(400, "Received too much data in POST request<br>Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length);
|
||||||
headers = errpage[0];
|
headers = errpage[0];
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
sendToClient(socket, headers, data);
|
sendToClient(socket, headers, data);
|
||||||
@@ -1238,7 +1272,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
|||||||
var enc_data = CryptoJS.enc.Hex.parse(data_hex);
|
var enc_data = CryptoJS.enc.Hex.parse(data_hex);
|
||||||
if (enc_data.sigBytes > 0) {
|
if (enc_data.sigBytes > 0) {
|
||||||
if (!socket_sessions[socket.id].wtvsec) {
|
if (!socket_sessions[socket.id].wtvsec) {
|
||||||
var errpage = doErrorPage(400);
|
var errpage = wtvshared.doErrorPage(400);
|
||||||
var headers = errpage[0];
|
var headers = errpage[0];
|
||||||
headers += "wtv-visit: client:relog\n";
|
headers += "wtv-visit: client:relog\n";
|
||||||
data = errpage[1];
|
data = errpage[1];
|
||||||
@@ -1330,6 +1364,7 @@ async function cleanupSocket(socket) {
|
|||||||
async function handleSocket(socket) {
|
async function handleSocket(socket) {
|
||||||
// create unique socket id with client address and port
|
// create unique socket id with client address and port
|
||||||
socket.id = parseInt(crc16('CCITT-FALSE', Buffer.from(String(socket.remoteAddress) + String(socket.remotePort), "utf8")).toString(16), 16);
|
socket.id = parseInt(crc16('CCITT-FALSE', Buffer.from(String(socket.remoteAddress) + String(socket.remotePort), "utf8")).toString(16), 16);
|
||||||
|
socket.ssid = null;
|
||||||
socket_sessions[socket.id] = [];
|
socket_sessions[socket.id] = [];
|
||||||
socket.minisrv_pc_mode = false;
|
socket.minisrv_pc_mode = false;
|
||||||
socket.setEncoding('hex'); //set data encoding (Text: 'ascii', 'utf8' ~ Binary: 'hex', 'base64' (do not trust 'binary' encoding))
|
socket.setEncoding('hex'); //set data encoding (Text: 'ascii', 'utf8' ~ Binary: 'hex', 'base64' (do not trust 'binary' encoding))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"service_ip": "0.0.0.0",
|
"service_ip": "127.0.0.1",
|
||||||
"ServiceVaults": [
|
"ServiceVaults": [
|
||||||
"UserServiceVault",
|
"UserServiceVault",
|
||||||
"ServiceVault"
|
"ServiceVault"
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"post_data_socket_timeout": 30,
|
"post_data_socket_timeout": 30,
|
||||||
"error_log_file": "errors.log",
|
"error_log_file": "errors.log",
|
||||||
"catchall_file_name": "catchall.js",
|
"catchall_file_name": "catchall.js",
|
||||||
"enable_lzpf_compression": false,
|
"enable_lzpf_compression": true,
|
||||||
"enable_gzip_compression": true,
|
"enable_gzip_compression": true,
|
||||||
"pc_server_hidden_service": "http_pc",
|
"pc_server_hidden_service": "http_pc",
|
||||||
"pc_server_hidden_service_enabled": false,
|
"pc_server_hidden_service_enabled": false,
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
"flags": "0x00000040",
|
"flags": "0x00000040",
|
||||||
"debug": false,
|
"debug": false,
|
||||||
"use_zefie_server": true,
|
"use_zefie_server": true,
|
||||||
"bf0app_default_rom": "content/artemis-webtv-000/build7181/daily-nondebug/bf0app-part000.rom",
|
"bf0app_default_rom": "content/artemis-webtv-000/build7588/daily-nondebug/bf0app-part000.rom",
|
||||||
"catchall_file_name": "content-serve.js"
|
"catchall_file_name": "content-serve.js"
|
||||||
},
|
},
|
||||||
"wtv-setup": {
|
"wtv-setup": {
|
||||||
|
|||||||
14
zefie_wtvp_minisrv/package-lock.json
generated
14
zefie_wtvp_minisrv/package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "zefie_wtvp_minisrv",
|
"name": "zefie_wtvp_minisrv",
|
||||||
"version": "0.9.18",
|
"version": "0.9.20",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -36,9 +36,9 @@
|
|||||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||||
},
|
},
|
||||||
"crypto-js": {
|
"crypto-js": {
|
||||||
"version": "4.0.0",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
|
||||||
"integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg=="
|
"integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
|
||||||
},
|
},
|
||||||
"data-uri-to-buffer": {
|
"data-uri-to-buffer": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
@@ -444,9 +444,9 @@
|
|||||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||||
},
|
},
|
||||||
"vm2": {
|
"vm2": {
|
||||||
"version": "3.9.3",
|
"version": "3.9.5",
|
||||||
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.5.tgz",
|
||||||
"integrity": "sha512-smLS+18RjXYMl9joyJxMNI9l4w7biW8ilSDaVRvFBDwOH8P0BK1ognFQTpg0wyQ6wIKLTblHJvROW692L/E53Q=="
|
"integrity": "sha512-LuCAHZN75H9tdrAiLFf030oW7nJV5xwNMuk1ymOZwopmuK3d2H4L1Kv4+GFHgarKiLfXXLFU+7LDABHnwOkWng=="
|
||||||
},
|
},
|
||||||
"word-wrap": {
|
"word-wrap": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "zefie_wtvp_minisrv",
|
"name": "zefie_wtvp_minisrv",
|
||||||
"version": "0.9.19",
|
"version": "0.9.21",
|
||||||
"description": "WebTV Service (WTVP) Emulation Server",
|
"description": "WebTV Service (WTVP) Emulation Server",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"homepage": "https://github.com/zefie/zefie_wtvp_minisrv",
|
"homepage": "https://github.com/zefie/zefie_wtvp_minisrv",
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"url": "https://github.com/zefie/zefie_wtvp_minisrv.git"
|
"url": "https://github.com/zefie/zefie_wtvp_minisrv.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"crypto-js": "^4.0.0",
|
"crypto-js": "^4.1.1",
|
||||||
"easy-crc": "0.0.2",
|
"easy-crc": "0.0.2",
|
||||||
"endianness": "^8.0.2",
|
"endianness": "^8.0.2",
|
||||||
"mime-types": "^2.1.31",
|
"mime-types": "^2.1.31",
|
||||||
|
|||||||
Reference in New Issue
Block a user