v0.9.13
- wtv-cookie support - further development will be in dev branch (may rebase alot) - compression not yet ready, leave it disabled - update: do not delete WTVSec on last socket, instead recreate on prereg - update: clean up SSID session data only if client is not seen for 3 minutes - update: add shouldWeCompress() function - update: tweak lzpf (still corrupted) - update: rename wtv-setup:/get to wtv-setup:/get-settings - update: add additional headers to wtv-setup:/get-settings - update: add initial blank wtv-music:/get-playlist - update wtv-tricks system - Info now shows Guest Mode or Subscriber Info - Implemented wtv-tricks:/unregister - Implemented wtv-tricks:/register - Show correct link in wtv-tricks:/tricks based on Guest Mode status - config.json: enable compression by default - WTVP does not use \r, so swapping the internal header's usage for now. May remove internal header in future update - lzpf: this doesn't fix anything but doesn't break it more either :) - renamed some functions - fixed some param documentation - added ConvertToBuffer function - WTVSec Updates - optimize WordArray to Buffer functions - update documentation in WTVSec - update WTVSec barrowed function in WTVLzpf - removed NewRC4Session, was a pointless alias to SecureOn
This commit is contained in:
16
README.md
16
README.md
@@ -11,21 +11,27 @@ This open source server is in alpha status. Use at your own risk.
|
||||
- Suports `.js` service files with synchronous or asynchronous requests
|
||||
- Supports multiple simultaneous users
|
||||
- WebTV-compatible HTTP(S) Proxy (via minisrv, or using an external proxy for enhanced features (such as [WebOne](https://github.com/atauenis/webone))
|
||||
- WebTV Cookie (wtv-cookie) support for HTTP(s)
|
||||
- Flashrom flashing support for all known units (including bf0app 'Old Classic')
|
||||
- Can flash anything on [Ultra Willies](https://wtv.zefie.com/willie.php) with optional `use_zefie_server` flag set on `wtv-flashrom` service.
|
||||
- `wtv-update:/sync` for Download-o-Rama style file downloading
|
||||
- Custom Tellyscripts *(not yet customizable though)*
|
||||
- Flat file client session store and registration system
|
||||
|
||||
### Current issues:
|
||||
- Satellite Receiver units reportedly cannot surf with http or https proxy.
|
||||
- wtv-cookie implementation is still partial
|
||||
- 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:
|
||||
- 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
|
||||
- ~~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:
|
||||
- wtv-lzpf support
|
||||
- TellyScript generation and/or manipulation (needed for Name Server configuration)
|
||||
- wtv-lzpf support *(Milestone v1.0)*
|
||||
- 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)***
|
||||
- ~~Flashrom flashing for bf0app old classic~~ ***Done [v0.9.9](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.9.9)***
|
||||
- ~~SSID/IP black/whitelisting (including tying SSID to an IP or multiple IPs)~~ ***Done [v0.9.4](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.9.4)***
|
||||
- ~~Flashrom flashing functionality (at least for LC2 and higher)~~ ***Done [v0.8.0](https://github.com/zefie/zefie_wtvp_minisrv/releases/tag/v0.8.0)***
|
||||
@@ -49,4 +55,4 @@ This open source server is in alpha status. Use at your own risk.
|
||||
- [Report Bugs](https://github.com/zefie/zefie_wtvp_minisrv/issues)
|
||||
- [Add a Feature and send a Pull Request](https://github.com/zefie/zefie_wtvp_minisrv/pulls)
|
||||
- Write and submit better documentation than I created (see Pull Request above)
|
||||
- [Support financially on Patreon](https://www.patreon.com/zefie)
|
||||
- [Support financially on Patreon](https://www.patreon.com/zefie)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
FROM alpine:latest
|
||||
FROM node:current-alpine
|
||||
|
||||
RUN apk add git nodejs npm
|
||||
RUN apk add git
|
||||
RUN cd /opt && git clone --depth=1 https://github.com/zefie/zefie_wtvp_minisrv.git minisrv
|
||||
RUN cd /opt/minisrv && git config pull.ff only
|
||||
RUN cd /opt/minisrv/zefie_wtvp_minisrv && npm install
|
||||
|
||||
COPY ./run.sh /opt/minisrv/zefie_wtvp_minisrv/run.sh
|
||||
|
||||
@@ -17,7 +17,11 @@ If an absolute path (`wtv-url:/`, `file://` url, or `http(s)://` url) is not pas
|
||||
```
|
||||
"post_debug": true
|
||||
```
|
||||
If you would like to see debug information about realtime bytes received from a client POST request, set `post_debug` to true.
|
||||
If you would like to see debug information about realtime bytes received from a client POST request, set `post_debug` to `true`.
|
||||
```
|
||||
"allow_guests": false
|
||||
```
|
||||
If you would like to require registration, disabling guest mode, you can set `allow_guests` to `false`. Default is `true`;
|
||||
```
|
||||
"post_percentages": [ 0, 25, 50, 100]
|
||||
```
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
var gourl = "wtv-head-waiter:/login?";
|
||||
var gourl = "wtv-head-waiter:/login?";
|
||||
|
||||
if (socket.ssid) {
|
||||
if (ssid_sessions[socket.ssid].loadSessionData() == true) {
|
||||
console.log(" * Loaded session data from disk for", filterSSID(socket.ssid))
|
||||
ssid_sessions[socket.ssid].setSessionData("registered", (ssid_sessions[socket.ssid].getSessionData("registered") == true) ? true : false);
|
||||
if (socket.ssid) {
|
||||
if (ssid_sessions[socket.ssid].loadSessionData() == true) {
|
||||
console.log(" * Loaded session data from disk for", filterSSID(socket.ssid))
|
||||
ssid_sessions[socket.ssid].setSessionData("registered", (ssid_sessions[socket.ssid].getSessionData("registered") == true) ? true : false);
|
||||
} else {
|
||||
ssid_sessions[socket.ssid].session_data = {};
|
||||
ssid_sessions[socket.ssid].setSessionData("registered", false);
|
||||
}
|
||||
if (ssid_sessions[socket.ssid].data_store) {
|
||||
if (ssid_sessions[socket.ssid].data_store.sockets) {
|
||||
var i = 0;
|
||||
ssid_sessions[socket.ssid].data_store.sockets.forEach(function (k) {
|
||||
if (typeof k != "undefined") {
|
||||
if (k != socket) {
|
||||
k.destroy();
|
||||
ssid_sessions[socket.ssid].data_store.sockets.delete(k);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (i > 0 && zdebug) console.log(" # Closed", i, "previous sockets for", filterSSID(socket.ssid));
|
||||
}
|
||||
}
|
||||
if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
||||
if (zdebug) console.log(" # Recreating primary WTVSec login instance for", filterSSID(socket.ssid));
|
||||
delete ssid_sessions[socket.ssid].data_store.wtvsec_login;
|
||||
}
|
||||
|
||||
ssid_sessions[socket.ssid].data_store.wtvsec_login = new WTVSec();
|
||||
ssid_sessions[socket.ssid].data_store.wtvsec_login.IssueChallenge();
|
||||
ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(request_headers["wtv-incarnation"] || 1);
|
||||
} else {
|
||||
ssid_sessions[socket.ssid].session_data = {};
|
||||
ssid_sessions[socket.ssid].setSessionData("registered", false);
|
||||
console.log(" * Something bad happened (we don't know the client ssid???)");
|
||||
var errpage = doErrorPage(400)
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
}
|
||||
if (ssid_sessions[socket.ssid].data_store) {
|
||||
if (ssid_sessions[socket.ssid].data_store.sockets) {
|
||||
var i = 0;
|
||||
ssid_sessions[socket.ssid].data_store.sockets.forEach(function (k) {
|
||||
if (typeof k != "undefined") {
|
||||
if (k != socket) {
|
||||
k.destroy();
|
||||
ssid_sessions[socket.ssid].data_store.sockets.delete(k);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (i > 0 && zdebug) console.log(" # Closed", i, "previous sockets for", filterSSID(socket.ssid));
|
||||
}
|
||||
}
|
||||
if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
||||
if (zdebug) console.log(" # Recreating primary WTVSec login instance for", filterSSID(socket.ssid));
|
||||
delete ssid_sessions[socket.ssid].data_store.wtvsec_login;
|
||||
}
|
||||
|
||||
ssid_sessions[socket.ssid].data_store.wtvsec_login = new WTVSec();
|
||||
ssid_sessions[socket.ssid].data_store.wtvsec_login.IssueChallenge();
|
||||
ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(request_headers["wtv-incarnation"] || 1);
|
||||
} else {
|
||||
console.log(" * Something bad happened (we don't know the client ssid???)");
|
||||
var errpage = doErrorPage(400)
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
}
|
||||
|
||||
if (request_headers.query.relogin && ssid_sessions[socket.ssid].getSessionData("registered")) gourl += "relogin=true";
|
||||
if (request_headers.query.reconnect && ssid_sessions[socket.ssid].getSessionData("registered")) gourl += "reconnect=true";
|
||||
if (request_headers.query.relogin && ssid_sessions[socket.ssid].getSessionData("registered")) gourl += "relogin=true";
|
||||
if (request_headers.query.reconnect && ssid_sessions[socket.ssid].getSessionData("registered")) gourl += "reconnect=true";
|
||||
|
||||
if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
||||
var prereg_contype = "text/html";
|
||||
@@ -53,11 +53,11 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
||||
var file_path = null;
|
||||
var bf0app_update = false;
|
||||
var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
|
||||
var send_tellyscripts = (minisrv_config.services[service_name].send_tellyscripts && !request_headers.query.relogin);
|
||||
var send_tellyscript = (minisrv_config.services[service_name].send_tellyscripts && !request_headers.query.relogin);
|
||||
var wtv_script_id = parseInt(ssid_sessions[socket.ssid].get("wtv-script-id"));
|
||||
var bootrom = ssid_sessions[socket.ssid].get("wtv-client-bootrom-version");
|
||||
if ((request_headers.query.reconnect || request_headers.query.relogin) && wtv_script_id != 0) send_tellyscripts = false;
|
||||
if (send_tellyscripts) {
|
||||
var bootrom = ssid_sessions[socket.ssid].get("wtv-client-bootrom-version");
|
||||
if ((request_headers.query.reconnect || request_headers.query.relogin) && wtv_script_id != 0) send_tellyscript = false;
|
||||
if (send_tellyscript) {
|
||||
if (minisrv_config.services[service_name].send_tellyscript_ssid_whitelist) {
|
||||
var send_telly_to_ssid = (minisrv_config.services[service_name].send_tellyscript_ssid_whitelist.findIndex(element => element == socket.ssid) != -1)
|
||||
if (send_telly_to_ssid) {
|
||||
@@ -101,7 +101,7 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!request_headers['wtv-client-rom-type'] && bootrom == "105") {
|
||||
// assume old classic in flash mode, override user setting and send tellyscript
|
||||
// because it is required to proceed in flash mode
|
||||
@@ -110,17 +110,23 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
||||
var bf0app_update = true;
|
||||
ssid_sessions[socket.ssid].set("bf0app_update", bf0app_update);
|
||||
}
|
||||
|
||||
|
||||
if (request_headers["wtv-ticket"] && !request_headers.query.reconnect) {
|
||||
gourl = "wtv-head-waiter:/login-stage-two?relogin=true";
|
||||
}
|
||||
|
||||
if (request_headers.query.reconnect) {
|
||||
gourl = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_path != null && !zquiet) console.log(" * Sending TellyScript", file_path, "on socket", socket.id);
|
||||
|
||||
if (request_headers.query.guest_login) {
|
||||
send_tellyscript = false;
|
||||
gourl += "&guest_login=true"
|
||||
if (request_headers.query.skip_splash) gourl += "&skip_splash=true";
|
||||
}
|
||||
|
||||
headers = "200 OK\n"
|
||||
if (bf0app_update) headers += "minisrv-use-carriage-return: false\n";
|
||||
headers += "Connection: Keep-Alive\n";
|
||||
@@ -134,10 +140,14 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
||||
|
||||
if (bf0app_update) headers += getServiceString('wtv-star', { "no_star_word": true }) + "\n";
|
||||
else headers += getServiceString('wtv-star') + "\n";
|
||||
if (request_headers.query.reconnect && !ssid_sessions[socket.ssid].session_data.registered) headers += getServiceString('wtv-register') + "\n";
|
||||
if (request_headers.query.reconnect && !ssid_sessions[socket.ssid].getSessionData("registered")) headers += getServiceString('wtv-register') + "\n";
|
||||
headers += getServiceString('wtv-flashrom') + "\n";
|
||||
if (bf0app_update) headers += "wtv-boot-url: " + gourl + "\n";
|
||||
else headers += "wtv-boot-url: wtv-1800:/preregister?relogin=true\n";
|
||||
else {
|
||||
headers += "wtv-boot-url: wtv-1800:/preregister?relogin=true";
|
||||
if (request_headers.query.guest_login) headers += "&guest_login=true";
|
||||
headers += "\n";
|
||||
}
|
||||
if (gourl != null) headers += "wtv-visit: " + gourl + "\n";
|
||||
if (!bf0app_update && ssid_sessions[socket.ssid].get("wtv-open-access")) headers += "wtv-open-isp-disabled: false\n";
|
||||
headers += "wtv-client-time-zone: GMT -0000\n";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
if (socket.ssid) {
|
||||
if (request_headers.post_data) {
|
||||
if (ssid_sessions[socket.ssid]) {
|
||||
ssid_sessions[socket.ssid].addCookie(cookie_data);
|
||||
ssid_sessions[socket.ssid].addCookie(request_headers.query.domain,request_headers.query.path,request_headers.query.expires,request_headers.query.cookie);
|
||||
headers = "200 OK\n";
|
||||
headers += "Content-Type: text/html";
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ if (request_headers.post_data) {
|
||||
if (request_headers.query.domain && request_headers.query.path) {
|
||||
if (socket.ssid) {
|
||||
if (ssid_sessions[socket.ssid]) {
|
||||
|
||||
data = ssid_sessions[socket.ssid].getCookieString(unescape(request_headers.query.domain), unescape(request_headers.query.path));
|
||||
data = ssid_sessions[socket.ssid].getCookieString(request_headers.query.domain, request_headers.query.path);
|
||||
headers = "200 OK\n";
|
||||
headers += "Content-Type: text/plain";
|
||||
}
|
||||
|
||||
25
zefie_wtvp_minisrv/ServiceVault/wtv-cookie/reset.js
Normal file
25
zefie_wtvp_minisrv/ServiceVault/wtv-cookie/reset.js
Normal file
@@ -0,0 +1,25 @@
|
||||
if (socket.ssid) {
|
||||
if (ssid_sessions[socket.ssid]) {
|
||||
ssid_sessions[socket.ssid].resetCookies();
|
||||
headers = "200 OK\n";
|
||||
headers += "Content-Type: text/html";
|
||||
data = `<html>
|
||||
<head>
|
||||
<display fontsize=medium>
|
||||
<title>Cookies cleared!</title>
|
||||
<meta http-equiv=Refresh content="3; url=client:goback?">
|
||||
</head>
|
||||
<body bgcolor="#000000" text="gold" link="gold" alink="gold" vlink="gold">
|
||||
<br><br>
|
||||
Your cookies have successfully been cleared!<br>
|
||||
Redirecting shortly... <a href="client:goback">Go Back</a>
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
}
|
||||
|
||||
if (!headers) {
|
||||
var errpage = doErrorPage(400)
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
}
|
||||
@@ -11,7 +11,7 @@ var default_build_to_send = minisrv_config.services[service_name].bf0app_default
|
||||
|
||||
var request_path = "";
|
||||
var bf0app_update = true;
|
||||
if (request_headers.query.path) request_path = unescape(request_headers.query.path);
|
||||
if (request_headers.query.path) request_path = request_headers.query.path;
|
||||
else request_path = default_build_to_send;
|
||||
|
||||
if (ssid_sessions[socket.ssid].get("wtv-client-rom-type") == "bf0app" && ssid_sessions[socket.ssid].get("wtv-client-bootrom-version") == "105") {
|
||||
@@ -22,7 +22,7 @@ if (ssid_sessions[socket.ssid].get("wtv-client-rom-type") == "bf0app" && ssid_se
|
||||
}
|
||||
|
||||
if (!ssid_sessions[socket.ssid].data_store.WTVFlashrom) {
|
||||
ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, bf0app_update);
|
||||
ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, bf0app_update, minisrv_config.services[service_name].debug);
|
||||
}
|
||||
|
||||
ssid_sessions[socket.ssid].data_store.WTVFlashrom.getFlashRom(request_path, function (data, headers) {
|
||||
|
||||
@@ -2,7 +2,7 @@ const WTVFlashrom = require("./WTVFlashrom.js");
|
||||
request_is_async = true;
|
||||
|
||||
var bf0app_update = false;
|
||||
var request_path = unescape(request_headers.query.path);
|
||||
var request_path = request_headers.query.path;
|
||||
var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
|
||||
var bootver = ssid_sessions[socket.ssid].get("wtv-client-bootrom-version")
|
||||
|
||||
@@ -15,7 +15,7 @@ if ((romtype == "bf0app" || !romtype) && (bootver == "105" || !bootver)) {
|
||||
|
||||
if (request_headers.query.raw || bf0app_update) {
|
||||
if (!ssid_sessions[socket.ssid].data_store.WTVFlashrom) {
|
||||
ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, bf0app_update);
|
||||
ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, bf0app_update, minisrv_config.services[service_name].debug);
|
||||
}
|
||||
|
||||
ssid_sessions[socket.ssid].data_store.WTVFlashrom.getFlashRom(request_path, function (data, headers) {
|
||||
|
||||
@@ -8,8 +8,8 @@ if (!request_headers.query.path) {
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
} else {
|
||||
var wtvflashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server);
|
||||
var request_path = unescape(request_headers.query.path);
|
||||
var wtvflashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, minisrv_config.services[service_name].debug);
|
||||
var request_path = request_headers.query.path;
|
||||
|
||||
// read flashrom header info into array using WTVFlashrom class
|
||||
wtvflashrom.getFlashromMeta(request_path, function (data) {
|
||||
|
||||
@@ -11,7 +11,7 @@ var default_build_to_send = minisrv_config.services[service_name].bf0app_default
|
||||
|
||||
var request_path = "";
|
||||
var bf0app_update = true;
|
||||
if (request_headers.query.path) request_path = unescape(request_headers.query.path);
|
||||
if (request_headers.query.path) request_path = request_headers.query.path;
|
||||
else request_path = default_build_to_send;
|
||||
|
||||
if (ssid_sessions[socket.ssid].get("wtv-client-rom-type") == "bf0app" && ssid_sessions[socket.ssid].get("wtv-client-bootrom-version") == "105") {
|
||||
@@ -22,7 +22,7 @@ if (ssid_sessions[socket.ssid].get("wtv-client-rom-type") == "bf0app" && ssid_se
|
||||
}
|
||||
|
||||
if (!ssid_sessions[socket.ssid].data_store.WTVFlashrom) {
|
||||
ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(service_vaults, service_name, 0, minisrv_config.services[service_name].use_zefie_server, bf0app_update);
|
||||
ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(service_vaults, service_name, 0, minisrv_config.services[service_name].use_zefie_server, bf0app_update, minisrv_config.services[service_name].debug);
|
||||
}
|
||||
|
||||
ssid_sessions[socket.ssid].data_store.WTVFlashrom.getFlashRom(request_path, function (data, headers) {
|
||||
|
||||
@@ -12,39 +12,33 @@ if (socket.ssid != null && !ssid_sessions[socket.ssid].get("wtvsec_login")) {
|
||||
|
||||
if (socket.ssid !== null) {
|
||||
if (wtvsec_login.ticket_b64 == null) {
|
||||
if (request_headers["wtv-ticket"]) {
|
||||
if (request_headers["wtv-ticket"].length > 8) {
|
||||
wtvsec_login.DecodeTicket(request_headers["wtv-ticket"]);
|
||||
wtvsec_login.ticket_b64 = request_headers["wtv-ticket"];
|
||||
challenge_response = wtvsec_login.challenge_response;
|
||||
var client_challenge_response = request_headers["wtv-challenge-response"] || null;
|
||||
if (challenge_response && client_challenge_response) {
|
||||
if (challenge_response.toString(CryptoJS.enc.Base64) == client_challenge_response) {
|
||||
console.log(" * wtv-challenge-response success for " + filterSSID(socket.ssid));
|
||||
wtvsec_login.PrepareTicket();
|
||||
|
||||
} else {
|
||||
console.log(" * wtv-challenge-response FAILED for " + filterSSID(socket.ssid));
|
||||
if (zdebug) console.log("Response Expected:", challenge_response.toString(CryptoJS.enc.Base64));
|
||||
if (zdebug) console.log("Response Received:", client_challenge_response)
|
||||
gourl = "wtv-head-waiter:/login?reissue_challenge=true";
|
||||
}
|
||||
} else {
|
||||
challenge_response = wtvsec_login.challenge_response;
|
||||
var client_challenge_response = request_headers["wtv-challenge-response"] || null;
|
||||
if (challenge_response && client_challenge_response) {
|
||||
if (challenge_response.toString(CryptoJS.enc.Base64) == client_challenge_response) {
|
||||
console.log(" * wtv-challenge-response success for " + filterSSID(socket.ssid));
|
||||
wtvsec_login.PrepareTicket();
|
||||
if (!ssid_sessions[socket.ssid].getSessionData("registered")) gourl = "wtv-register:/splash";
|
||||
|
||||
} else {
|
||||
console.log(" * wtv-challenge-response FAILED for " + filterSSID(socket.ssid));
|
||||
if (zdebug) console.log("Response Expected:", challenge_response.toString(CryptoJS.enc.Base64));
|
||||
if (zdebug) console.log("Response Received:", client_challenge_response)
|
||||
gourl = "wtv-head-waiter:/login?reissue_challenge=true";
|
||||
}
|
||||
} else {
|
||||
gourl = "wtv-head-waiter:/login?no_response=true";
|
||||
}
|
||||
gourl = "wtv-head-waiter:/login?no_response=true";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ssid_sessions[socket.ssid].getSessionData("registered") && (!request_headers.query.guest_login || !minisrv_config.config.allow_guests)) gourl = "wtv-register:/splash";
|
||||
|
||||
if (gourl) {
|
||||
headers = `200 OK
|
||||
Connection: Close
|
||||
wtv-open-isp-disabled: false
|
||||
`;
|
||||
if (!ssid_sessions[socket.ssid].session_data.registered && !request_headers.query.guest_mode) {
|
||||
if (!ssid_sessions[socket.ssid].getSessionData("registered") && (!request_headers.query.guest_login || !minisrv_config.config.allow_guests)) {
|
||||
headers += `wtv-encrypted: true
|
||||
wtv-ticket: ${wtvsec_login.ticket_b64}
|
||||
${getServiceString('wtv-register')}
|
||||
@@ -58,14 +52,15 @@ Content-type: text/html`;
|
||||
data = '';
|
||||
}
|
||||
else {
|
||||
if (request_headers.query.guest_mode) {
|
||||
if (request_headers.query.guest_login && minisrv_config.config.allow_guests) {
|
||||
var namerand = Math.floor(Math.random() * 100000);
|
||||
var nickname = (minisrv_config.config.service_name + '_' + namerand)
|
||||
var human_name = nickname;
|
||||
var userid = '1' + Math.floor(Math.random() * 1000000000000000000);
|
||||
var messenger_enabled = 0;
|
||||
var messenger_authorized = 0;
|
||||
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 if (!ssid_sessions[socket.ssid].getSessionData("registered")) {
|
||||
var errpage = doErrorPage(400);
|
||||
headers = errpage[0];
|
||||
@@ -99,7 +94,7 @@ wtv-messenger-authorized: ${messenger_authorized}
|
||||
wtv-messenger-enable: ${messenger_enabled}
|
||||
wtv-noback-all: wtv-
|
||||
wtv-service: reset
|
||||
`+ getServiceString('all', { "exceptions": ["wtv-register"] } ) + `
|
||||
`+ getServiceString('all', { "exceptions": ["wtv-register"] }) + `
|
||||
user-id: ${userid}
|
||||
wtv-human-name: ${human_name}
|
||||
${ssid_sessions[socket.ssid].setIRCNick(nickname)}
|
||||
@@ -111,15 +106,36 @@ wtv-input-timeout: 14400
|
||||
wtv-connection-timeout: 90
|
||||
wtv-fader-timeout: 900
|
||||
wtv-smartcard-inserted-message: Contacting service
|
||||
user-id: ${userid}
|
||||
wtv-transition-override: off
|
||||
wtv-allow-dsc: true
|
||||
wtv-messenger-enable: 0
|
||||
wtv-noback-all: wtv-
|
||||
wtv-service: reset
|
||||
`+ getServiceString('all') + `
|
||||
wtv-boot-url: wtv-1800:/preregister?relogin=true
|
||||
wtv-human-name: ${nickname}
|
||||
${ssid_sessions[socket.ssid].setIRCNick(nickname)}
|
||||
wtv-home-url: wtv-home:/home?`
|
||||
if (ssid_sessions[socket.ssid].get('wtv-need-upgrade') != 'true' && !request_headers.query.reconnect) {
|
||||
headers += "\nwtv-settings-url: wtv-setup:/get-settings";
|
||||
}
|
||||
headers += `
|
||||
wtv-domain: wtv.zefie.com
|
||||
wtv-inactive-timeout: 0
|
||||
wtv-connection-timeout: 90
|
||||
wtv-show-time-enabled: true
|
||||
wtv-fader-timeout: 900
|
||||
wtv-tourist-enabled: true
|
||||
wtv-boot-url: wtv-1800:/preregister?relogin=true
|
||||
wtv-allow-dsc: true
|
||||
wtv-home-url: wtv-home:/home?
|
||||
`
|
||||
wtv-tourist-enabled: true`
|
||||
headers += "\nwtv-relogin-url: wtv-1800:/preregister?relogin=true";
|
||||
if (request_headers.query.guest_login) headers += "&guest_login=true";
|
||||
headers += "\nwtv-reconnect-url: wtv-1800:/preregister?reconnect=true";
|
||||
if (request_headers.query.guest_login) headers += "&guest_login=true";
|
||||
headers += "\nwtv-boot-url: wtv-1800:/preregister?relogin=true";
|
||||
if (request_headers.query.guest_login) headers += "&guest_login=true";
|
||||
headers += "\nwtv-allow-dsc: true";
|
||||
headers += "\nwtv-home-url: wtv-home:/home?";
|
||||
|
||||
if (ssid_sessions[socket.ssid].get('wtv-need-upgrade') != 'true' && !request_headers.query.reconnect) {
|
||||
headers += "\nwtv-settings-url: wtv-setup:/get";
|
||||
}
|
||||
|
||||
@@ -2,7 +2,14 @@ var challenge_response, challenge_header = "";
|
||||
|
||||
var gourl = "wtv-head-waiter:/login-stage-two?";
|
||||
if (request_headers.query.relogin) gourl += "relogin=true";
|
||||
if (request_headers.query.reconnect) gourl += "reconnect=true";
|
||||
else if (request_headers.query.reconnect) gourl += "reconnect=true";
|
||||
|
||||
if (request_headers.query.guest_login) {
|
||||
if (request_headers.query.relogin || request_headers.query.reconnect) gourl += "&";
|
||||
gourl += "guest_login=true";
|
||||
if (request_headers.query.skip_splash) gourl += "&skip_splash=true";
|
||||
}
|
||||
|
||||
var send_to_relogin = true;
|
||||
|
||||
if (socket.ssid) {
|
||||
|
||||
@@ -4,7 +4,7 @@ wtv-expire-all: wtv-home:/splash
|
||||
wtv-expire-all: wtv-flashrom:
|
||||
Content-type: text/html`
|
||||
|
||||
if (request_headers.query.url) headers += "\nwtv-visit: " + unescape(request_headers.query.url);
|
||||
if (request_headers.query.url) headers += "\nwtv-visit: " + request_headers.query.url;
|
||||
|
||||
if (ssid_sessions[socket.ssid].get('box-does-psuedo-encryption')) {
|
||||
var cryptstatus = "<a href='client:showalert?message=Your%20WebTV%20Unit%20sent%20us%20a%20request%20for%20SECURE%20ON%2C%20but%20did%20not%20encrypt%20any%20data%2C%20nor%20will%20accept%20it.%20However%2C%20we%20send%20the%20wtv-encryption%20flag%20to%20roll%20with%20it%2C%20enabling%20%27psuedo-encryption%27.%20Nothing%20is%20encrypted%2C%20but%20the%20box%20trusts%20us.%20This%20will%20probably%20go%20away%20if%20you%20reload%20or%20change%20pages.&buttonaction1=client:donothing&buttonlabel1=Oh%2C%20okay...'>Psuedo-encrypted</a>";
|
||||
@@ -24,7 +24,10 @@ function go() {
|
||||
location.href=document.access.url.value;
|
||||
}
|
||||
</script>
|
||||
<h4>Welcome to `+ z_title + `</h4>
|
||||
<b>Welcome to `+ z_title + `</b><br>
|
||||
`;
|
||||
if (minisrv_config.config.git_commit) data += "<small><i>" + " ".repeat(32) + "git revision " + minisrv_config.config.git_commit + "</i></small><br>";
|
||||
data += `
|
||||
<b>Encryption Status</b>: ${cryptstatus}<br>
|
||||
<b>Connection Speed</b>: &rate;
|
||||
<p>
|
||||
@@ -53,7 +56,7 @@ if (ssid_sessions[socket.ssid].hasCap("client-can-do-javascript")) {
|
||||
data += `<li><input name=url `;
|
||||
|
||||
if (request_headers.query.url) {
|
||||
data += "value='" + unescape(request_headers.query.url) + "'";
|
||||
data += "value='" + request_headers.query.url + "'";
|
||||
}
|
||||
|
||||
data += `width=250 height=10 bgcolor=#444444 text=#ffdd33 cursor=#cc9933>
|
||||
|
||||
@@ -24,9 +24,7 @@ data = `<html>
|
||||
Mini service
|
||||
<tr><td>
|
||||
zefie minisrv v${minisrv_config.version}`;
|
||||
if (getGitRevision()) {
|
||||
data += " (git " + getGitRevision().substring(0, 8) + ")";
|
||||
}
|
||||
if (minisrv_config.config.git_commit) data += " (git " + minisrv_config.config.git_commit + ")";
|
||||
data += `
|
||||
<tr><td>&rate;
|
||||
</table>
|
||||
|
||||
@@ -15,7 +15,7 @@ Content-length: 0`;
|
||||
|
||||
var logdata_outstring = '';
|
||||
Object.keys(request_headers.query).forEach(function (k) {
|
||||
logdata_outstring += k + "=" + unescape(request_headers.query[k].toString()) + "\r\n";
|
||||
logdata_outstring += k + "=" + request_headers.query[k].toString() + "\r\n";
|
||||
});
|
||||
logdata_outstring += "\r\n";
|
||||
var logdata_outstring_hex = Buffer.from(logdata_outstring, 'utf8').toString('hex');
|
||||
@@ -36,7 +36,7 @@ Content-length: 0`;
|
||||
|
||||
var logdata_outstring = '';
|
||||
Object.keys(request_headers.query).forEach(function (k) {
|
||||
logdata_outstring += k + "=" + unescape(request_headers.query[k].toString()) + "\r\n";
|
||||
logdata_outstring += k + "=" + request_headers.query[k].toString() + "\r\n";
|
||||
});
|
||||
var logdata_outstring_hex = Buffer.from(logdata_outstring, 'utf8').toString('hex');
|
||||
if (minisrv_config.services[service_name].write_logs_to_disk) {
|
||||
|
||||
@@ -31,4 +31,6 @@ wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/underground/renegad
|
||||
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/moods/affectionate.rmf
|
||||
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/moods/sociable.rmf`;
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
data = '';
|
||||
|
||||
26
zefie_wtvp_minisrv/ServiceVault/wtv-register/BeMyGuest.js
Normal file
26
zefie_wtvp_minisrv/ServiceVault/wtv-register/BeMyGuest.js
Normal file
@@ -0,0 +1,26 @@
|
||||
if (minisrv_config.config.allow_guests) {
|
||||
headers = `300 Moved
|
||||
Connection: Close
|
||||
wtv-noback-all: wtv-register:
|
||||
wtv-expire-all: wtv-`;
|
||||
if (socket.ssid) {
|
||||
if (ssid_sessions[socket.ssid]) {
|
||||
if (ssid_sessions[socket.ssid].data_store) {
|
||||
if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
||||
headers += "\nwtv-ticket: " + ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
headers += `
|
||||
wtv-service: reset
|
||||
${getServiceString('wtv-1800')}
|
||||
wtv-relogin-url: wtv-1800:/preregister?guest_login=true&skip_splash=true
|
||||
wtv-reconnect-url: wtv-1800:/preregister?guest_login=true&reconnect=true
|
||||
wtv-boot-url: wtv-1800:/preregister?guest_login=true
|
||||
Location: client:relogin`;
|
||||
} else {
|
||||
var errpage = doErrorPage(400, "Guest mode is not enabled on this service.");
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
}
|
||||
@@ -10,9 +10,9 @@ if (!request_headers.query.registering) {
|
||||
if (!request_headers.query.registering) errpage = 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_username) errpage = doErrorPage(400, "Please enter a username.");
|
||||
else if (unescape(request_headers.query.subscriber_username).length < 5) errpage = doErrorPage(400, "Please choose a username with 5 or more characters.");
|
||||
else if (unescape(request_headers.query.subscriber_username).length > 16) errpage = doErrorPage(400, "Please choose a username with 16 or less characters.");
|
||||
else if (!WTVRegister.checkUsernameSanity(unescape(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 (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 > 16) errpage = doErrorPage(400, "Please choose a username with 16 or less characters.");
|
||||
else if (!WTVRegister.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 (!WTVRegister.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 (!request_headers.query.subscriber_contact) errpage = 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.");
|
||||
@@ -64,10 +64,10 @@ Review account info
|
||||
<td border=0 abswidth=40 bgcolor="#171726" rowspan="6" >
|
||||
<form ACTION="ValidateReviewAccountInfo" ENCTYPE="x-www-form-encoded" METHOD="POST">
|
||||
<input type=hidden name=registering value="true">
|
||||
<input type=hidden name=subscriber_name value="${unescape(request_headers.query.subscriber_name)}">
|
||||
<input type=hidden name=subscriber_username value="${unescape(request_headers.query.subscriber_username)}">
|
||||
<input type=hidden name=subscriber_contact value="${unescape(request_headers.query.subscriber_contact)}">
|
||||
<input type=hidden name=subscriber_contact_method value="${unescape(request_headers.query.subscriber_contact_method)}">
|
||||
<input type=hidden name=subscriber_name value="${request_headers.query.subscriber_name}">
|
||||
<input type=hidden name=subscriber_username value="${request_headers.query.subscriber_username}">
|
||||
<input type=hidden name=subscriber_contact value="${request_headers.query.subscriber_contact}">
|
||||
<input type=hidden name=subscriber_contact_method value="${request_headers.query.subscriber_contact_method}">
|
||||
<td height=50 width= 300 bgcolor="#171726" colspan=6 valign=top align=left>
|
||||
Here is your account information. If you need to<br>
|
||||
correct an item, press <b>Back</b>.
|
||||
@@ -76,24 +76,24 @@ correct an item, press <b>Back</b>.
|
||||
<td width=260 valign=top align=left colspan=4>
|
||||
<table cellspacing=0 cellpadding=0 border=0 >
|
||||
<img src="images/arrow.gif"> <font size=-2><b>NAME</b></font><br>
|
||||
<tt><font color=#d1d3d3 size=-2><spacer type=horizontal size=17> ${unescape(request_headers.query.subscriber_name)}</font></tt></a>
|
||||
<tt><font color=#d1d3d3 size=-2><spacer type=horizontal size=17> ${request_headers.query.subscriber_name}</font></tt></a>
|
||||
</table>
|
||||
<p>
|
||||
<table cellspacing=0 cellpadding=0 border=0>
|
||||
<img src="images/arrow.gif"> <font size=-2><b>CONTACT</b></font><br>
|
||||
<tt><font color=#d1d3d3 size=-2><spacer type=horizontal size=17> ${unescape(request_headers.query.subscriber_contact)}</font></tt></a>
|
||||
<tt><font color=#d1d3d3 size=-2><spacer type=horizontal size=17> ${request_headers.query.subscriber_contact}</font></tt></a>
|
||||
</table>
|
||||
</TD>
|
||||
<td abswidth=200 bgcolor=#171726 valign=top align=left>
|
||||
<table cellspacing=0 cellpadding=0 border=0> <TR><TD>
|
||||
<img src="images/arrow.gif"><font size=-2> <b>USERNAME</b></font><br>
|
||||
<tr><td maxlines=1 >
|
||||
<tt><font color=#d1d3d3><spacer type=horizontal size=17>${unescape(request_headers.query.subscriber_name)}</font></tt></a>
|
||||
<tt><font color=#d1d3d3><spacer type=horizontal size=17>${request_headers.query.subscriber_name}</font></tt></a>
|
||||
</table>
|
||||
<p>
|
||||
<table cellspacing=0 cellpadding=0 border=0>
|
||||
<img src="images/arrow.gif"> <font size=-2><b>CONTACT TYPE</b></font><br>
|
||||
<tt><font color=#d1d3d3 size=-2><spacer type=horizontal size=17>${unescape(request_headers.query.subscriber_contact_method)}</font></tt>
|
||||
<tt><font color=#d1d3d3 size=-2><spacer type=horizontal size=17>${request_headers.query.subscriber_contact_method}</font></tt>
|
||||
</table> <P> <P>
|
||||
<td abswidth=20 bgcolor=#171726 >
|
||||
</tr>
|
||||
|
||||
@@ -11,10 +11,10 @@ if (!request_headers.query.registering ||
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
} else {
|
||||
ssid_sessions[socket.ssid].setSessionData("subscriber_name", unescape(request_headers.query.subscriber_name));
|
||||
ssid_sessions[socket.ssid].setSessionData("subscriber_username", unescape(request_headers.query.subscriber_username));
|
||||
ssid_sessions[socket.ssid].setSessionData("subscriber_contact", unescape(request_headers.query.subscriber_contact));
|
||||
ssid_sessions[socket.ssid].setSessionData("subscriber_contact_method", unescape(request_headers.query.subscriber_contact_method));
|
||||
ssid_sessions[socket.ssid].setSessionData("subscriber_name", request_headers.query.subscriber_name);
|
||||
ssid_sessions[socket.ssid].setSessionData("subscriber_username", request_headers.query.subscriber_username);
|
||||
ssid_sessions[socket.ssid].setSessionData("subscriber_contact", request_headers.query.subscriber_contact);
|
||||
ssid_sessions[socket.ssid].setSessionData("subscriber_contact_method", request_headers.query.subscriber_contact_method);
|
||||
ssid_sessions[socket.ssid].setSessionData("subscriber_userid", '1' + Math.floor(Math.random() * 1000000000000000000));
|
||||
ssid_sessions[socket.ssid].setSessionData("registered", true);
|
||||
if (!ssid_sessions[socket.ssid].storeSessionData()) {
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
if (request_headers.query.noreg) {
|
||||
headers = `302 Moved
|
||||
Connection: Close
|
||||
wtv-noback-all: wtv-register:
|
||||
wtv-expire-all: wtv-
|
||||
wtv-open-isp-disabled: false
|
||||
wtv-visit: wtv-head-waiter:/login-stage-two?guest_mode=true
|
||||
Location: wtv-head-waiter:/login-stage-two?guest_mode=true
|
||||
Content-type: text/html`;
|
||||
} else if (!request_headers.query.registering) {
|
||||
if (!request_headers.query.registering) {
|
||||
var errpage = doErrorPage(400);
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
|
||||
@@ -59,11 +59,13 @@ The next screens will lead you through a quick setup process for using this serv
|
||||
var namerand = Math.floor(Math.random() * 100000);
|
||||
var nickname = (minisrv_config.config.service_name + '_' + namerand)
|
||||
var human_name = nickname;
|
||||
data += `
|
||||
data += `
|
||||
<shadow>
|
||||
<input type=button action="ValidateAgreement?registering=true&subscriber_name=${human_name}&subscriber_username=${nickname}" Value="Quick Reg" name="speedyreg" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=130>
|
||||
<input type=button action="ValidateWelcome" Value="Sign in as Guest" name="noreg" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=170>
|
||||
<input type=submit Value=Continue name="Continue" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=110 selected>
|
||||
`;
|
||||
if (minisrv_config.config.allow_guests) data += `<input type=button action="BeMyGuest" Value="Sign in as Guest" name="noreg" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=170 >`;
|
||||
|
||||
data += `<input type=submit Value=Continue name="Continue" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=110 selected>
|
||||
</shadow>
|
||||
</font>
|
||||
</form> <td abswidth=13 absheight=50 bgcolor=#171726>
|
||||
|
||||
@@ -24,9 +24,7 @@ data = `<html>
|
||||
Mini service
|
||||
<tr><td>
|
||||
zefie minisrv v${minisrv_config.version}`;
|
||||
if (getGitRevision()) {
|
||||
data += " (git " + getGitRevision().substring(0, 8) + ")";
|
||||
}
|
||||
if (minisrv_config.config.git_commit) data += " (git " + minisrv_config.config.git_commit + ")";
|
||||
data += `
|
||||
<tr><td>&rate;
|
||||
</table>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Allow URL access outside our trusted minisrv
|
||||
|
||||
if (request_headers.query.url) var url = unescape(request_headers.query.url);
|
||||
if (request_headers.query.url) var url = request_headers.query.url;
|
||||
else var url = "client:showalert?message=Please%20provide%20a%20%3Furl%3D%20with%20the%20url%20you%20would%20like%20to%20access.&buttonlabel1=Okay&buttonacction1=client:donothing"
|
||||
|
||||
headers = `200 OK
|
||||
|
||||
@@ -6,7 +6,7 @@ Content-type: text/html`
|
||||
var visit_url = null;
|
||||
|
||||
if (request_headers.Referer) visit_url = request_headers.Referer;
|
||||
else if (request_headers.query.return_to) visit_url = unescape(request_headers.query.return_to);
|
||||
else if (request_headers.query.return_to) visit_url = request_headers.query.return_to;
|
||||
else visit_url = "client:goback";
|
||||
|
||||
data = `<html>
|
||||
|
||||
@@ -50,6 +50,10 @@ Content-Type: text/html`
|
||||
<td valign=top align=right><shadow>Connected to:</shadow>
|
||||
<td width=10>
|
||||
<td valign=top>Mini Service
|
||||
<tr>
|
||||
<td valign=top align=right><shadow>Host/Port:</shadow>
|
||||
<td width=10>
|
||||
<td valign=top>${service_ip}/${minisrv_config.services[service_name].port}
|
||||
<tr>
|
||||
<td valign=top align=right width=150><shadow>Service:</shadow>
|
||||
<td width=10>
|
||||
@@ -76,11 +80,28 @@ Content-Type: text/html`
|
||||
<td valign=top align=right><shadow>Client IP number:</shadow>
|
||||
<td width=10>
|
||||
<td valign=top>${socket.remoteAddress}
|
||||
<tr>
|
||||
<td valign=top align=right><shadow>Service IP number:</shadow>
|
||||
`;
|
||||
if (ssid_sessions[socket.ssid].getSessionData("registered")) {
|
||||
data += `<tr>
|
||||
<td valign=top align=right><shadow>Subscriber Name:</shadow>
|
||||
<td width=10>
|
||||
<td valign=top>${service_ip}
|
||||
<td valign=top>${ssid_sessions[socket.ssid].getSessionData("subscriber_name")}
|
||||
<tr>
|
||||
<td valign=top align=right><shadow>Subscriber Username:</shadow>
|
||||
<td width=10>
|
||||
<td valign=top>${ssid_sessions[socket.ssid].getSessionData("subscriber_username")}
|
||||
<tr>
|
||||
<td valign=top align=right><shadow>Subscriber Contact:</shadow>
|
||||
<td width=10>
|
||||
<td valign=top>${ssid_sessions[socket.ssid].getSessionData("subscriber_contact")} (${ssid_sessions[socket.ssid].getSessionData("subscriber_contact_method")})`;
|
||||
} else {
|
||||
data += `<tr>
|
||||
<td valign=top align=right><shadow>Unregistered Guest:</shadow>
|
||||
<td width=10>
|
||||
<td valign=top>Yes`;
|
||||
}
|
||||
|
||||
data += `<tr>
|
||||
<td height=20>
|
||||
<tr>
|
||||
<td valign=top align=right><shadow>ROM type:</shadow>
|
||||
@@ -106,7 +127,7 @@ Content-Type: text/html`
|
||||
<tr>
|
||||
<td valign=top align=right><shadow>SysConfig:</shadow>
|
||||
<td width=10>
|
||||
<td valign=top>0x${wtv_system_sysconfig_hex.toUpperCase()}
|
||||
<td valign=top>0x${wtv_system_sysconfig_hex}
|
||||
</table>
|
||||
|
||||
<table>
|
||||
|
||||
39
zefie_wtvp_minisrv/ServiceVault/wtv-tricks/register.js
Normal file
39
zefie_wtvp_minisrv/ServiceVault/wtv-tricks/register.js
Normal file
@@ -0,0 +1,39 @@
|
||||
headers = `200 OK
|
||||
Content-Type: text/html`;
|
||||
|
||||
if (ssid_sessions[socket.ssid].getSessionData("registered")) {
|
||||
var redirect = [10, "client:goback?"];
|
||||
var message = "Error: Your box is already registered. If you would like to re-register, you must first unregister.";
|
||||
} else if (request_headers.query.confirm_register) {
|
||||
headers += `
|
||||
wtv-noback-all: wtv-
|
||||
wtv-expire-all: wtv-
|
||||
wtv-relogin-url: wtv-1800:/preregister?relogin=true
|
||||
wtv-reconnect-url: wtv-1800:/preregister?reconnect=true
|
||||
wtv-boot-url: wtv-1800:/preregister?relogin=true`;
|
||||
var redirect = [3, "client:relog?"];
|
||||
var message = "You will now be be redirected to registration.<br><br>";
|
||||
message += `<a href="${redirect[1]}">Click here if you are not automatically redirected.</a>`;
|
||||
} else {
|
||||
message = `Are you ready to register your box with ${minisrv_config.config.service_name}?
|
||||
<br><br>
|
||||
<form action="register" method="POST" ENCTYPE="x-www-form-encoded">
|
||||
<input type="button" action="client:goback" value="Nah, I like being a Guest" borderimage="file://ROM/Borders/ButtonBorder2.bif" text="#dadada" >
|
||||
<input type="submit" name="confirm_register" value="Yes, I'm ready to register!" borderimage="file://ROM/Borders/ButtonBorder2.bif" text="#dadada" selected>
|
||||
</form>`;
|
||||
}
|
||||
|
||||
data = `<html>
|
||||
<head>
|
||||
<display fontsize=medium>
|
||||
<title>Comfy Zone!</title>
|
||||
`;
|
||||
if (redirect) data += `<meta http-equiv=Refresh content="${redirect[0]}; url=${redirect[1]}">`;
|
||||
|
||||
data += `</head>
|
||||
<body bgcolor="#202020" text="#dadada" link="#dadada" alink="#dadada" vlink="#dadada">
|
||||
<br><br>
|
||||
${message}
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
@@ -38,7 +38,11 @@ data = `<html>
|
||||
<tr>
|
||||
<td><a href="client:showservices">Show Services</a>
|
||||
<td width = 25>
|
||||
<td><a href="wtv-tricks:/unregister">Unregister This Box</a>
|
||||
`;
|
||||
if (ssid_sessions[socket.ssid].getSessionData("registered")) data += `<td><a href="wtv-tricks:/unregister">Unregister This Box</a>`;
|
||||
else data += `<td><a href="wtv-tricks:/register">Register This Box</a>`
|
||||
|
||||
data += `
|
||||
<tr>
|
||||
<td colspan=3 height=6>
|
||||
<tr>
|
||||
|
||||
42
zefie_wtvp_minisrv/ServiceVault/wtv-tricks/unregister.js
Normal file
42
zefie_wtvp_minisrv/ServiceVault/wtv-tricks/unregister.js
Normal file
@@ -0,0 +1,42 @@
|
||||
headers = `200 OK
|
||||
Content-Type: text/html`;
|
||||
|
||||
if (!ssid_sessions[socket.ssid].getSessionData("registered")) {
|
||||
var redirect = [10, "client:goback?"];
|
||||
var message = "Error: Your box is not registered. You are accessing " + minisrv_config.config.service_name + " in Guest Mode. There is nothing to delete!";
|
||||
} else if (request_headers.query.confirm_unregister) {
|
||||
if (ssid_sessions[socket.ssid].unregisterBox()) {
|
||||
headers += "\nwtv-noback-all: wtv-";
|
||||
headers += "\nwtv-expire-all: wtv-";
|
||||
var redirect = [3, "client:relog?"];
|
||||
var message = "Your account data has been successfully removed. You will now be be redirected to registration.<br><br>";
|
||||
message += `<a href="${redirect[1]}">Click here if you are not automatically redirected.</a>`;
|
||||
} else {
|
||||
var redirect = [10, "client:goback?"];
|
||||
var message = "There was an error deleting your account data. Please try again later. If the problem persists, please contact " + minisrv_config.config.service_owner + " to request manual deletion.";
|
||||
message += "SSID verifcation may be required to perform a manual deletion.< br > <br>Returning from whence you came...<br><br>";
|
||||
message += `<a href="${redirect[1]}">Click here if you are not automatically redirected.</a>`;
|
||||
}
|
||||
} else {
|
||||
message = `Are you sure you wish to unregister your account? Session Data deleted by this tool is unrecoverable, even by ${minisrv_config.config.service_owner}.
|
||||
Please be absolutely sure this is what you want to do!<br><br>
|
||||
<form action="unregister" method="POST" ENCTYPE="x-www-form-encoded">
|
||||
<input type="button" action="client:goback" value="No, I changed my mind" borderimage="file://ROM/Borders/ButtonBorder2.bif" text="gold" selected>
|
||||
<input type="submit" name="confirm_unregister" value="Yes, delete my account" borderimage="file://ROM/Borders/ButtonBorder2.bif" text="gold">
|
||||
</form>`;
|
||||
}
|
||||
|
||||
data = `<html>
|
||||
<head>
|
||||
<display fontsize=medium>
|
||||
<title>Danger Zone!</title>
|
||||
`;
|
||||
if (redirect) data += `<meta http-equiv=Refresh content="${redirect[0]}; url=${redirect[1]}">`;
|
||||
|
||||
data += `</head>
|
||||
<body bgcolor="#000000" text="gold" link="gold" alink="gold" vlink="gold">
|
||||
<br><br>
|
||||
${message}
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
@@ -77,9 +77,23 @@ class WTVClientSessionData {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.session_store.cookies[this.countCookies()] = Object.assign({}, cookie_data);
|
||||
this.storeSessionData();
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var cookie_index = -1;
|
||||
// see if we have a cookie for this domain/path
|
||||
Object.keys(this.session_store.cookies).forEach(function (k) {
|
||||
if (cookie_index >= 0) return;
|
||||
if (domain == self.session_store.cookies[k].domain && path == self.session_store.cookies[k].path) cookie_index = k;
|
||||
});
|
||||
// otherwise add a new one
|
||||
if (cookie_index == -1) cookie_index = this.countCookies();
|
||||
|
||||
this.session_store.cookies[cookie_index] = Object.assign({}, cookie_data);
|
||||
|
||||
// do not write file if user is not registered
|
||||
if (getSessionData('registered')) this.storeSessionData();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -92,8 +106,8 @@ class WTVClientSessionData {
|
||||
if (self.session_store['cookies'][k].domain == domain &&
|
||||
self.session_store['cookies'][k].path == path) {
|
||||
|
||||
var current_epoch_utc = Math.floor(Date.toUTCString().getTime() / 1000);
|
||||
var cookie_expires_epoch_utc = Math.floor(Date.Parse(self.session_store['cookies'][k].expires).toUTCString().getTime());
|
||||
var current_epoch_utc = Date.parse((new Date()).toUTCString());
|
||||
var cookie_expires_epoch_utc = Date.parse(new Date(Date.parse(self.session_store['cookies'][k].expires)).toUTCString());
|
||||
if (cookie_expires_epoch_utc <= current_epoch_utc) self.deleteCookie(self.session_store['cookies'][k]);
|
||||
else result = self.session_store['cookies'][k];
|
||||
}
|
||||
@@ -103,11 +117,14 @@ class WTVClientSessionData {
|
||||
|
||||
getCookieString(domain, path) {
|
||||
var cookie_data = this.getCookie(domain, path);
|
||||
var outstring = "";
|
||||
/*
|
||||
var outstring = "";
|
||||
Object.keys(cookie_data).forEach(function (k) {
|
||||
outstring += k + "=" + escape(cookie_data[k]) + "&";
|
||||
});
|
||||
return outstring.substring(0, outstring.length - 1);
|
||||
*/
|
||||
return cookie_data.cookie;
|
||||
}
|
||||
|
||||
deleteCookie(domain, path = null) {
|
||||
@@ -197,6 +214,19 @@ class WTVClientSessionData {
|
||||
}
|
||||
|
||||
|
||||
unregisterBox() {
|
||||
try {
|
||||
if (this.fs.lstatSync(this.session_storage + this.path.sep + this.ssid + ".json")) {
|
||||
return this.fs.unlinkSync(this.session_storage + this.path.sep + this.ssid + ".json");
|
||||
this.session_store = {};
|
||||
}
|
||||
} catch (e) {
|
||||
// Don't log error 'file not found', it just means the client isn't registered yet
|
||||
if (e.code != "ENOENT") console.error(" # Error deleting session data for", this.filterSSID(this.ssid), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
hasCap(cap) {
|
||||
if (this.capabilities) {
|
||||
return this.capabilities[cap] || false;
|
||||
|
||||
@@ -14,9 +14,35 @@ class WTVFlashrom {
|
||||
this.service_name = service_name;
|
||||
this.use_zefie_server = use_zefie_server;
|
||||
this.bf0app_update = bf0app_update;
|
||||
this.zdebug = debug;
|
||||
this.zdebug = true;
|
||||
}
|
||||
|
||||
|
||||
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, callback, info_only = false) {
|
||||
// use local flashrom files;
|
||||
console.log(info_only);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
/**
|
||||
* Pure-JS implementation of WebTV's LZPF compression
|
||||
*
|
||||
@@ -5,15 +7,22 @@
|
||||
* Originally reverse engineered from the box
|
||||
*
|
||||
* By: Eric MacDonald (eMac)
|
||||
* Modified By: zefie
|
||||
*/
|
||||
|
||||
class WTVLzpf {
|
||||
// Note: currentlty doesn't offer 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_literal = 0
|
||||
current_length = 0;
|
||||
current_literal = 0;
|
||||
flag = 0xFFFF;
|
||||
working_data = 0;
|
||||
match_index = 0;
|
||||
type_index = 0;
|
||||
checksum = 0;
|
||||
flag_table = new Uint16Array(0x1000)
|
||||
compressed_data = []
|
||||
ring_buffer = new Uint8Array(0x2000)
|
||||
encoded_data = [];
|
||||
|
||||
nomatchEncode = [
|
||||
[0x0000, 0x10], [0x0001, 0x10], [0x0002, 0x10],
|
||||
@@ -274,8 +283,25 @@ class WTVLzpf {
|
||||
clear() {
|
||||
this.current_length = 0;
|
||||
this.current_literal = 0;
|
||||
this.flag = 0xFFFF;
|
||||
this.working_data = 0;
|
||||
this.match_index = 0;
|
||||
this.type_index = 0;
|
||||
this.checksum = 0;
|
||||
this.ring_buffer.fill(0x00, 0, 0x2000)
|
||||
this.flag_table.fill(0xFFFF, 0, 0x1000);
|
||||
this.compressed_data = [];
|
||||
this.encoded_data = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a byte to the end of the compressed byte array. Re-allocates as needed
|
||||
*
|
||||
* @param byte {Number} char code of the byte to be added.
|
||||
*
|
||||
* @returns {undefined}
|
||||
*/
|
||||
AddByte(byte) {
|
||||
this.encoded_data.push(byte);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,8 +319,7 @@ class WTVLzpf {
|
||||
this.current_length += code_length;
|
||||
|
||||
while (this.current_length > 7) {
|
||||
//console.log("add", this.current_literal >>> 0, code >>> 0, byte, type)
|
||||
this.compressed_data.push((this.current_literal >>> 0x18) & 0xFF);
|
||||
this.AddByte((this.current_literal >>> 0x18) & 0xFF);
|
||||
|
||||
this.current_length -= 8;
|
||||
this.current_literal = (this.current_literal << 8) & 0xFFFFFFFF;
|
||||
@@ -302,74 +327,73 @@ class WTVLzpf {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress data using WebTV's Lzpf compression algorithm and adds the footer to the end.
|
||||
* Starts a compression stream
|
||||
*
|
||||
* @param uncompressed_data {String} data to compress
|
||||
*
|
||||
* @returns {Buffer} Lzpf compression data
|
||||
* @returns {undefined} Lzpf compression data
|
||||
*/
|
||||
Compress(uncompressed_data) {
|
||||
Begin() {
|
||||
this.clear();
|
||||
}
|
||||
|
||||
if (uncompressed_data.words) {
|
||||
uncompressed_data = new Buffer.from(this.wordArrayToUint8Array(uncompressed_data));
|
||||
} else {
|
||||
uncompressed_data = new Buffer.from(uncompressed_data);
|
||||
}
|
||||
|
||||
var uncompressed_len = uncompressed_data.length;
|
||||
/**
|
||||
* Encode a block of data. Used for streamed chunks.
|
||||
*
|
||||
* @param unencoded_data {Buffer} data to encode
|
||||
* @param compress_data {Boolean} compress data
|
||||
*
|
||||
* @returns {Buffer} Lzpf encoded data
|
||||
*/
|
||||
EncodeBlock(unencoded_data, compress_data) {
|
||||
this.encoded_data = [];
|
||||
var uncompressed_len = unencoded_data.byteLength;
|
||||
|
||||
var i = 0;
|
||||
var sum = 0;
|
||||
var working_data = 0;
|
||||
var flag = 0xFFFF;
|
||||
var flags_index = 0;
|
||||
var match_index = 0;
|
||||
var type_index = 0;
|
||||
while(i < uncompressed_len) {
|
||||
while (i < uncompressed_len) {
|
||||
var code_length = -1;
|
||||
var code = -1;
|
||||
|
||||
var byte = uncompressed_data.readUInt8(i);
|
||||
var byte = unencoded_data.readUInt8(i);
|
||||
this.ring_buffer[i & 0x1FFF] = byte;
|
||||
|
||||
if(match_index > 0) {
|
||||
if (byte != uncompressed_data.readUInt8(flag) || match_index > 0x0127) {
|
||||
code_length = this.matchEncode[match_index][1];
|
||||
code = this.matchEncode[match_index][0];
|
||||
match_index = 0;
|
||||
type_index = 3;
|
||||
if (this.match_index > 0) {
|
||||
if (byte != this.ring_buffer[this.flag] || this.match_index > 0x0127) {
|
||||
code_length = this.matchEncode[this.match_index][1];
|
||||
code = this.matchEncode[this.match_index][0];
|
||||
this.match_index = 0;
|
||||
this.type_index = 3;
|
||||
} else {
|
||||
match_index++;
|
||||
flag++;
|
||||
sum = (sum + byte) & 0xFFFF;
|
||||
working_data = ((working_data * 0x0100) + byte) & 0xFFFFFFFF;
|
||||
this.match_index = (this.match_index + 1) & 0x1FFF;
|
||||
this.flag = (this.flag + 1) & 0x1FFF;
|
||||
this.checksum = (this.checksum + byte) & 0xFFFF;
|
||||
this.working_data = ((this.working_data * 0x0100) + byte) & 0xFFFFFFFF;
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
flag = 0xFFFF;
|
||||
this.flag = 0xFFFF;
|
||||
|
||||
if (i >= 3) {
|
||||
flags_index = (working_data >>> 0x0B ^ working_data) & 0x0FFF;
|
||||
flag = this.flag_table[flags_index];
|
||||
this.flag_table[flags_index] = i;
|
||||
flags_index = (this.working_data >>> 0x0B ^ this.working_data) & 0x0FFF;
|
||||
this.flag = this.flag_table[flags_index];
|
||||
this.flag_table[flags_index] = i & 0x1FFF;
|
||||
} else {
|
||||
type_index++;
|
||||
this.type_index++;
|
||||
}
|
||||
|
||||
if (flag == 0xFFFF) {
|
||||
if (this.flag == 0xFFFF) {
|
||||
code_length = this.nomatchEncode[byte][1];
|
||||
code = this.nomatchEncode[byte][0] << 0x10;
|
||||
} else if (byte == uncompressed_data.readUInt8(flag)) {
|
||||
match_index = 1;
|
||||
flag++;
|
||||
type_index = 4;
|
||||
} else if (byte == this.ring_buffer[this.flag] && compress_data) {
|
||||
this.match_index = 1;
|
||||
this.flag = (this.flag + 1) & 0x1FFF;
|
||||
this.type_index = 4;
|
||||
} else {
|
||||
code_length = this.nomatchEncode[byte][1] + 1;
|
||||
code = this.nomatchEncode[byte][0] << 0x0F;
|
||||
}
|
||||
|
||||
sum = (sum + byte) & 0xFFFF;
|
||||
working_data = ((working_data * 0x0100) + byte) & 0xFFFFFFFF;
|
||||
this.checksum = (this.checksum + byte) & 0xFFFF;
|
||||
this.working_data = ((this.working_data * 0x0100) + byte) & 0xFFFFFFFF;
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -378,18 +402,32 @@ class WTVLzpf {
|
||||
}
|
||||
}
|
||||
|
||||
// Finish up. This would normally be in an Lzpf_Finish method.
|
||||
if(type_index == 2) {
|
||||
return Buffer.from(this.encoded_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends a compression stream.
|
||||
*
|
||||
* @param type_index {Number} the end type used to finalize
|
||||
*
|
||||
* @returns {Buffer} Lzpf compression data
|
||||
*/
|
||||
Finish() {
|
||||
var code_length = -1
|
||||
var code = -1
|
||||
|
||||
if (this.type_index == 2) {
|
||||
this.EncodeLiteral(0x10, 0x00990000);
|
||||
} else if(type_index >= 3) {
|
||||
if(type_index == 4) {
|
||||
code_length = this.matchEncode[match_index][1];
|
||||
code = this.matchEncode[match_index][0];
|
||||
} else if (this.type_index >= 3) {
|
||||
if (this.type_index == 4) {
|
||||
code_length = this.matchEncode[this.match_index][1];
|
||||
code = this.matchEncode[this.match_index][0];
|
||||
this.EncodeLiteral(code_length, code);
|
||||
}
|
||||
|
||||
flags_index = (working_data >>> 0x0B ^ working_data) & 0x0FFF;
|
||||
if (flags_index == 0xFFFF) {
|
||||
var flags_index = (this.working_data >>> 0x0B ^ this.working_data) & 0x0FFF;
|
||||
var flag = this.flag_table[flags_index];
|
||||
if (flag == 0xFFFF) {
|
||||
this.EncodeLiteral(0x10, 0x00990000);
|
||||
} else {
|
||||
this.EncodeLiteral(0x11, 0x004c8000);
|
||||
@@ -399,14 +437,48 @@ class WTVLzpf {
|
||||
// Below is just metadata. The compressed block is complete.
|
||||
|
||||
// Encode checksum
|
||||
this.EncodeLiteral(0x08, (sum << 0x10) & 0xFFFFFFFF);
|
||||
this.EncodeLiteral(0x08, (sum << 0x18) & 0xFFFFFFFF);
|
||||
this.EncodeLiteral(0x08, (this.checksum << 0x10) & 0xFFFFFFFF);
|
||||
this.EncodeLiteral(0x08, (this.checksum << 0x18) & 0xFFFFFFFF);
|
||||
|
||||
// End
|
||||
this.compressed_data.push(this.current_literal >>> 0x18);
|
||||
this.compressed_data.push(0x20);
|
||||
this.AddByte((this.current_literal >>> 0x18) & 0xFF);
|
||||
this.AddByte(0x20);
|
||||
}
|
||||
|
||||
return new Buffer.from(this.compressed_data);
|
||||
/**
|
||||
* Converts the data to a Javascript Buffer object
|
||||
*
|
||||
* @param data {String|Buffer|CryptoJS.lib.WordArray} Data to convert
|
||||
*
|
||||
* @returns {Buffer} Javascript Buffer object
|
||||
*/
|
||||
ConvertToBuffer(data) {
|
||||
if (data.words) {
|
||||
var WTVSec = require("./WTVSec.js");
|
||||
wtvsec = new WTVSec(1);
|
||||
data = wtvsec.wordArrayToBuffer(data);
|
||||
WTVSec, wtvsec = null;
|
||||
} else if (!data.byteLength) {
|
||||
// otherwise if its not already a Buffer, convert it to one
|
||||
data = new Buffer.from(data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress data using WebTV's Lzpf compression algorithm and adds the footer to the end.
|
||||
*
|
||||
* @param uncompressed_data {String|Buffer|CryptoJS.lib.WordArray} data to compress
|
||||
*
|
||||
* @returns {Buffer} Lzpf compression data
|
||||
*/
|
||||
Compress(uncompressed_data) {
|
||||
uncompressed_data = this.ConvertToBuffer(uncompressed_data);
|
||||
this.Begin();
|
||||
this.EncodeBlock(uncompressed_data, true);
|
||||
this.Finish();
|
||||
|
||||
return Buffer.from(this.encoded_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ class WTVRegister {
|
||||
checkUsernameAvailable(username, ssid_sessions) {
|
||||
var username_match = false;
|
||||
this.fs.readdirSync(this.session_store_dir).forEach(file => {
|
||||
if (!file.match(/.*\.json/ig)) return;
|
||||
if (username_match) return;
|
||||
try {
|
||||
var temp_session_data_file = this.fs.readFileSync(this.session_store_dir + this.path.sep + file, 'Utf8');
|
||||
|
||||
@@ -2,13 +2,14 @@ const CryptoJS = require('crypto-js');
|
||||
const endianness = require('endianness');
|
||||
var crypto = require('crypto');
|
||||
|
||||
/***********************************\
|
||||
|* Special Thanks to: *|
|
||||
|* eMac (Eric MacDonald) *|
|
||||
|* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *|
|
||||
|* For the encryption/decryption *|
|
||||
|* information and process *|
|
||||
\***********************************/
|
||||
/**
|
||||
* Javascript implementation of WTVP Security
|
||||
*
|
||||
* Special Thanks to eMac (Eric MacDonald)
|
||||
* For the encryption/decryption information and process
|
||||
*
|
||||
* By: zefie
|
||||
*/
|
||||
|
||||
class WTVSec {
|
||||
// Initial Shared Key, in Base64 Format
|
||||
@@ -32,6 +33,15 @@ class WTVSec {
|
||||
RC4Session = new Array();
|
||||
zdebug = false;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Initialize the WTVSec class.
|
||||
*
|
||||
* @param {Number} wtv_incarnation Sets the wtv-incarnation for this instance
|
||||
* @param {Boolean} zdebug Enable debugging
|
||||
*
|
||||
*/
|
||||
constructor(wtv_incarnation = 1, zdebug = false) {
|
||||
this.zdebug = zdebug;
|
||||
this.initial_shared_key = CryptoJS.enc.Base64.parse(this.initial_shared_key_b64);
|
||||
@@ -44,6 +54,11 @@ class WTVSec {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the wtv-incarnation for this instance
|
||||
*
|
||||
* @param {Number} wtv_incarnation
|
||||
*/
|
||||
set_incarnation(wtv_incarnation) {
|
||||
if (this.incarnation != wtv_incarnation) {
|
||||
this.incarnation = wtv_incarnation;
|
||||
@@ -51,14 +66,26 @@ class WTVSec {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the wtv-incaration for this instance by 1
|
||||
*/
|
||||
increment_incarnation() {
|
||||
this.set_incarnation(parseInt(this.incarnation) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones a WordArray to allow modification without referencing its original
|
||||
* @param {CryptoJS.lib.WordArray} wa
|
||||
*
|
||||
* @returns {CryptoJS.lib.WordArray}
|
||||
*/
|
||||
DuplicateWordArray(wa) {
|
||||
return CryptoJS.lib.WordArray.create(this.wordArrayToUint8Array(wa).buffer);
|
||||
return CryptoJS.lib.WordArray.create(this.wordArrayToBuffer(wa));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the wtv-ticket for this instance
|
||||
*/
|
||||
PrepareTicket() {
|
||||
// store last challenge response in ticket
|
||||
var ticket_data = this.challenge_raw;
|
||||
@@ -77,6 +104,11 @@ class WTVSec {
|
||||
return this.ticket_b64;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a wtv-ticket to set up this instance
|
||||
*
|
||||
* @param {Base64} ticket_b64
|
||||
*/
|
||||
DecodeTicket(ticket_b64) {
|
||||
var ticket_hex = CryptoJS.enc.Base64.parse(ticket_b64).toString(CryptoJS.enc.Hex);
|
||||
var challenge_key = CryptoJS.enc.Hex.parse(ticket_hex.substring(0, 16));
|
||||
@@ -95,6 +127,13 @@ class WTVSec {
|
||||
console.log(" * Decoded session from wtv-ticket");
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a wtv-challenge to get the expected response
|
||||
* @param {Base64} wtv_challenge
|
||||
* @param {any} key
|
||||
*
|
||||
* @returns {CryptoJS.lib.WordArray} wtv-challenge-response (or blank if failed)
|
||||
*/
|
||||
ProcessChallenge(wtv_challenge, key = this.current_shared_key) {
|
||||
var challenge_raw = CryptoJS.enc.Base64.parse(wtv_challenge);
|
||||
|
||||
@@ -139,7 +178,6 @@ class WTVSec {
|
||||
var challenge_response = CryptoJS.enc.Hex.parse(challenge_raw_hex.substr(0, (8 * 2))).concat(echo_encrypted.ciphertext);
|
||||
return challenge_response;
|
||||
} else {
|
||||
throw ("Couldn't solve challenge");
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
@@ -147,6 +185,11 @@ class WTVSec {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a wtv-challenge for this instance
|
||||
*
|
||||
* @returns {Base64} wtv-challenge
|
||||
*/
|
||||
IssueChallenge() {
|
||||
/*
|
||||
* bytes 0-8: Random id? Just echoed in the response
|
||||
@@ -188,41 +231,21 @@ class WTVSec {
|
||||
return challenge_b64;
|
||||
}
|
||||
|
||||
wordToByteArray(word, length) {
|
||||
var ba = [],
|
||||
i,
|
||||
xFF = 0xFF;
|
||||
if (length > 0)
|
||||
ba.push(word >>> 24);
|
||||
if (length > 1)
|
||||
ba.push((word >>> 16) & xFF);
|
||||
if (length > 2)
|
||||
ba.push((word >>> 8) & xFF);
|
||||
if (length > 3)
|
||||
ba.push(word & xFF);
|
||||
|
||||
return ba;
|
||||
/**
|
||||
* convert a CryptoJS.lib.WordArray to a Javascript Buffer
|
||||
* @param {CryptoJS.lib.WordArray} wordArray
|
||||
*
|
||||
* #returns {Buffer} JS Buffer object
|
||||
*/
|
||||
wordArrayToBuffer(wordArray) {
|
||||
return new Buffer.from(wordArray.toString(CryptoJS.enc.Hex), 'hex');
|
||||
}
|
||||
|
||||
wordArrayToUint8Array(wordArray, length = 0) {
|
||||
if (wordArray.hasOwnProperty("sigBytes") && wordArray.hasOwnProperty("words")) {
|
||||
length = wordArray.sigBytes;
|
||||
wordArray = wordArray.words;
|
||||
}
|
||||
|
||||
var result = [],
|
||||
bytes,
|
||||
i = 0;
|
||||
while (length > 0) {
|
||||
bytes = this.wordToByteArray(wordArray[i], Math.min(4, length));
|
||||
length -= bytes.length;
|
||||
result.push(bytes);
|
||||
i++;
|
||||
}
|
||||
return new Uint8Array([].concat.apply([], result));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts an encryption session
|
||||
* @param {Number} rc4session Session Type (0 = enc k1, 1 = dec k1, 3 = enc k2, 4 = dec k2, default: all)
|
||||
*
|
||||
*/
|
||||
SecureOn(rc4session = null) {
|
||||
if (this.zdebug) console.log(" # Generating RC4 sessions with wtv-incarnation: " + this.incarnation);
|
||||
|
||||
@@ -230,33 +253,37 @@ class WTVSec {
|
||||
endianness(buf, 4);
|
||||
this.hRC4_Key1 = CryptoJS.MD5(this.DuplicateWordArray(this.session_key1).concat(CryptoJS.lib.WordArray.create(buf).concat(this.DuplicateWordArray(this.session_key1))));
|
||||
this.hRC4_Key2 = CryptoJS.MD5(this.DuplicateWordArray(this.session_key2).concat(CryptoJS.lib.WordArray.create(buf).concat(this.DuplicateWordArray(this.session_key2))));
|
||||
var key1 = this.wordArrayToBuffer(this.hRC4_Key1);
|
||||
var key2 = this.wordArrayToBuffer(this.hRC4_Key2);
|
||||
switch (rc4session) {
|
||||
case 0:
|
||||
this.RC4Session[0] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)),'');
|
||||
this.RC4Session[0] = crypto.createCipheriv('rc4', key1,'');
|
||||
break;
|
||||
case 1:
|
||||
this.RC4Session[1] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)),'');
|
||||
this.RC4Session[1] = crypto.createDecipheriv('rc4', key1,'');
|
||||
break;
|
||||
case 2:
|
||||
this.RC4Session[2] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)),'');
|
||||
this.RC4Session[2] = crypto.createCipheriv('rc4', key2,'');
|
||||
break;
|
||||
case 3:
|
||||
this.RC4Session[3] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)),'');
|
||||
this.RC4Session[3] = crypto.createDecipheriv('rc4', key2,'');
|
||||
break;
|
||||
default:
|
||||
this.RC4Session[0] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)), '');
|
||||
this.RC4Session[1] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)), '');
|
||||
this.RC4Session[2] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)), '');
|
||||
this.RC4Session[3] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)), '');
|
||||
this.RC4Session[0] = crypto.createCipheriv('rc4', key1, '');
|
||||
this.RC4Session[1] = crypto.createDecipheriv('rc4', key1, '');
|
||||
this.RC4Session[2] = crypto.createCipheriv('rc4', key2, '');
|
||||
this.RC4Session[3] = crypto.createDecipheriv('rc4', key2, '');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NewRC4Session(num) {
|
||||
this.SecureOn(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* RC4 Encrypt data
|
||||
* @param {Number} keynum Which key to use (0 = k1, 1 = k2)
|
||||
* @param {CryptoJS.lib.WordArray|ArrayBuffer|Buffer} data Data to encrypt
|
||||
*
|
||||
* @returns {ArrayBuffer} Encrypted data
|
||||
*/
|
||||
Encrypt(keynum, data) {
|
||||
var session_id;
|
||||
switch (keynum) {
|
||||
@@ -271,16 +298,23 @@ class WTVSec {
|
||||
break;
|
||||
}
|
||||
if (!this.RC4Session[session_id]) {
|
||||
this.NewRC4Session(session_id);
|
||||
this.SecureOn(session_id);
|
||||
}
|
||||
if (data.words) {
|
||||
data = new Buffer.from(this.wordArrayToUint8Array(data));
|
||||
data = this.wordArrayToBuffer(data);
|
||||
} else if (data.constructor === ArrayBuffer) {
|
||||
data = new Buffer.from(data);
|
||||
}
|
||||
return this.RC4Session[session_id].update(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* RC4 Decrypt data
|
||||
* @param {Number} keynum Which key to use (0 = k1, 1 = k2)
|
||||
* @param {CryptoJS.lib.WordArray|ArrayBuffer|Buffer} data Data to decrypt
|
||||
*
|
||||
* @returns {ArrayBuffer} Decrypted data
|
||||
*/
|
||||
Decrypt(keynum, data) {
|
||||
var session_id;
|
||||
switch (keynum) {
|
||||
@@ -295,10 +329,10 @@ class WTVSec {
|
||||
break;
|
||||
}
|
||||
if (!this.RC4Session[session_id]) {
|
||||
this.NewRC4Session(session_id);
|
||||
this.SecureOn(session_id);
|
||||
}
|
||||
if (data.words) {
|
||||
data = new Buffer.from(this.wordArrayToUint8Array(data));
|
||||
data = this.wordArrayToBuffer(data);
|
||||
} else if (data.constructor === ArrayBuffer) {
|
||||
data = new Buffer.from(data);
|
||||
}
|
||||
|
||||
@@ -99,12 +99,68 @@ function doErrorPage(code, data = null) {
|
||||
|
||||
|
||||
function getConType(path) {
|
||||
// custom contype for flashrom
|
||||
if (path.indexOf("wtv-flashrom") && (getFileExt(path).toLowerCase() == "rom" || getFileExt(path).toLowerCase() == "brom")) {
|
||||
return "binary/x-wtv-flashblock";
|
||||
} else if (getFileExt(path).toLowerCase() == "rmf") {
|
||||
return "audio/x-rmf";
|
||||
var file_ext = getFileExt(path).toLowerCase();
|
||||
// process WebTV overrides, fall back to generic mime lookup
|
||||
switch (file_ext) {
|
||||
case "aif":
|
||||
return "audio/x-aif";
|
||||
case "aifc":
|
||||
return "audio/x-aifc";
|
||||
case "aiff":
|
||||
return "audio/x-aiff";
|
||||
case "ani":
|
||||
return "x-wtv-animation";
|
||||
case "brom":
|
||||
return "binary/x-wtv-bootrom";
|
||||
case "cdf":
|
||||
return "application/netcdf";
|
||||
case "dat":
|
||||
return "binary/cache-data";
|
||||
case "dl":
|
||||
return "wtv/download-list";
|
||||
case "gsm":
|
||||
return "audio/x-gsm";
|
||||
case "gz":
|
||||
return "application/gzip";
|
||||
case "ini":
|
||||
return "wtv/jack-configuration";
|
||||
case "mips-code":
|
||||
return "code/x-wtv-code-mips";
|
||||
case "o":
|
||||
return "binary/x-wtv-approm";
|
||||
case "ram":
|
||||
return "audio/x-pn-realaudio";
|
||||
case "rom":
|
||||
return "binary/x-wtv-flashblock";
|
||||
case "rsp":
|
||||
return "wtv/jack-response";
|
||||
case "swa":
|
||||
case "swf":
|
||||
return "application/x-shockwave-flash";
|
||||
case "srf":
|
||||
case "spl":
|
||||
return "wtv/jack-data";
|
||||
case "ttf":
|
||||
return "wtv/jack-fonts";
|
||||
case "tvch":
|
||||
return "wtv/tv-channels";
|
||||
case "tvl":
|
||||
return "wtv/tv-listings";
|
||||
case "tvsl":
|
||||
return "wtv/tv-smartlinks";
|
||||
case "wad":
|
||||
return "binary/doom-data";
|
||||
case "mp2":
|
||||
case "hsb":
|
||||
case "rmf":
|
||||
case "s3m":
|
||||
case "mod":
|
||||
case "xm":
|
||||
return "application/Music";
|
||||
}
|
||||
|
||||
// if we reach here, its not a WebTV specific override
|
||||
// or we are not yet aware of said override
|
||||
return mime.lookup(path);
|
||||
}
|
||||
|
||||
@@ -260,9 +316,10 @@ async function processURL(socket, request_headers) {
|
||||
if (qraw.length > 0) {
|
||||
qraw = qraw.split("&");
|
||||
for (let i = 0; i < qraw.length; i++) {
|
||||
var k = qraw[i].split("=")[0];
|
||||
if (k) {
|
||||
request_headers.query[k] = qraw[i].split("=")[1];
|
||||
var qraw_split = qraw[i].split("=");
|
||||
if (qraw_split.length == 2) {
|
||||
var k = qraw_split[0];
|
||||
request_headers.query[k] = unescape(qraw[i].split("=")[1].replace(/\+/g,"%20"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,23 +328,25 @@ async function processURL(socket, request_headers) {
|
||||
}
|
||||
|
||||
if (request_headers.post_data) {
|
||||
if (headersAreStandard(request_headers.post_data.toString(CryptoJS.enc.Utf8))) {
|
||||
if (request_headers.post_data.toString(CryptoJS.enc.Utf8).indexOf('=')) {
|
||||
if (request_headers.post_data.toString(CryptoJS.enc.Utf8).indexOf('&')) {
|
||||
var qraw = request_headers.post_data.toString(CryptoJS.enc.Utf8).split('&');
|
||||
var post_data_string = request_headers.post_data.toString(CryptoJS.enc.Utf8).replace("\0", "");
|
||||
if (isUnencryptedString(post_data_string)) {
|
||||
if (post_data_string.indexOf('=')) {
|
||||
if (post_data_string.indexOf('&')) {
|
||||
var qraw = post_data_string.split('&');
|
||||
if (qraw.length > 0) {
|
||||
for (let i = 0; i < qraw.length; i++) {
|
||||
var k = qraw[i].split("=")[0];
|
||||
if (k) {
|
||||
request_headers.query[k] = qraw[i].split("=")[1];
|
||||
var qraw_split = qraw[i].split("=");
|
||||
if (qraw_split.length == 2) {
|
||||
var k = qraw_split[0];
|
||||
request_headers.query[k] = unescape(qraw[i].split("=")[1].replace(/\+/g, "%20"));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var qraw = request_headers.post_data.toString(CryptoJS.enc.Utf8);
|
||||
var k = qraw[i].split("=")[0];
|
||||
if (k) {
|
||||
request_headers.query[k] = qraw[i].split("=")[1];
|
||||
var qraw_split = post_data_string.split("=");
|
||||
if (qraw_split.length == 2) {
|
||||
var k = qraw_split[0];
|
||||
request_headers.query[k] = unescape(qraw_split[1].replace(/\+/g, "%20"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -495,10 +554,10 @@ function headerStringToObj(headers, response = false) {
|
||||
return headers_obj;
|
||||
}
|
||||
|
||||
async function sendToClient(socket, headers_obj, data, compress_data = false) {
|
||||
var headers = "";
|
||||
var wni_style_content_length = false;
|
||||
async function sendToClient(socket, headers_obj, data) {
|
||||
var compress_data = false;
|
||||
var headers = "";
|
||||
var content_length = 0;
|
||||
if (typeof (data) === 'undefined') data = '';
|
||||
if (typeof (headers_obj) === 'string') {
|
||||
// string to header object
|
||||
@@ -517,72 +576,44 @@ async function sendToClient(socket, headers_obj, data, compress_data = false) {
|
||||
headers_obj = moveObjectElement('Connection', 'http_response', headers_obj);
|
||||
}
|
||||
|
||||
if (headers_obj['minisrv-already-compressed'] && wni_style_content_length) {
|
||||
content_length = headers_obj["Content-length"];
|
||||
} else {
|
||||
var content_length = 0;
|
||||
if (typeof data.length !== 'undefined') {
|
||||
content_length = data.length;
|
||||
} else if (typeof data.byteLength !== 'undefined') {
|
||||
content_length = data.byteLength;
|
||||
}
|
||||
var clen = 0;
|
||||
if (typeof data.length !== 'undefined') {
|
||||
clen = data.length;
|
||||
} else if (typeof data.byteLength !== 'undefined') {
|
||||
clen = data.byteLength;
|
||||
}
|
||||
|
||||
|
||||
// fix captialization of Content-Type header. May be unnecessary.
|
||||
// fix captialization
|
||||
if (headers_obj["Content-type"]) {
|
||||
headers_obj["Content-Type"] = headers_obj["Content-type"];
|
||||
delete headers_obj["Content-type"];
|
||||
}
|
||||
|
||||
/*
|
||||
// check if client reports it supports compressed data
|
||||
|
||||
// if box can do compression, see if its worth enabling
|
||||
if (ssid_sessions[socket.ssid].capabilities) {
|
||||
if (ssid_sessions[socket.ssid].capabilities['client-can-receive-compressed-data']) {
|
||||
// if the client reports it supports compression, check the Content-Type
|
||||
// of the file we are sending to see if its worth compressing
|
||||
if (ssid_sessions[socket.ssid].capabilities['client-can-receive-compressed-data'] && minisrv_config.config.enable_lzpf_compression) {
|
||||
compress_data = shouldWeCompress(headers_obj["Content-Type"]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// compress if needed, and if not already compressed
|
||||
if (compress_data && content_length > 0 && !headers_obj['minisrv-already-compressed']) {
|
||||
if (zdebug) console.log(" # Uncompressed data length:", content_length);
|
||||
// compress if needed
|
||||
if (compress_data && clen > 0) {
|
||||
content_length = clen;
|
||||
|
||||
headers_obj["wtv-lzpf"] = 0;
|
||||
|
||||
var wtvcomp = new WTVLzpf();
|
||||
// we expect the compressed data to be smaller or at most equal to the source size
|
||||
// so we set our initial buffer size to the source size
|
||||
var compressed_data = new Buffer.alloc(content_length);
|
||||
wtvcomp.on('data', (data, length, offset, complete) => {
|
||||
// put data received into buffer
|
||||
data.copy(compressed_data, offset, 0, length);
|
||||
if (complete !== false) {
|
||||
if (zdebug) console.log(" # Compressed data length:", complete);
|
||||
// now that we have all of the compressed data, copy it to a new buffer
|
||||
// of the correct length, and clean up the original buffer.
|
||||
data = new Buffer.alloc(complete);
|
||||
compressed_data.copy(data, 0, 0, compressed_data.byteLength);
|
||||
compressed_data, wtvcomp = null;
|
||||
// internal header to tell ourselves to not compress again
|
||||
headers_obj['minisrv-already-compressed'] = true;
|
||||
if (wni_style_content_length) headers_obj["Content-length"] = content_length;
|
||||
sendToClient(socket, headers_obj, data);
|
||||
}
|
||||
});
|
||||
wtvcomp.Compress(data);
|
||||
return;
|
||||
data = wtvcomp.Compress(data);
|
||||
|
||||
wtvcomp = null; // Makes the garbage gods happy so it cleans up our mess
|
||||
}
|
||||
|
||||
// clean up internal header for compression
|
||||
if (headers_obj['minisrv-already-compressed']) delete headers_obj['minisrv-already-compressed'];
|
||||
|
||||
|
||||
// encrypt if needed
|
||||
if (socket_sessions[socket.id].secure == true) {
|
||||
headers_obj["wtv-encrypted"] = 'true';
|
||||
headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj);
|
||||
if (content_length > 0 && socket_sessions[socket.id].wtvsec) {
|
||||
if (clen > 0 && socket_sessions[socket.id].wtvsec) {
|
||||
if (!zquiet) console.log(" * Encrypting response to client ...")
|
||||
var enc_data = socket_sessions[socket.id].wtvsec.Encrypt(1, data);
|
||||
data = enc_data;
|
||||
@@ -594,8 +625,14 @@ async function sendToClient(socket, headers_obj, data, compress_data = false) {
|
||||
if (headers_obj["Content-Length"]) delete headers_obj["Content-Length"];
|
||||
if (headers_obj["Content-length"]) delete headers_obj["Content-length"];
|
||||
|
||||
// On the WNI server this is the length before compression but we're using the length after compression.
|
||||
// It matches the HTTP spec anyway so leaving.
|
||||
if (content_length == 0) {
|
||||
if (typeof data.length !== 'undefined') {
|
||||
content_length = data.length;
|
||||
} else if (typeof data.byteLength !== 'undefined') {
|
||||
content_length = data.byteLength;
|
||||
}
|
||||
}
|
||||
|
||||
headers_obj["Content-length"] = content_length;
|
||||
|
||||
if (ssid_sessions[socket.ssid]) {
|
||||
@@ -610,15 +647,13 @@ async function sendToClient(socket, headers_obj, data, compress_data = false) {
|
||||
}
|
||||
}
|
||||
|
||||
// internal header to determine EOL type. bf0app upgrader does not like \r, while the rest of the WebTV world does.
|
||||
// set header 'minisrv-use-carriage-return' to true to disable \r for this specific transfer.
|
||||
var end_of_line = "\n";
|
||||
if (!headers_obj['minisrv-use-carriage-return'] || headers_obj['minisrv-use-carriage-return'] != "false") end_of_line = "\r\n";
|
||||
if (headers_obj['minisrv-use-carriage-return'] == "true") end_of_line = "\r\n";
|
||||
if (headers_obj['minisrv-use-carriage-return']) delete headers_obj['minisrv-use-carriage-return'];
|
||||
|
||||
if (end_of_line == "\n" && zdebug) console.log(" * Script requested to send headers without carriage return (bf0app hack)");
|
||||
if (end_of_line == "\r\n" && zdebug) console.log(" * Script requested to send headers with carriage return (out of WTVP Spec)");
|
||||
|
||||
// convert header object back to string
|
||||
// header object to string
|
||||
if (zshowheaders) console.log(" * Outgoing headers on socket ID", socket.id, (await filterSSID(headers_obj)));
|
||||
Object.keys(headers_obj).forEach(function (k) {
|
||||
if (k == "http_response") {
|
||||
@@ -643,7 +678,7 @@ async function sendToClient(socket, headers_obj, data, compress_data = false) {
|
||||
if (zquiet) var verbosity_mod = (headers_obj["wtv-encrypted"] == 'true') ? " encrypted response" : "";
|
||||
if (socket_sessions[socket.id].secure_headers == true) {
|
||||
// encrypt headers
|
||||
if (zquiet)verbosity_mod += " with encrypted headers";
|
||||
if (zquiet) verbosity_mod += " with encrypted headers";
|
||||
var enc_headers = socket_sessions[socket.id].wtvsec.Encrypt(1, headers + end_of_line);
|
||||
socket.write(new Uint8Array(concatArrayBuffer(enc_headers, data)));
|
||||
} else {
|
||||
@@ -660,7 +695,7 @@ async function sendToClient(socket, headers_obj, data, compress_data = false) {
|
||||
if (socket_sessions[socket.id].post_data) delete socket_sessions[socket.id].post_data;
|
||||
if (socket_sessions[socket.id].post_data_length) delete socket_sessions[socket.id].post_data_length;
|
||||
if (socket_sessions[socket.id].post_data_percents_shown) delete socket_sessions[socket.id].post_data_percents_shown;
|
||||
|
||||
|
||||
if (socket_sessions[socket.id].close_me) socket.end();
|
||||
if (headers_obj["Connection"]) {
|
||||
if (headers_obj["Connection"].toLowerCase() == "close" || wtv_connection_close == "true") {
|
||||
@@ -712,7 +747,7 @@ function moveObjectElement(currentKey, afterKey, obj) {
|
||||
if (next !== -1) return result; else return obj;
|
||||
}
|
||||
|
||||
function headersAreStandard(string, verbose = false) {
|
||||
function isUnencryptedString(string, verbose = false) {
|
||||
// a generic "isAscii" check is not sufficient, as the test will see the binary
|
||||
// compressed / encrypted data as ASCII. This function checks for characters expected
|
||||
// in unencrypted headers, and returns true only if every character in the string matches
|
||||
@@ -745,7 +780,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
||||
} else {
|
||||
data = data.split("\n\n")[0];
|
||||
}
|
||||
if (headersAreStandard(data)) {
|
||||
if (isUnencryptedString(data)) {
|
||||
if (headers.length != 0) {
|
||||
var new_header_obj = headerStringToObj(data);
|
||||
Object.keys(new_header_obj).forEach(function (k, v) {
|
||||
@@ -758,7 +793,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
||||
} else if (!skipSecure) {
|
||||
// if its a POST request, assume its a binary blob and not encrypted (dangerous)
|
||||
if (!encryptedRequest) {
|
||||
// its not a POST and it failed the headersAreStandard test, so we think this is an encrypted blob
|
||||
// its not a POST and it failed the isUnencryptedString test, so we think this is an encrypted blob
|
||||
if (socket_sessions[socket.id].secure != true) {
|
||||
// first time so reroll sessions
|
||||
if (zdebug) console.log(" # [ UNEXPECTED BINARY BLOCK ] First sign of encryption, re-creating RC4 sessions for socket id", socket.id);
|
||||
@@ -917,6 +952,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
||||
if (zdebug) console.log(" # New ticket from client");
|
||||
ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 = headers["wtv-ticket"];
|
||||
ssid_sessions[socket.ssid].data_store.wtvsec_login.DecodeTicket(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64);
|
||||
ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(headers["wtv-incarnation"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -951,7 +987,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
||||
}
|
||||
var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2));
|
||||
if (enc_data.sigBytes > 0) {
|
||||
if (headersAreStandard(enc_data.toString(CryptoJS.enc.Latin1), (!skipSecure && !encryptedRequest))) {
|
||||
if (isUnencryptedString(enc_data.toString(CryptoJS.enc.Latin1), (!skipSecure && !encryptedRequest))) {
|
||||
// some builds (like our targeted 3833), send SECURE ON but then unencrypted headers
|
||||
if (zdebug) console.log(" # Psuedo-encrypted Request (SECURE ON)", "on", socket.id);
|
||||
// don't actually encrypt output
|
||||
@@ -1028,33 +1064,34 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
||||
var post_string = "POST";
|
||||
if (socket_sessions[socket.id].secure == true) {
|
||||
post_string = "Encrypted " + post_string;
|
||||
} else {
|
||||
// if the request is not encrypted, the client may have just sent the data with the primary headers, so lets look for that.
|
||||
if (data_hex.indexOf("0d0a0d0a") != -1) socket_sessions[socket.id].post_data = data_hex.substring(data_hex.indexOf("0d0a0d0a") + 8);
|
||||
if (data_hex.indexOf("0a0a") != -1) socket_sessions[socket.id].post_data = data_hex.substring(data_hex.indexOf("0a0a") + 4);
|
||||
}
|
||||
if (socket_sessions[socket.id].post_data.length == (socket_sessions[socket.id].post_data_length * 2)) {
|
||||
// got all expected data
|
||||
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
|
||||
console.log(" * Incoming", post_string, "request on", socket.id, "from", filterSSID(socket.ssid), "to", headers['request_url'], "(got all expected", socket_sessions[socket.id].post_data_length, "bytes of data from client already)");
|
||||
headers.post_data = CryptoJS.enc.Hex.parse(socket_sessions[socket.id].post_data);
|
||||
if (socket_sessions[socket.id].headers) delete socket_sessions[socket.id].headers;
|
||||
processURL(socket, headers);
|
||||
} else {
|
||||
// expecting more data (see below)
|
||||
socket_sessions[socket.id].expecting_post_data = true;
|
||||
console.log(" * Incoming", post_string, "request on", socket.id, "from", filterSSID(socket.ssid), "to", headers['request_url'], "(expecting", socket_sessions[socket.id].post_data_length, "bytes of data from client...)");
|
||||
}
|
||||
if (socket_sessions[socket.id].post_data.length > (socket_sessions[socket.id].post_data_length * 2)) {
|
||||
// got too much data ? ... should not ever reach this code
|
||||
var errpage = doErrorPage(400, "Received too much data in POST request<br>Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length);
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
sendToClient(socket, headers, data);
|
||||
return;
|
||||
}
|
||||
|
||||
// the client may have just sent the data with the primary headers, so lets look for that.
|
||||
if (data_hex.indexOf("0d0a0d0a") != -1) socket_sessions[socket.id].post_data = data_hex.substring(data_hex.indexOf("0d0a0d0a") + 8);
|
||||
if (data_hex.indexOf("0a0a") != -1) socket_sessions[socket.id].post_data = data_hex.substring(data_hex.indexOf("0a0a") + 4);
|
||||
|
||||
}
|
||||
if (socket_sessions[socket.id].post_data.length == (socket_sessions[socket.id].post_data_length * 2)) {
|
||||
// got all expected data
|
||||
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
|
||||
console.log(" * Incoming", post_string, "request on", socket.id, "from", filterSSID(socket.ssid), "to", headers['request_url'], "(got all expected", socket_sessions[socket.id].post_data_length, "bytes of data from client already)");
|
||||
headers.post_data = CryptoJS.enc.Hex.parse(socket_sessions[socket.id].post_data);
|
||||
if (socket_sessions[socket.id].headers) delete socket_sessions[socket.id].headers;
|
||||
processURL(socket, headers);
|
||||
} else {
|
||||
// expecting more data (see below)
|
||||
socket_sessions[socket.id].expecting_post_data = true;
|
||||
console.log(" * Incoming", post_string, "request on", socket.id, "from", filterSSID(socket.ssid), "to", headers['request_url'], "(expecting", socket_sessions[socket.id].post_data_length, "bytes of data from client...)");
|
||||
}
|
||||
if (socket_sessions[socket.id].post_data.length > (socket_sessions[socket.id].post_data_length * 2)) {
|
||||
// got too much data ? ... should not ever reach this code
|
||||
var errpage = doErrorPage(400, "Received too much data in POST request<br>Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length);
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
sendToClient(socket, headers, data);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
delete socket_sessions[socket.id].headers;
|
||||
delete socket_sessions[socket.id].post_data;
|
||||
@@ -1150,7 +1187,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
||||
return;
|
||||
}
|
||||
var str_test = enc_data.toString(CryptoJS.enc.Latin1);
|
||||
if (headersAreStandard(str_test)) {
|
||||
if (isUnencryptedString(str_test)) {
|
||||
var dec_data = enc_data;
|
||||
} else {
|
||||
var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data));
|
||||
@@ -1303,7 +1340,7 @@ function getGitRevision() {
|
||||
if (rev.indexOf(':') === -1) {
|
||||
return rev;
|
||||
} else {
|
||||
return fs.readFileSync(__dirname + path.sep + ".." + path.sep + ".git" + path.sep + rev.substring(5)).toString().trim();
|
||||
return fs.readFileSync(__dirname + path.sep + ".." + path.sep + ".git" + path.sep + rev.substring(5)).toString().trim().substring(0,8) + "-" + rev.split('/').pop();
|
||||
}
|
||||
} catch (e) {
|
||||
return null;
|
||||
@@ -1312,12 +1349,9 @@ function getGitRevision() {
|
||||
|
||||
// SERVER START
|
||||
var git_commit = getGitRevision()
|
||||
if (git_commit) {
|
||||
var z_title = "zefie's wtv minisrv v" + require('./package.json').version + " (git " + git_commit.substring(0,8) + ")";
|
||||
} else {
|
||||
var z_title = "zefie's wtv minisrv v" + require('./package.json').version;
|
||||
}
|
||||
console.log("**** Welcome to " + z_title + " ****");
|
||||
var z_title = "zefie's wtv minisrv v" + require('./package.json').version;
|
||||
if (git_commit) console.log("**** Welcome to " + z_title + " (git " + git_commit + ") ****");
|
||||
else console.log("**** Welcome to " + z_title + " ****");
|
||||
console.log(" *** Reading global configuration...");
|
||||
try {
|
||||
var minisrv_config = JSON.parse(fs.readFileSync(__dirname + path.sep + "config.json"));
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
"hide_ssid_in_logs": true,
|
||||
"post_percentages": [ 0, 25, 50, 100 ],
|
||||
"verbosity": 2,
|
||||
"error_log_file": "errors.log"
|
||||
"error_log_file": "errors.log",
|
||||
"allow_guests": true,
|
||||
"enable_lzpf_compression": true
|
||||
},
|
||||
"services": {
|
||||
"wtv-head-waiter": {
|
||||
@@ -48,6 +50,7 @@
|
||||
"wtv-flashrom": {
|
||||
"port": 1618,
|
||||
"flags": "0x00000040",
|
||||
"debug": false,
|
||||
"use_zefie_server": true,
|
||||
"bf0app_default_rom": "content/artemis-webtv-000/build7181/daily-nondebug/bf0app-part000.rom"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "zefie_wtvp_minisrv",
|
||||
"version": "0.9.12",
|
||||
"version": "0.9.13",
|
||||
"description": "WebTV Service (WTVP) Emulation Server",
|
||||
"main": "app.js",
|
||||
"homepage": "https://github.com/zefie/zefie_wtvp_minisrv",
|
||||
|
||||
@@ -47,6 +47,9 @@
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-cookie\list.js" />
|
||||
<Content Include="ServiceVault\wtv-cookie\reset.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-flashrom\current-noflash.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
@@ -196,6 +199,9 @@
|
||||
<Content Include="ServiceVault\wtv-music\get-playlist.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-register\BeMyGuest.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-register\FinishRegistration.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
@@ -220,7 +226,8 @@
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-register\splash.js" />
|
||||
<Content Include="ServiceVault\wtv-setup\get.js">
|
||||
<Content Include="ServiceVault\wtv-setup\get.js" />
|
||||
<Content Include="ServiceVault\wtv-setup\get-settings.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-star\ROMCache\HackTVLogoJewel.gif" />
|
||||
@@ -231,9 +238,15 @@
|
||||
<Content Include="ServiceVault\wtv-tricks\info.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-tricks\register.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-tricks\tricks.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-tricks\unregister.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-update\content\diskmaps\DealerDemo.json">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
|
||||
Reference in New Issue
Block a user