v0.9.16
- numerous bug fixes - improve session retention - use wtv-head-waiter:/relogin for boot url - viewer seems to retain only wtv-* and wtv-head-waiter, so lets try to be closer to protocol and boot with a wtv-head-waiter address instead of wtv-1800 - we still handle via wtv-1800 but we accept wtv-head-waiter:/relogin and send the client on its way to the relogin path - update wtv-home:/home - remove spacing in favor of right alignment - add compression status - guest mode session store update - allow calls to saveSessionData() but do not actually write if user is guest - saveSessionData() returns true even if guest, because false is meant to define an error - You can also use SaveIfRegistered(), this will return false on both saveSessionData() errors AND guest mode; - if you want to block guests, check for isRegistered() and block the request if it is false - otherwise this update will allow all tools (including any logins) to work with guest mode, but the stored SessionData will not be persistently saved, and lost when the cleanup timeout hits (default 3 min), or the server is restarted. - more accurately mimic WTVP by accepting URLs without / - use service-style cookie links on tricks - add catchall system & http pc server - define a catchall name to run globally or per service - catchall must be javascript, but not necessarily a .js file - catchall can request async mode - catchall will catch any non-existing requests under its directory - see wtv-flashrom:/content/content-serve.js as an example, which will catch wtv-flashrom:/content/ URLs. - http pc: sends HTTP/1.0 to PC clients - can be disabled with `pc_server_hidden_service_enabled`: false - can change servicevault path by changing string of pc_server_hidden_service - get.js in default PC service vault to get any WTV Url on the service - flashrom system updates - fix bugs - more WNI-like flow path - make scripts use `service_name` variable so that they should work in a renamed service (eg not wtv-flashrom, untested) - rewrite wtv-disk system - move wtv-update to wtv-disk - allow accessing wtv-disk:/sync?group=&diskmap= - rewrite Download List generation to be more proper - only send files if diskmap has changed - allow force redownload with &force=true
@@ -11,7 +11,7 @@ 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)
|
||||
- WebTV cookie support (wtv-cookie) 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
|
||||
@@ -31,7 +31,7 @@ This open source server is in alpha status. Use at your own risk.
|
||||
### Feature Todo:
|
||||
- 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)***
|
||||
- ~~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)***
|
||||
|
||||
@@ -11,12 +11,15 @@ services:
|
||||
minisrv:
|
||||
build: ./minisrv
|
||||
restart: unless-stopped
|
||||
stop_signal: SIGINT
|
||||
links:
|
||||
- webone
|
||||
ports:
|
||||
- "1600-1699:1600-1699"
|
||||
volumes:
|
||||
- /home/zefie/docker/wtvminisrv/user_config.json:/opt/minisrv/zefie_wtvp_minisrv/user_config.json:ro
|
||||
- /home/zefie/docker/wtvminisrv/UserServiceVault:/opt/minisrv/zefie_wtvp_minisrv/UserServiceVault
|
||||
- /home/zefie/docker/wtvminisrv/UserServiceVault:/opt/minisrv/zefie_wtvp_minisrv/UserServiceVault:ro
|
||||
- /home/zefie/docker/wtvminisrv/SessionStore:/opt/minisrv/zefie_wtvp_minisrv/SessionStore
|
||||
- /home/zefie/docker/wtvminisrv/ServiceLogPost:/opt/minisrv/zefie_wtvp_minisrv/ServiceLogPost
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
FROM node:current-alpine
|
||||
|
||||
RUN apk add git
|
||||
RUN npm install -g npm@latest 2>/dev/null > /dev/null
|
||||
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
|
||||
@@ -10,3 +11,4 @@ RUN chmod +x /opt/minisrv/zefie_wtvp_minisrv/run.sh
|
||||
|
||||
WORKDIR /opt/minisrv/zefie_wtvp_minisrv
|
||||
CMD ./run.sh
|
||||
|
||||
|
||||
@@ -22,6 +22,11 @@ If you would like to see debug information about realtime bytes received from a
|
||||
"allow_guests": false
|
||||
```
|
||||
If you would like to require registration, disabling guest mode, you can set `allow_guests` to `false`. Default is `true`;
|
||||
```
|
||||
"pc_server_hidden_service_enabled": false,
|
||||
"pc_server_hidden_service": "http_pc"
|
||||
```
|
||||
Set `pc_server_hidden_service_enabled` option to `true` to enable the HTTP Server for Browsers. Set `pc_server_hidden_service` to a directory under the ServiceVaults to use solely for PC requests. See `ServiceVault/http_pc` for some example code.
|
||||
```
|
||||
"post_percentages": [ 0, 25, 50, 100]
|
||||
```
|
||||
|
||||
37
zefie_wtvp_minisrv/ServiceVault/http_pc/get.js
Normal file
@@ -0,0 +1,37 @@
|
||||
if (request_headers.query.url) {
|
||||
if (request_headers.query.url.indexOf(":/") > 0) {
|
||||
var service_request = request_headers.query.url.split(":/")[0];
|
||||
var service_port = 0;
|
||||
Object.keys(minisrv_config.services).forEach(function (k) {
|
||||
if (minisrv_config.services[k].disabled) return;
|
||||
if (k == service_request) service_port = minisrv_config.services[k].port;
|
||||
});
|
||||
if (service_port > 0) {
|
||||
request_is_async = true;
|
||||
var request_headers_out = new Array()
|
||||
request_headers_out.request = "GET " + request_headers.query.url;
|
||||
request_headers_out.request_url = request_headers.query.url;
|
||||
request_headers_out['wtv-client-serial-number'] = socket.id + "HTTPPCReq";
|
||||
processURL(socket, request_headers_out);
|
||||
/*
|
||||
var s = require('net').Socket();
|
||||
var outdata = "";
|
||||
s.connect(service_port);
|
||||
s.setTimeout(1, function () {
|
||||
outdata = outdata.split()
|
||||
sendToClient(socket,outdata);
|
||||
});
|
||||
s.on('data', function (data) {
|
||||
outdata += data;
|
||||
});
|
||||
s.write()
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!headers) {
|
||||
var errpage = doErrorPage(500)
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
}
|
||||
31
zefie_wtvp_minisrv/ServiceVault/http_pc/index.js
Normal file
@@ -0,0 +1,31 @@
|
||||
headers = `200 OK
|
||||
Content-Type: text/html`
|
||||
|
||||
var splash_logo = minisrv_config.config.service_splash_logo;
|
||||
if (splash_logo.substring(0, 4) == "file") splash_logo = "wtv-star:/ROMCache/splash_logo_hacktv.gif";
|
||||
|
||||
data = `<html>
|
||||
<head>
|
||||
<display hideoptions nostatus showwhencomplete skipback clearback fontsize=medium>
|
||||
<title>zefie minisrv ${minisrv_config.version}</title>
|
||||
<meta http-equiv=Refresh content="4; url=wtv-home:/home?">
|
||||
</head>
|
||||
<body bgcolor="#000000" text="#449944">
|
||||
<center>
|
||||
<spacer type=block height=88 width=21>
|
||||
<img src="/get?url=${escape('wtv-star:/ROMCache/spacer.gif')}" height=4><br>
|
||||
<img src="/get?url=${escape(splash_logo)}">
|
||||
<br><br><br>
|
||||
<p><br>
|
||||
<p><br>
|
||||
<table border>
|
||||
<tr><td width=150>
|
||||
Mini service
|
||||
<tr><td>
|
||||
zefie minisrv v${minisrv_config.version}`;
|
||||
if (minisrv_config.config.git_commit) data += " (git " + minisrv_config.config.git_commit + ")";
|
||||
data += `
|
||||
</table>
|
||||
</center>
|
||||
</body>
|
||||
</html>`;
|
||||
@@ -144,7 +144,7 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
|
||||
headers += getServiceString('wtv-flashrom') + "\n";
|
||||
if (bf0app_update) headers += "wtv-boot-url: " + gourl + "\n";
|
||||
else {
|
||||
headers += "wtv-boot-url: wtv-1800:/preregister?relogin=true";
|
||||
headers += "wtv-boot-url: wtv-head-waiter:/relogin?relogin=true";
|
||||
if (request_headers.query.guest_login) headers += "&guest_login=true";
|
||||
headers += "\n";
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 43 B After Width: | Height: | Size: 43 B |
311
zefie_wtvp_minisrv/ServiceVault/wtv-disk/sync.js
Normal file
@@ -0,0 +1,311 @@
|
||||
// todo: async
|
||||
|
||||
var force_update = (request_headers.query.force == "true") ? true : false;
|
||||
console.log(force_update);
|
||||
if (request_headers['wtv-request-type'] == 'download') {
|
||||
var path = require("path");
|
||||
|
||||
var content_dir = "content/"
|
||||
var diskmap_dir = content_dir + "diskmaps/";
|
||||
|
||||
function generateDownloadList(diskmap_group_data, update_list, diskmap_data) {
|
||||
// create WebTV Download List
|
||||
var newest_file_epoch = 0;
|
||||
var download_list = '';
|
||||
|
||||
if (diskmap_data.execute && diskmap_data.execute_when == "atStart") {
|
||||
download_list += "EXECUTE " + diskmap_data.execute + "\n\n";
|
||||
}
|
||||
|
||||
if (diskmap_data.partition_size) {
|
||||
download_list += "CREATE " + diskmap_data.base + "\n";
|
||||
download_list += "partition-size: " + diskmap_data.partition_size + "\n\n";
|
||||
}
|
||||
|
||||
download_list += "CREATE-GROUP " + diskmap_group_data + "-UPDATE\n";
|
||||
download_list += "state: invalid\n";
|
||||
download_list += "base: " + diskmap_data.base + ".GROUP-UPDATE/\n\n";
|
||||
|
||||
download_list += "CREATE-GROUP " + diskmap_group_data + "\n";
|
||||
download_list += "state: invalid\n";
|
||||
download_list += "service-owned: " + (diskmap_data.service_owned || false) + "\n";
|
||||
download_list += "base: " + diskmap_data.base + "\n\n";
|
||||
|
||||
Object.keys(update_list).forEach(function (k) {
|
||||
if (!update_list[k].invalid) return;
|
||||
download_list += "DELETE " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
|
||||
download_list += "group: " + diskmap_group_data + "\n\n";
|
||||
});
|
||||
|
||||
Object.keys(update_list).forEach(function (k) {
|
||||
if (update_list[k].checksum_match && !force_update) return;
|
||||
if (!update_list[k].invalid && !force_update) return;
|
||||
download_list += "DISPLAY " + update_list[k].display + "\n\n";
|
||||
download_list += "GET " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
|
||||
download_list += "group: " + diskmap_group_data + "-UPDATE\n";
|
||||
download_list += "location: " + service_name + ":/" + update_list[k].location + "\n";
|
||||
download_list += "file-permission: r\n"
|
||||
download_list += "wtv-checksum: " + update_list[k].checksum + "\n";
|
||||
download_list += "service-source-location: /webtv/content/" + service_name.replace("wtv-", "") + "d/" + update_list[k].location + "\n";
|
||||
download_list += "client-dest-location: " + update_list[k].file + "\n\n";
|
||||
});
|
||||
|
||||
download_list += "CREATE-GROUP " + diskmap_group_data + "\n";
|
||||
download_list += "state: invalid\n";
|
||||
download_list += "service-owned: " + (diskmap_data.service_owned || false) + "\n";
|
||||
download_list += "base: " + diskmap_data.base + "\n\n";
|
||||
|
||||
|
||||
Object.keys(update_list).forEach(function (k) {
|
||||
if (!update_list[k].invalid) return;
|
||||
download_list += "RENAME " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
|
||||
download_list += "group: " + diskmap_group_data + "-UPDATE\n";
|
||||
download_list += "destination-group: " + diskmap_group_data + "\n";
|
||||
download_list += "location: " + update_list[k].file.replace(diskmap_data.base, "") + "\n\n";
|
||||
});
|
||||
|
||||
download_list += "SET-GROUP " + diskmap_group_data + "\n";
|
||||
download_list += "state: ok\n";
|
||||
download_list += "version: " + diskmap_data.version + "\n";
|
||||
download_list += "last-checkup-time: " + new Date().toUTCString().replace("GMT", "+0000") + "\n\n";
|
||||
|
||||
if (diskmap_data.execute && diskmap_data.execute_when == "atEnd") {
|
||||
download_list += "EXECUTE " + diskmap_data.execute + "\n\n";
|
||||
}
|
||||
|
||||
download_list += "DELETE-GROUP " + diskmap_group_data + "-UPDATE\n\n";
|
||||
download_list += "DELETE " + diskmap_data.base + ".GROUP-UPDATE/\n\n";
|
||||
console.log(download_list);
|
||||
return download_list;
|
||||
}
|
||||
|
||||
function processGroup(diskmap_primary_group, diskmap_group_data, diskmap_subgroup = null) {
|
||||
// parse webtv post
|
||||
var output_data = '';
|
||||
var post_data = request_headers.post_data.toString(CryptoJS.enc.Latin1).split("\n");
|
||||
var post_data_current_directory = '';
|
||||
var post_data_current_file = false;
|
||||
var post_data_current_group = '';
|
||||
var post_data_last_modified = false;
|
||||
var post_data_content_length = false;
|
||||
var post_data_current_group_state = false;
|
||||
var post_data_fileinfo = new Array();
|
||||
var entry_type = false;
|
||||
var post_data_current_version = false;
|
||||
var post_data_current_checksum = false;
|
||||
var post_data_last_checkup_time = 0;
|
||||
Object.keys(post_data).forEach(function (k) {
|
||||
if (post_data[k].substring(0, 7) == "file://") {
|
||||
entry_type = "folder";
|
||||
post_data_current_file = false;
|
||||
post_data_current_version = false;
|
||||
post_data_last_checkup_time = 0;
|
||||
post_data_current_group = '';
|
||||
post_data_current_group_state = false;
|
||||
post_data_last_modified = false;
|
||||
post_data_content_length = false;
|
||||
post_data_current_checksum = false;
|
||||
post_data_current_directory = post_data[k];
|
||||
} else {
|
||||
if (post_data[k].indexOf(":") > 0) {
|
||||
var post_data_line = post_data[k].split(": ")
|
||||
var post_data_line_name = post_data_line[0];
|
||||
post_data_line.shift();
|
||||
var post_data_line_data = post_data_line.join(": ");
|
||||
|
||||
switch (post_data_line_name.toLowerCase()) {
|
||||
case "last-modified":
|
||||
post_data_last_modified = (new Date(new Date(Date.parse(post_data_line_data)).toUTCString()) / 1000);
|
||||
break;
|
||||
case "content-length":
|
||||
post_data_content_length = parseInt(post_data_line_data);
|
||||
break;
|
||||
case "version":
|
||||
post_data_current_version = parseInt(post_data_line_data);
|
||||
break;
|
||||
case "group":
|
||||
post_data_current_group = post_data_line_data;
|
||||
break;
|
||||
case "state":
|
||||
post_data_current_group_state = post_data_line_data;
|
||||
break;
|
||||
case "wtv-checksum":
|
||||
post_data_current_checksum = post_data_line_data;
|
||||
break;
|
||||
case "last-checkup-time":
|
||||
post_data_last_checkup_time = (new Date(new Date(Date.parse(post_data_line_data)).toUTCString()) / 1000);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!entry_type && post_data[k] != "") {
|
||||
entry_type = "file";
|
||||
post_data_current_file = post_data[k];
|
||||
}
|
||||
|
||||
if (post_data[k] == "" && entry_type) {
|
||||
var post_data_current_path = ((entry_type == "file") ? (post_data_current_directory + post_data_current_file) : post_data_current_directory);
|
||||
var index = post_data_current_path.replace(/[\:\/]/g, "_").toLowerCase() + "_" + post_data_current_group;
|
||||
if (index.match(/\/$/)) entry_type = "folder";
|
||||
if (!post_data_fileinfo[index]) post_data_fileinfo[index] = new Array();
|
||||
post_data_fileinfo[index].entry_type = entry_type;
|
||||
post_data_fileinfo[index].file = post_data_current_path;
|
||||
post_data_fileinfo[index].group = post_data_current_group;
|
||||
post_data_fileinfo[index].version = post_data_current_version || 0;
|
||||
if (post_data_current_checksum) post_data_fileinfo[index].checksum = post_data_current_checksum;
|
||||
if (post_data_current_group_state) post_data_fileinfo[index].state = post_data_current_group_state;
|
||||
if (post_data_last_checkup_time) post_data_fileinfo[index].last_checkup = post_data_last_checkup_time;
|
||||
if (post_data_last_modified) post_data_fileinfo[index].last_modified = post_data_last_modified;
|
||||
if (post_data_content_length) post_data_fileinfo[index].content_length = post_data_content_length;
|
||||
entry_type = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
var wtv_download_list = new Array();
|
||||
var newest_file_epoch = 0;
|
||||
Object.keys(diskmap_group_data.files).forEach(function (k) {
|
||||
if (!diskmap_group_data.files[k].location) diskmap_group_data.files[k].location = diskmap_group_data.location + diskmap_group_data.files[k].file.replace(diskmap_group_data.base, "");
|
||||
var post_match_file = null;
|
||||
Object.keys(service_vaults).forEach(function (g) {
|
||||
if (post_match_file != null) return;
|
||||
post_match_file = service_vaults[g] + "/" + service_name + "/" + diskmap_group_data.files[k].location;
|
||||
if (!fs.existsSync(post_match_file)) post_match_file = null;
|
||||
});
|
||||
|
||||
var post_match_file_lstat = fs.lstatSync(post_match_file);
|
||||
var post_match_file_data = new Buffer.from(fs.readFileSync(post_match_file, {
|
||||
encoding: null,
|
||||
flags: 'r'
|
||||
}));
|
||||
diskmap_group_data.files[k].base = diskmap_group_data.base;
|
||||
diskmap_group_data.files[k].last_modified = (new Date(new Date(post_match_file_lstat.mtime).toUTCString()) / 1000);
|
||||
diskmap_group_data.files[k].content_length = post_match_file_lstat.size;
|
||||
diskmap_group_data.files[k].checksum = CryptoJS.MD5(CryptoJS.lib.WordArray.create(post_match_file_data)).toString(CryptoJS.enc.Hex).toLowerCase();
|
||||
|
||||
if (parseInt(diskmap_group_data.files[k].last_modified) > newest_file_epoch) newest_file_epoch = parseInt(diskmap_group_data.files[k].last_modified);
|
||||
if (!diskmap_group_data.files[k].display) diskmap_group_data.files[k].display = diskmap_group_data.display;
|
||||
|
||||
diskmap_group_data.files[k].invalid = true;
|
||||
wtv_download_list.push(diskmap_group_data.files[k]);
|
||||
});
|
||||
// check to see if client says they have this version
|
||||
diskmap_group_data.version = newest_file_epoch;
|
||||
Object.keys(wtv_download_list).forEach(function (k) {
|
||||
wtv_download_list[k].version = newest_file_epoch;
|
||||
Object.keys(post_data_fileinfo).forEach(function (g) {
|
||||
if (post_data_fileinfo[g].file == wtv_download_list[k] || post_data_fileinfo[g].file == wtv_download_list[k].base) {
|
||||
diskmap_group_data.group_exists = true;
|
||||
if (diskmap_group_data.files[k].checksum.toLowerCase() == post_data_fileinfo[g].checksum) wtv_download_list[k].invalid = false;
|
||||
else if (post_data_fileinfo[g].version == wtv_download_list[k].version && post_data_fileinfo[g].state != "invalid") wtv_download_list[k].invalid = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
var diskmap_group_name = (diskmap_subgroup == null) ? diskmap_primary_group : diskmap_primary_group + "-" + diskmap_subgroup;
|
||||
output_data = generateDownloadList(diskmap_group_name, wtv_download_list, diskmap_group_data);
|
||||
return output_data;
|
||||
}
|
||||
|
||||
if (request_headers.query.diskmap && request_headers.query.group && request_headers.post_data) {
|
||||
var diskmap_json_file = null;
|
||||
Object.keys(service_vaults).forEach(function (g) {
|
||||
if (diskmap_json_file != null) return;
|
||||
diskmap_json_file = service_vaults[g] + "/" + service_name + "/" + diskmap_dir + request_headers.query.diskmap + ".json";
|
||||
if (!fs.existsSync(diskmap_json_file)) diskmap_json_file = null;
|
||||
});
|
||||
|
||||
if (diskmap_json_file != null) {
|
||||
if (fs.lstatSync(diskmap_json_file)) {
|
||||
try {
|
||||
// read diskmap
|
||||
var diskmap_data = JSON.parse(fs.readFileSync(diskmap_json_file).toString());
|
||||
if (!diskmap_data[request_headers.query.group]) {
|
||||
throw ("Invalid diskmap data (group does not match)");
|
||||
}
|
||||
data = '';
|
||||
diskmap_data = diskmap_data[request_headers.query.group];
|
||||
if (!diskmap_data.location) {
|
||||
Object.keys(diskmap_data).forEach(function (k) {
|
||||
if (diskmap_data[k]) data += processGroup(request_headers.query.group, diskmap_data[k], k);
|
||||
});
|
||||
} else {
|
||||
data = processGroup(request_headers.query.group, diskmap_data);
|
||||
}
|
||||
|
||||
headers = "200 OK\nContent-Type: wtv/download-list";
|
||||
} catch (e) {
|
||||
var errpage = doErrorPage(400);
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
console.error(" # " + service_name+":/sync error", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var errpage = doErrorPage(404, "The requested DiskMap does not exist.");
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
if (zdebug) console.error(" # " + service_name +":/sync error", "could not find diskmap");
|
||||
}
|
||||
} else {
|
||||
var errpage = doErrorPage(400);
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
if (zdebug) console.error(" # " + service_name + ":/sync error", "missing query arguments");
|
||||
}
|
||||
} else if (request_headers.query.group && request_headers.query.diskmap) {
|
||||
var message = request_headers.query.message || "Retrieving files...";
|
||||
var main_message = request_headers.query.main_message || "Your receiver is downloading files.";
|
||||
headers = `200 OK
|
||||
Content-Type: text/html`;
|
||||
|
||||
data = `
|
||||
<html>
|
||||
<head>
|
||||
<meta
|
||||
http-equiv=refresh
|
||||
content="0;url=client:Fetch?group=${escape(request_headers.query.group)}&source=${service_name}:/sync%3Fdiskmap%3D${escape(escape(request_headers.query.diskmap))}%26force%3D${force_update}&message=${escape(message)}"
|
||||
>
|
||||
<display downloadsuccess="client:ShowAlert?message=Download%20successful%21&buttonlabel1=Okay&buttonaction1=client:goback&image=${minisrv_config.config.service_logo}&noback=true" downloadfail="client:ShowAlert?message=Download%20failed...&buttonlabel1=Okay...&buttonaction1=client:goback&image=${minisrv_config.config.service_logo}&noback=true">
|
||||
<title>Retrieving files...</title>
|
||||
</head>
|
||||
<body bgcolor=#0 text=#42CC55 fontsize=large hspace=0 vspace=0>
|
||||
<table cellspacing=0 cellpadding=0>
|
||||
<tr>
|
||||
<td width=104 height=74 valign=middle align=center bgcolor=3B3A4D>
|
||||
<img src="${minisrv_config.config.service_logo}" width=86 height=64>
|
||||
<td width=20 valign=top align=left bgcolor=3B3A4D>
|
||||
<spacer>
|
||||
<td colspan=2 width=436 valign=middle align=left bgcolor=3B3A4D>
|
||||
<font color=D6DFD0 size=+2><blackface><shadow>
|
||||
<spacer type=block width=1 height=4>
|
||||
<br>
|
||||
${message}
|
||||
</shadow>
|
||||
</blackface>
|
||||
</font>
|
||||
<tr>
|
||||
<td width=104 height=20>
|
||||
<td width=20>
|
||||
<td width=416>
|
||||
<td width=20>
|
||||
<tr>
|
||||
<td colspan=2>
|
||||
<td>
|
||||
<font size=+1>
|
||||
${main_message}
|
||||
<p>This may take a while.
|
||||
</font>
|
||||
<tr>
|
||||
<td colspan=2>
|
||||
<td>
|
||||
<br><br>
|
||||
<font color=white>
|
||||
<progressindicator name="downloadprogress"
|
||||
message="Preparing..."
|
||||
height=40 width=250>
|
||||
</font>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
const WTVFlashrom = require("./WTVFlashrom.js");
|
||||
request_is_async = true;
|
||||
console.log(request_headers);
|
||||
|
||||
var bf0app_update = false;
|
||||
var request_path = request_headers.request_url.replace(service_name + ":/", "");
|
||||
var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
|
||||
var bootver = ssid_sessions[socket.ssid].get("wtv-client-bootrom-version")
|
||||
|
||||
if ((romtype == "bf0app" || !romtype) && (bootver == "105" || !bootver)) {
|
||||
// assume old classic in flash mode, override user setting and send tellyscript
|
||||
// because it is required to proceed in flash mode
|
||||
bf0app_update = true;
|
||||
ssid_sessions[socket.ssid].set("bf0app_update", bf0app_update);
|
||||
}
|
||||
|
||||
if (!ssid_sessions[socket.ssid].data_store.WTVFlashrom) {
|
||||
ssid_sessions[socket.ssid].data_store.WTVFlashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server, bf0app_update, minisrv_config.services[service_name].debug);
|
||||
}
|
||||
|
||||
ssid_sessions[socket.ssid].data_store.WTVFlashrom.getFlashRom(request_path, function (data, headers) {
|
||||
sendToClient(socket, headers, data);
|
||||
});
|
||||
@@ -22,10 +22,10 @@ if (request_headers.query.raw || bf0app_update) {
|
||||
sendToClient(socket, headers, data);
|
||||
});
|
||||
} else {
|
||||
headers = "200 OK\n"
|
||||
if (request_headers.query.path) {
|
||||
headers += "Content-type: text/html\n"
|
||||
headers += "wtv-visit: wtv-flashrom:/initiate-lc2-download?path=" + request_headers.query.path;
|
||||
headers = "200 OK\n"
|
||||
headers += "wtv-visit: " + service_name + ":/initiate-lc2-download?path=" + request_headers.query.path + "\n";
|
||||
headers += "Content-type: text/html"
|
||||
data = '';
|
||||
} else {
|
||||
var errpage = doErrorPage(404)
|
||||
|
||||
@@ -20,11 +20,10 @@ if (!request_headers.query.path) {
|
||||
async function processLC2DownloadPage(path, flashrom_info, numparts = null) {
|
||||
if (numparts != null) flashrom_info.part_count = parseInt(numparts);
|
||||
if (!flashrom_info.part_count) flashrom_info.part_count = parseInt(flashrom_info.message.substring(flashrom_info.message.length - 4).replace(/\D/g, ''));
|
||||
|
||||
if (!flashrom_info.is_last_part) {
|
||||
flashrom_info.next_rompath = flashrom_info.next_rompath.replace("get-by-path", "get-lc2-page").replace("&raw=true", "&numparts=" + flashrom_info.part_count);
|
||||
}
|
||||
if (!flashrom_info.part_number || !flashrom_info.is_last_part || !flashrom_info.rompath || !flashrom_info.next_rompath || !flashrom_info.is_bootrom) {
|
||||
if (!flashrom_info.is_last_part || request_headers.query.last_part) {
|
||||
flashrom_info.next_rompath = request_headers.request_url.replace(escape(request_headers.query.path), escape(flashrom_info.next_rompath.replace(service_name+":/","")));
|
||||
}
|
||||
|
||||
headers = `200 OK
|
||||
Content-type: text/html`
|
||||
@@ -43,12 +42,12 @@ hspace=0 vspace=0 fontsize="large">
|
||||
<td width=104 height=74 valign=middle align=center bgcolor="3B3A4D">
|
||||
<img src="${minisrv_config.config.service_logo}" width=87 height=67>
|
||||
<td width=20 valign=top align=left bgcolor="3B3A4D">
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=1>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=1 height=1>
|
||||
<td colspan=10 width=436 valign=middle align=left bgcolor="3B3A4D">
|
||||
<font color="D6DFD0" size="+2">
|
||||
<blackface>
|
||||
<shadow>
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=4>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=1 height=4>
|
||||
<br>
|
||||
Updating now
|
||||
</shadow>
|
||||
@@ -56,7 +55,7 @@ Updating now
|
||||
</font>
|
||||
<tr>
|
||||
<td colspan=12 width=560 height=10 valign=top align=left>
|
||||
<img src="wtv-flashrom:/ROMCache/S40H1.gif" width=560 height=6>
|
||||
<img src="${service_name}:/ROMCache/S40H1.gif" width=560 height=6>
|
||||
<tr>
|
||||
<td width=104 height=10 valign=top align=left>
|
||||
<td width=20 valign=top align=left>
|
||||
@@ -92,7 +91,7 @@ data += `
|
||||
<br><br><br><br><br>
|
||||
<upgradeblock width=280 height=15
|
||||
nexturl="${flashrom_info.next_rompath}"
|
||||
errorurl="wtv-flashrom:/lc2-download-failed?"
|
||||
errorurl="${service_name}:/lc2-download-failed?"
|
||||
blockurl="${flashrom_info.rompath}"
|
||||
lastblock="${flashrom_info.is_last_part}"
|
||||
curblock="` + (flashrom_info.part_number + 1) + `"
|
||||
@@ -103,14 +102,14 @@ curblock="` + (flashrom_info.part_number + 1) + `"
|
||||
data += `>
|
||||
<font size="-1" color="#D6DFD0">
|
||||
<br>
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=2 height=10><br>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=2 height=10><br>
|
||||
${flashrom_info.message}
|
||||
<br><br>
|
||||
<tr>
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
<td colspan=10 height=2 valign=middle align=center bgcolor="#191919">
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<tr>
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
@@ -119,7 +118,7 @@ ${flashrom_info.message}
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
<td colspan=10 height=2 valign=top align=left bgcolor="#191919">
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<tr>
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
if (request_headers.query.path) {
|
||||
var url = "wtv-flashrom:/get-lc2-page?path=" + request_headers.query.path;
|
||||
var url = service_name + ":/get-lc2-page?path=" + request_headers.query.path;
|
||||
var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
|
||||
if (romtype == "bf0app") {
|
||||
url = "client:updateflash?ipaddr=" + minisrv_config.services[service_name].host + "&port=" + minisrv_config.services[service_name].port + "&path=" + escape(url.replace("get-lc2-page", "get-by-path"));
|
||||
url = "client:updateflash?ipaddr=" + minisrv_config.services[service_name].host + "&port=" + minisrv_config.services[service_name].port + "&path=" + escape(service_name + ":/" +request_headers.query.path);
|
||||
if (request_headers.query.numparts) url += escape("&numparts=" + request_headers.query.numparts);
|
||||
}
|
||||
headers = "300 OK\n";
|
||||
headers = "200 OK\n";
|
||||
headers += "wtv-visit: " + url + "\n";
|
||||
headers += "Location: " + url + "\n";
|
||||
headers += "Content-type: text/html";
|
||||
data = '';
|
||||
} else {
|
||||
|
||||
@@ -25,12 +25,12 @@ hspace=0 vspace=0 fontsize="large">
|
||||
<td width=104 height=74 valign=middle align=center bgcolor="3B3A4D">
|
||||
<img src="${minisrv_config.config.service_logo}" width=87 height=67>
|
||||
<td width=20 valign=top align=left bgcolor="3B3A4D">
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=1>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=1 height=1>
|
||||
<td colspan=10 width=436 valign=middle align=left bgcolor="3B3A4D">
|
||||
<font color="D6DFD0" size="+2">
|
||||
<blackface>
|
||||
<shadow>
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=4>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=1 height=4>
|
||||
<br>
|
||||
Updating complete
|
||||
</shadow>
|
||||
@@ -38,7 +38,7 @@ Updating complete
|
||||
</font>
|
||||
<tr>
|
||||
<td colspan=12 width=560 height=10 valign=top align=left>
|
||||
<img src="wtv-flashrom:/ROMCache/S40H1.gif" width=560 height=6>
|
||||
<img src="${service_name}:/ROMCache/S40H1.gif" width=560 height=6>
|
||||
<tr>
|
||||
<td width=104 height=10 valign=top align=left>
|
||||
<td width=20 valign=top align=left>
|
||||
@@ -65,7 +65,7 @@ The update is complete.<br>
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
<td colspan=10 height=2 valign=middle align=center bgcolor="2B2B2B">
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<tr>
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
@@ -74,7 +74,7 @@ The update is complete.<br>
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
<td colspan=10 height=2 valign=top align=left bgcolor="0D0D0D">
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<tr>
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
|
||||
@@ -32,7 +32,7 @@ if (request_headers.query.error) {
|
||||
}
|
||||
|
||||
|
||||
var try_again_url = 'wtv-flashrom:/willie';
|
||||
var try_again_url = service_name + ":/willie";
|
||||
var try_again_url_path = ''
|
||||
var try_again_url_start_time = parseInt(new Date().toUTCString()) / 1000;
|
||||
|
||||
@@ -53,12 +53,12 @@ data = `<html>
|
||||
<td width=104 height=74 valign=middle align=center bgcolor="3B3A4D">
|
||||
<img src="${minisrv_config.config.service_logo}" width=87 height=67>
|
||||
<td width=20 valign=top align=left bgcolor="3B3A4D">
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=1>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=1 height=1>
|
||||
<td colspan=10 width=436 valign=middle align=left bgcolor="3B3A4D">
|
||||
<font color="D6DFD0" size="+2">
|
||||
<blackface>
|
||||
<shadow>
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=1 height=4>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=1 height=4>
|
||||
<br>
|
||||
Updating failed
|
||||
</shadow>
|
||||
@@ -66,7 +66,7 @@ data = `<html>
|
||||
</font>
|
||||
<tr>
|
||||
<td colspan=12 width=560 height=10 valign=top align=left>
|
||||
<img src="wtv-flashrom:/ROMCache/S40H1.gif" width=560 height=6>
|
||||
<img src="${service_name}:/ROMCache/S40H1.gif" width=560 height=6>
|
||||
<tr>
|
||||
<td width=104 height=10 valign=top align=left>
|
||||
<td width=20 valign=top align=left>
|
||||
@@ -96,7 +96,7 @@ data = `<html>
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
<td colspan=10 height=2 valign=middle align=center bgcolor="2B2B2B">
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<tr>
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
@@ -105,7 +105,7 @@ data = `<html>
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
<td colspan=10 height=2 valign=top align=left bgcolor="0D0D0D">
|
||||
<img src="wtv-flashrom:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<img src="${service_name}:/ROMCache/Spacer.gif" width=436 height=1>
|
||||
<tr>
|
||||
<td width=104 valign=middle align=center>
|
||||
<td width=20 valign=middle align=center>
|
||||
|
||||
@@ -9,7 +9,7 @@ if (request_headers.query.vflash) delete request_headers.query.vflash;
|
||||
if (request_headers.query.pflash) delete request_headers.query.pflash;
|
||||
|
||||
for (const [key, value] of Object.entries(request_headers.query)) {
|
||||
proxy_query += "&" + key + "=" + value;
|
||||
proxy_query += "&" + key + "=" + escape(value);
|
||||
}
|
||||
|
||||
if (!minisrv_config.services[service_name].use_zefie_server) {
|
||||
@@ -18,7 +18,7 @@ if (!minisrv_config.services[service_name].use_zefie_server) {
|
||||
|
||||
var options = {
|
||||
host: "wtv.zefie.com",
|
||||
path: "/willie.php?minisrv=true&pflash=" + ssid_sessions[socket.ssid].get("wtv-client-rom-type") + proxy_query,
|
||||
path: "/willie.php?minisrv=true&service_name="+escape(service_name)+"&pflash=" + ssid_sessions[socket.ssid].get("wtv-client-rom-type") + proxy_query,
|
||||
timeout: 5000,
|
||||
method: 'GET'
|
||||
}
|
||||
@@ -42,7 +42,7 @@ const req = https.request(options, function (res) {
|
||||
res.on('end', function () {
|
||||
if (!zquiet) console.log(" * Upstream Ultra Willies HTTP Response:", res.statusCode, res.statusMessage);
|
||||
if (request_headers.query.clear_cache) {
|
||||
headers += "\nwtv-expire-all: wtv-flashrom";
|
||||
headers += "\nwtv-expire-all: "+service_name;
|
||||
}
|
||||
sendToClient(socket, headers, data);
|
||||
});
|
||||
|
||||
@@ -31,11 +31,10 @@ if (socket.ssid !== null) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!ssid_sessions[socket.ssid].getSessionData("registered") && (!request_headers.query.guest_login || !minisrv_config.config.allow_guests)) gourl = "wtv-register:/splash";
|
||||
if (!ssid_sessions[socket.ssid].getSessionData("registered") && (!request_headers.query.guest_login || !minisrv_config.config.allow_guests)) gourl = "wtv-register:/splash?";
|
||||
|
||||
if (gourl) {
|
||||
headers = `200 OK
|
||||
Connection: Close
|
||||
wtv-open-isp-disabled: false
|
||||
`;
|
||||
if (!ssid_sessions[socket.ssid].getSessionData("registered") && (!request_headers.query.guest_login || !minisrv_config.config.allow_guests)) {
|
||||
@@ -44,7 +43,7 @@ wtv-ticket: ${wtvsec_login.ticket_b64}
|
||||
${getServiceString('wtv-register')}
|
||||
${getServiceString('wtv-head-waiter')}
|
||||
${getServiceString('wtv-star')}
|
||||
wtv-boot-url: wtv-register:/splash
|
||||
wtv-boot-url: wtv-head-waiter:/relogin?
|
||||
`
|
||||
}
|
||||
headers += `wtv-visit: ${gourl}
|
||||
@@ -127,11 +126,11 @@ wtv-connection-timeout: 90
|
||||
wtv-show-time-enabled: true
|
||||
wtv-fader-timeout: 900
|
||||
wtv-tourist-enabled: true`
|
||||
headers += "\nwtv-relogin-url: wtv-1800:/preregister?relogin=true";
|
||||
headers += "\nwtv-relogin-url: wtv-head-waiter:/relogin?relogin=true";
|
||||
if (request_headers.query.guest_login) headers += "&guest_login=true";
|
||||
headers += "\nwtv-reconnect-url: wtv-1800:/preregister?reconnect=true";
|
||||
headers += "\nwtv-reconnect-url: wtv-head-waiter:/relogin?reconnect=true";
|
||||
if (request_headers.query.guest_login) headers += "&guest_login=true";
|
||||
headers += "\nwtv-boot-url: wtv-1800:/preregister?relogin=true";
|
||||
headers += "\nwtv-boot-url: wtv-head-waiter:/relogin?relogin=true";
|
||||
if (request_headers.query.guest_login) headers += "&guest_login=true";
|
||||
headers += "\nwtv-allow-dsc: true";
|
||||
headers += "\nwtv-home-url: wtv-home:/home?";
|
||||
|
||||
@@ -53,8 +53,8 @@ wtv-expire-all: wtv-head-waiter:
|
||||
wtv-log-url: wtv-log:/log`;
|
||||
if (challenge_header != "") headers += "\n" + challenge_header;
|
||||
headers += `
|
||||
wtv-relogin-url: wtv-1800:/preregister?relogin=true
|
||||
wtv-reconnect-url: wtv-1800:/preregister?reconnect=true
|
||||
wtv-relogin-url: wtv-head-waiter:/relogin?relogin=true
|
||||
wtv-reconnect-url: wwtv-head-waiter:/relogin?reconnect=true
|
||||
wtv-visit: ${gourl}
|
||||
Content-type: text/html`;
|
||||
data = '';
|
||||
@@ -66,7 +66,7 @@ Connection: Keep-Alive
|
||||
Expires: Wed, 09 Oct 1991 22:00:00 GMT
|
||||
wtv-expire-all: wtv-head-waiter:
|
||||
wtv-expire-all: wtv-1800:
|
||||
wtv-visit: wtv-1800:/preregister?relogin=true
|
||||
wtv-visit: wtv-head-waiter:/relogin?relogin=true
|
||||
Content-type: text/html`;
|
||||
data = '';
|
||||
}
|
||||
20
zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js
Normal file
@@ -0,0 +1,20 @@
|
||||
var gourl = "wtv-1800:/preregister?";
|
||||
if (request_headers.query.relogin) gourl += "relogin=true";
|
||||
else if (request_headers.query.reconnect) gourl += "reconnect=true";
|
||||
|
||||
if (request_headers.query.guest_login) {
|
||||
if (request_headers.query.relogin || request_headers.query.reconnect) gourl += "&";
|
||||
gourl += "guest_login=true";
|
||||
if (request_headers.query.skip_splash) gourl += "&skip_splash=true";
|
||||
}
|
||||
|
||||
headers = `200 OK
|
||||
Connection: Keep-Alive
|
||||
Expires: Wed, 09 Oct 1991 22:00:00 GMT
|
||||
wtv-expire-all: wtv-head-waiter:
|
||||
wtv-expire-all: wtv-1800:
|
||||
wtv-service: reset
|
||||
${getServiceString('wtv-1800')}
|
||||
wtv-visit: ${gourl}
|
||||
Content-type: text/html`;
|
||||
data = '';
|
||||
@@ -12,6 +12,16 @@ if (ssid_sessions[socket.ssid].get('box-does-psuedo-encryption')) {
|
||||
var cryptstatus = ((socket_sessions[socket.id].secure === true) ? "Encrypted" : "Not Encrypted")
|
||||
}
|
||||
|
||||
var comp_type = shouldWeCompress(socket.ssid,'text/html');
|
||||
var compstatus = "uncompressed";
|
||||
switch (comp_type) {
|
||||
case 1:
|
||||
compstatus = "wtv-lzpf";
|
||||
break;
|
||||
case 2:
|
||||
compstatus = "gzip (level 9)";
|
||||
break;
|
||||
}
|
||||
|
||||
data = `<html>
|
||||
<head>
|
||||
@@ -24,13 +34,16 @@ function go() {
|
||||
location.href=document.access.url.value;
|
||||
}
|
||||
</script>
|
||||
<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>";
|
||||
<b>Welcome to ${z_title}`;
|
||||
if (ssid_sessions[socket.ssid].getSessionData("registered")) data += ", " + ssid_sessions[socket.ssid].getSessionData("subscriber_username") + "!";
|
||||
data += "</b><br>";
|
||||
if (minisrv_config.config.git_commit) data += `<div width="540" align="right"><font size="-4"><i>git revision ${minisrv_config.config.git_commit}</i></small></font></div><br>`;
|
||||
|
||||
data += `
|
||||
<b>Encryption Status</b>: ${cryptstatus}<br>
|
||||
<hr>
|
||||
<b>Status</b>: ${cryptstatus} (${compstatus})<br>
|
||||
<b>Connection Speed</b>: &rate;
|
||||
<p>
|
||||
<hr>
|
||||
<form name=access onsubmit="go()">
|
||||
<ul>
|
||||
<li><a href="client:relog">client:relog (direct)</a></li>
|
||||
@@ -45,7 +58,7 @@ if (ssid_sessions[socket.ssid].hasCap("client-has-disk")) {
|
||||
data += "<li><a href=\"client:diskhax\">DiskHax</a> ~ <a href=\"client:vfathax\">VFatHax</a></li>\n";
|
||||
if (ssid_sessions[socket.ssid].hasCap("client-can-do-macromedia-flash2")) {
|
||||
// only show demo if client can do flash2
|
||||
data += "<li>Old MSNTV DealerDemo: <a href=\"wtv-update:/DealerDemo\">Download</a> ~ <a href=\"file://Disk/Demo/index.html\"> Access (after Download)</a></li>\n";
|
||||
data += "<li>Old MSNTV DealerDemo: <a href=\"wtv-disk:/sync?group=DealerDemo&diskmap=DealerDemo\">Download</a> ~ <a href=\"file://Disk/Demo/index.html\"> Access (after Download)</a></li>\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -249,17 +249,17 @@ WARRANTY OF ANY KIND. THE INFORMATION, SOFTWARE, PRODUCTS, AND SERVICES INCLUDED
|
||||
THROUGH THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE MAY INCLUDE INACCURACIES OR TYPOGRAPHICAL ERRORS.
|
||||
ADVICE RECEIVED VIA THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE SHOULD NOT BE RELIED UPON FOR PERSONAL,
|
||||
MEDICAL, LEGAL OR FINANCIAL DECISIONS AND YOU SHOULD CONSULT AN APPROPRIATE
|
||||
PROFESSIONAL FOR SPECIFIC ADVICE TAILORED TO YOUR SITUATION. MICROSOFT,
|
||||
PROFESSIONAL FOR SPECIFIC ADVICE TAILORED TO YOUR SITUATION. ${WTVRegister.getServiceOperator().toUpperCase()},
|
||||
ITS RESELLERS, DISTRIBUTORS AND/OR SUPPLIERS DO NOT WARRANT THAT ACCESS TO
|
||||
OR USE OF THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE WILL BE UNINTERRUPTED OR ERROR-FREE, THAT MEMBERS
|
||||
WILL BE ABLE TO ACCESS THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE AT ANY TIME OR IN ANY GEOGRAPHIC AREA,
|
||||
OR THAT THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE OR ${WTVRegister.getServiceOperator().toUpperCase()} SOFTWARE OR SERVICES WILL MEET ANY
|
||||
PARTICULAR CRITERIA OF PERFORMANCE OR QUALITY. MICROSOFT, ITS RESELLERS,
|
||||
PARTICULAR CRITERIA OF PERFORMANCE OR QUALITY. ${WTVRegister.getServiceOperator().toUpperCase()}, ITS RESELLERS,
|
||||
DISTRIBUTORS AND/OR SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES AND CONDITIONS
|
||||
WITH REGARD TO THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE AND ALL RELATED SOFTWARE, INFORMATION,
|
||||
PRODUCTS, SERVICES AND GRAPHICS, INCLUDING ALL IMPLIED WARRANTIES AND
|
||||
CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, WORKMANLIKE
|
||||
EFFORT, TITLE, AND NON-INFRINGEMENT. IN NO EVENT SHALL MICROSOFT, ITS
|
||||
EFFORT, TITLE, AND NON-INFRINGEMENT. IN NO EVENT SHALL ${WTVRegister.getServiceOperator().toUpperCase()}, ITS
|
||||
RESELLERS, DISTRIBUTORS AND/OR SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
PUNITIVE, INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
|
||||
WHATSOEVER, INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF USE, DATA, OR
|
||||
@@ -281,7 +281,7 @@ DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR
|
||||
INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO YOU. IF YOU ARE
|
||||
DISSATISFIED WITH ANY PORTION OF THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE, OR WITH ANY OF THESE
|
||||
TERMS OF USE, YOUR SOLE AND EXCLUSIVE REMEDY IS TO NOT REGISTER FOR A ${minisrv_config.config.service_name.toUpperCase()}
|
||||
SERVICE ACCOUNT OR TO TERMINATE YOUR ${minisrv_config.config.service_name.toUpperCase()} SERVICE ACCOUNT. MICROSOFT MAY,
|
||||
SERVICE ACCOUNT OR TO TERMINATE YOUR ${minisrv_config.config.service_name.toUpperCase()} SERVICE ACCOUNT. ${WTVRegister.getServiceOperator().toUpperCase()} MAY,
|
||||
IN ITS SOLE DISCRETION AND WITHOUT PRIOR NOTICE (I) RESTRICT OR LIMIT ACCESS
|
||||
TO THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE; (II) TERMINATE A USER ACCOUNT OR USER SESSIONS AT ANY
|
||||
TIME; OR (III) DISCONTINUE OR MODIFY ANY OR ALL ASPECTS OF THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE OR ITS SERVICES.
|
||||
|
||||
@@ -40,7 +40,7 @@ Welcome
|
||||
ENCTYPE="x-www-form-encoded" METHOD="POST">
|
||||
<input type=hidden name=registering value="true">
|
||||
<td height=230 width= 300 bgcolor="#171726" colspan=5 valign=top align=left>
|
||||
Welcome to the ${minisrv_config.config.service_name} Mini Service, operated by ${minisrv_config.config.service_owner}
|
||||
Welcome to the ${minisrv_config.config.service_name} Mini Service, operated by ${minisrv_config.config.service_owner}.
|
||||
The next screens will lead you through a quick setup process for using this service.<p> Press the "Continue" button below to begin setup.<p>
|
||||
<td abswidth=20 bgcolor=#171726 >
|
||||
</tr>
|
||||
|
||||
@@ -20,13 +20,13 @@ data = `<html>
|
||||
<tr>
|
||||
<td><a href="wtv-tricks:/info">Info</a>
|
||||
<td width = 25>
|
||||
<td><a href="wtv-cookie:/list">List Cookies</a>
|
||||
<td><a href="wtv-cookie:list">List Cookies</a>
|
||||
<tr>
|
||||
<td colspan=3 height=6>
|
||||
<tr>
|
||||
<td><a href="wtv-flashrom:/willie">Visit Ultra Willie's!</a>
|
||||
<td width = 25>
|
||||
<td><a href="wtv-cookie:/reset">Clear Cookies</a>
|
||||
<td><a href="wtv-cookie:reset">Clear Cookies</a>
|
||||
<tr>
|
||||
<td colspan=3 height=6>
|
||||
<tr>
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
headers = `200 OK
|
||||
Content-Type: text/html`
|
||||
|
||||
data = `<html>
|
||||
<head>
|
||||
<meta
|
||||
http-equiv=refresh
|
||||
content="0;url=client:Fetch?group=DealerDemo&source=wtv-update:/sync%3Fdiskmap%3DDealerDemo&message=Retrieving%20Files..."
|
||||
>
|
||||
<display downloadsuccess="client:goback" downloadfail="client:ShowAlert?message=Download%20failed...&buttonlabel1=Okay...&buttonaction1=client:goback&noback=true">
|
||||
<title>Retrieving Files</title>
|
||||
</head>
|
||||
<body bgcolor=#0 text=#42CC55 fontsize=large hspace=0 vspace=0>
|
||||
<table cellspacing=0 cellpadding=0>
|
||||
<tr>
|
||||
<td width=104 height=74 valign=middle align=center bgcolor=3B3A4D>
|
||||
<img src="`+minisrv_config.config.service_logo+`" width=86 height=64>
|
||||
<td width=20 valign=top align=left bgcolor=3B3A4D>
|
||||
<spacer>
|
||||
<td colspan=2 width=436 valign=middle align=left bgcolor=3B3A4D>
|
||||
<font color=D6DFD0 size=+2><blackface><shadow>
|
||||
<spacer type=block width=1 height=4>
|
||||
<br>
|
||||
Retrieving Files
|
||||
</shadow>
|
||||
</blackface>
|
||||
</font>
|
||||
<tr>
|
||||
<td width=104 height=20>
|
||||
<td width=20>
|
||||
<td width=416>
|
||||
<td width=20>
|
||||
<tr>
|
||||
<td colspan=2>
|
||||
<td>
|
||||
<font size=+1>
|
||||
Your Internet terminal is retrieving some files.
|
||||
<p>This may take a while.
|
||||
</font>
|
||||
<tr>
|
||||
<td colspan=2>
|
||||
<td>
|
||||
<br><br>
|
||||
<font color=white>
|
||||
<progressindicator name="downloadprogress"
|
||||
message="Retrieving Files..."
|
||||
height=40 width=250>
|
||||
</font>
|
||||
</table>
|
||||
</body>
|
||||
</html>`
|
||||
@@ -1,187 +0,0 @@
|
||||
// todo: async
|
||||
|
||||
var path = require("path");
|
||||
|
||||
var content_dir = "content/"
|
||||
var diskmap_dir = content_dir + "diskmaps/";
|
||||
|
||||
function generateDownloadList(diskmap_group_data, update_list, diskmap_data) {
|
||||
// create WebTV Download List
|
||||
|
||||
var newest_file_epoch = 0;
|
||||
var download_list = '';
|
||||
|
||||
if (diskmap_data.partition_size) {
|
||||
download_list += "CREATE " + diskmap_data.base + "\n";
|
||||
download_list += "partition-size: " + diskmap_data.partition_size + "\n\n";
|
||||
}
|
||||
|
||||
download_list += "CREATE-GROUP " + diskmap_group_data + "-UPDATE\n";
|
||||
download_list += "state: invalid\n";
|
||||
download_list += "base: " + diskmap_data.base + ".GROUP-UPDATE/\n\n";
|
||||
|
||||
Object.keys(update_list).forEach(function (k) {
|
||||
if (parseInt(update_list[k]["Last-modified"]) > newest_file_epoch) newest_file_epoch = parseInt(update_list[k]["Last-modified"]);
|
||||
download_list += "DISPLAY " + update_list[k].display + "\n\n";
|
||||
download_list += "GET " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
|
||||
download_list += "group: " + diskmap_group_data + "-UPDATE\n";
|
||||
download_list += "location: " + service_name + ":/" + update_list[k].location + "\n";
|
||||
download_list += "file-permission: r\n"
|
||||
download_list += "wtv-checksum: " + update_list[k]["wtv-checksum"] + "\n";
|
||||
download_list += "service-source-location: /webtv/content/" + service_name.replace("wtv-","") + "d/" + update_list[k].location + "\n";
|
||||
download_list += "client-dest-location: " + update_list[k].file + "\n\n";
|
||||
});
|
||||
|
||||
download_list += "CREATE-GROUP " + diskmap_group_data + "\n";
|
||||
download_list += "state: invalid\n";
|
||||
download_list += "service-owned: " + (diskmap_data.service_owned || false) + "\n";
|
||||
download_list += "base: " + diskmap_data.base + "\n\n";
|
||||
|
||||
Object.keys(update_list).forEach(function (k) {
|
||||
download_list += "DELETE " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
|
||||
download_list += "group: " + diskmap_group_data + "\n\n";
|
||||
});
|
||||
|
||||
Object.keys(update_list).forEach(function (k) {
|
||||
download_list += "RENAME " + update_list[k].file.replace(diskmap_data.base, "") + "\n";
|
||||
download_list += "group: " + diskmap_group_data + "-UPDATE\n";
|
||||
download_list += "destination-group: " + diskmap_group_data + "\n";
|
||||
download_list += "location: " + update_list[k].file.replace(diskmap_data.base, "") + "\n\n";
|
||||
});
|
||||
|
||||
download_list += "DELETE-GROUP " + diskmap_group_data + "-UPDATE\n\n";
|
||||
|
||||
download_list += "SET-GROUP " + diskmap_group_data + "\n";
|
||||
download_list += "state: ok\n";
|
||||
download_list += "version: " + newest_file_epoch + "\n";
|
||||
download_list += "last-checkup-time: " + new Date().toUTCString().replace("GMT", "+0000") + "\n\n";
|
||||
|
||||
return download_list;
|
||||
}
|
||||
|
||||
function processGroup(diskmap_primary_group, diskmap_group_data, diskmap_subgroup = null) {
|
||||
// parse webtv post
|
||||
var output_data = '';
|
||||
var post_data = request_headers.post_data.toString(CryptoJS.enc.Latin1).split("\n");
|
||||
var post_data_current_directory = '';
|
||||
var post_data_current_file = '';
|
||||
var post_data_fileinfo = new Array();
|
||||
var post_data_filecount = -1;
|
||||
|
||||
Object.keys(post_data).forEach(function (k) {
|
||||
if (post_data[k] == "") return;
|
||||
if (post_data[k].substring(0, 7) == "file://") {
|
||||
post_data_current_directory = post_data[k];
|
||||
post_data_current_file = post_data[k];
|
||||
}
|
||||
if (post_data[k].indexOf(":") > 0) {
|
||||
var post_data_line = post_data[k].split(": ")
|
||||
var post_data_line_name = post_data_line[0];
|
||||
post_data_line.shift();
|
||||
var post_data_line_data = post_data_line.join(": ");
|
||||
|
||||
if (!post_data_fileinfo[post_data_filecount]) post_data_fileinfo[post_data_filecount] = new Array();
|
||||
|
||||
if (post_data_line_name == "Last-modified") {
|
||||
post_data_fileinfo[post_data_filecount][post_data_line_name] = (new Date(new Date(Date.parse(post_data_line_data)).toUTCString()) / 1000);
|
||||
} else if (post_data_line_name == "Content-length") {
|
||||
post_data_fileinfo[post_data_filecount][post_data_line_name] = parseInt(post_data_line_data);
|
||||
}
|
||||
else {
|
||||
post_data_fileinfo[post_data_filecount][post_data_line_name] = post_data_line_data;
|
||||
}
|
||||
} else {
|
||||
post_data_filecount++;
|
||||
post_data_current_file = post_data_current_directory + post_data[k];
|
||||
post_data_fileinfo[post_data_filecount] = new Array();
|
||||
post_data_fileinfo[post_data_filecount].file = post_data_current_file
|
||||
}
|
||||
});
|
||||
var wtv_download_list = new Array();
|
||||
Object.keys(diskmap_group_data.files).forEach(function (k) {
|
||||
if (!diskmap_group_data.files[k].location) diskmap_group_data.files[k].location = diskmap_group_data.location + diskmap_group_data.files[k].file.replace(diskmap_group_data.base, "");
|
||||
var post_match_file = null;
|
||||
Object.keys(service_vaults).forEach(function (g) {
|
||||
if (post_match_file != null) return;
|
||||
post_match_file = service_vaults[g] + "/" + service_name + "/" + diskmap_group_data.files[k].location;
|
||||
if (!fs.existsSync(post_match_file)) post_match_file = null;
|
||||
});
|
||||
|
||||
var file_in_postdata = function (post_file) {
|
||||
return post_file.file === diskmap_group_data.files[k].file
|
||||
}
|
||||
|
||||
var post_match_file_lstat = fs.lstatSync(post_match_file);
|
||||
var post_match_result = post_data_fileinfo.find(file_in_postdata) || null;
|
||||
var post_match_file_data = new Buffer.from(fs.readFileSync(post_match_file, {
|
||||
encoding: null,
|
||||
flags: 'r'
|
||||
}));
|
||||
diskmap_group_data.files[k]["Last-modified"] = (new Date(new Date(post_match_file_lstat.mtime).toUTCString()) / 1000);
|
||||
diskmap_group_data.files[k]["Content-length"] = post_match_file_lstat.size;
|
||||
diskmap_group_data.files[k]["wtv-checksum"] = CryptoJS.MD5(CryptoJS.lib.WordArray.create(post_match_file_data)).toString(CryptoJS.enc.Hex).toLowerCase();
|
||||
if (!diskmap_group_data.files[k].display) diskmap_group_data.files[k].display = diskmap_group_data.display;
|
||||
|
||||
if (post_match_result) {
|
||||
// md5s match, so client doesn't need file
|
||||
if (diskmap_group_data.files[k]['wtv-checksum'].toLowerCase() == post_match_result["wtv-checksum"]) return;
|
||||
// last modified is equal to or newer than the last update, and file size match, so assume same file and client does not need it
|
||||
else if ((post_match_result["Last-modified"] >= diskmap_group_data.files[k]["Last-modified"]) && (post_match_result["Content-length"] == diskmap_group_data.files[k]["Content-length"])) return;
|
||||
// otherwise send to client
|
||||
else wtv_download_list.push(diskmap_group_data.files[k]);
|
||||
} else {
|
||||
wtv_download_list.push(diskmap_group_data.files[k]);
|
||||
}
|
||||
var diskmap_group_name = (diskmap_subgroup == null) ? diskmap_primary_group : diskmap_primary_group + "-" + diskmap_subgroup;
|
||||
output_data = generateDownloadList(diskmap_group_name, wtv_download_list, diskmap_group_data)
|
||||
});
|
||||
return output_data;
|
||||
}
|
||||
|
||||
if (request_headers.query.diskmap && request_headers.query.group && request_headers.post_data) {
|
||||
var diskmap_json_file = null;
|
||||
Object.keys(service_vaults).forEach(function (g) {
|
||||
if (diskmap_json_file != null) return;
|
||||
diskmap_json_file = service_vaults[g] + "/" + service_name + "/" + diskmap_dir + request_headers.query.diskmap + ".json";
|
||||
if (!fs.existsSync(diskmap_json_file)) diskmap_json_file = null;
|
||||
});
|
||||
|
||||
if (diskmap_json_file != null) {
|
||||
if (fs.lstatSync(diskmap_json_file)) {
|
||||
try {
|
||||
// read diskmap
|
||||
var diskmap_data = JSON.parse(fs.readFileSync(diskmap_json_file).toString());
|
||||
if (!diskmap_data[request_headers.query.group]) {
|
||||
throw ("Invalid diskmap data (group does not match)");
|
||||
}
|
||||
data = '';
|
||||
diskmap_data = diskmap_data[request_headers.query.group];
|
||||
if (!diskmap_data.display) {
|
||||
Object.keys(diskmap_data).forEach(function (k) {
|
||||
if (diskmap_data[k]) data += processGroup(request_headers.query.group,diskmap_data[k],k);
|
||||
});
|
||||
} else {
|
||||
data = processGroup(request_headers.query.group, diskmap_data);
|
||||
}
|
||||
|
||||
headers = "200 OK\nContent-Type: wtv/download-list";
|
||||
} catch (e) {
|
||||
var errpage = doErrorPage(400);
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
console.log("wtv-update:/sync error", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var errpage = doErrorPage(404,"The requested DiskMap does not exist.");
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
if (zdebug) console.log(" # wtv-update:/sync error", "could not find diskmap");
|
||||
}
|
||||
} else {
|
||||
var errpage = doErrorPage(400);
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
if (zdebug) console.log(" # wtv-update:/sync error", "missing query arguments");
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
200 OK
|
||||
Content-Type: text/url
|
||||
|
||||
client:ShowAlert?message=HackTV%20Update%20was%20successful%21&buttonlabel2=Go%20to%20HackTV&action2=file%3A%2F%2FDisk%2FBrowser%2FGames%2FGames.html&buttonlabel1=Okay&buttonaction1=client:goback&image=file://disk/browser/Games/hacktv2.gif&noback=true
|
||||
@@ -1,3 +1,5 @@
|
||||
const { lib } = require('crypto-js');
|
||||
|
||||
class WTVClientSessionData {
|
||||
|
||||
fs = require('fs');
|
||||
@@ -38,7 +40,8 @@ class WTVClientSessionData {
|
||||
}
|
||||
}
|
||||
|
||||
constructor(hide_ssid_in_logs, session_storage_directory) {
|
||||
constructor(ssid, hide_ssid_in_logs, session_storage_directory) {
|
||||
this.ssid = ssid;
|
||||
if (hide_ssid_in_logs) this.hide_ssid_in_logs = hide_ssid_in_logs;
|
||||
if (!session_storage_directory) session_storage_directory = __dirname + "/SessionStore";
|
||||
this.session_storage = session_storage_directory;
|
||||
@@ -91,9 +94,6 @@ class WTVClientSessionData {
|
||||
|
||||
this.session_store.cookies[cookie_index] = Object.assign({}, cookie_data);
|
||||
|
||||
// do not write file if user is not registered
|
||||
if (getSessionData('registered')) this.storeSessionData();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -172,11 +172,13 @@ class WTVClientSessionData {
|
||||
return outstring;
|
||||
}
|
||||
|
||||
loadSessionData() {
|
||||
loadSessionData(raw_data = false) {
|
||||
try {
|
||||
if (this.fs.lstatSync(this.session_storage + this.path.sep + this.ssid + ".json")) {
|
||||
var session_data_file = this.fs.readFileSync(this.session_storage + this.path.sep + this.ssid + ".json", 'Utf8');
|
||||
var session_data = JSON.parse(session_data_file);
|
||||
var json_data = this.fs.readFileSync(this.session_storage + this.path.sep + this.ssid + ".json", 'Utf8')
|
||||
if (raw_data) return json_data;
|
||||
|
||||
var session_data = JSON.parse(json_data);
|
||||
this.session_store = session_data;
|
||||
return true;
|
||||
}
|
||||
@@ -188,14 +190,22 @@ class WTVClientSessionData {
|
||||
}
|
||||
|
||||
saveSessionData() {
|
||||
if (!this.session_store.registered) {
|
||||
if (this.isRegistered()) {
|
||||
// load data from disk and merge new data
|
||||
var temp_store = this.session_store;
|
||||
this.loadSessionData();
|
||||
this.session_store = Object.assign(this.session_store, temp_store);
|
||||
if (this.loadSessionData()) this.session_store = Object.assign(this.session_store, temp_store);
|
||||
else this.session_store = temp_store;
|
||||
temp_store = null;
|
||||
} else {
|
||||
// do not write file if user is not registered, return true because this is not an error
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
var store_data = JSON.stringify(this.session_store);
|
||||
this.fs.writeFileSync(this.session_storage + this.path.sep + this.ssid + ".json", store_data, "Utf8");
|
||||
// only save if file has changed
|
||||
var json_save_data = JSON.stringify(this.session_store);
|
||||
var json_load_data = this.loadSessionData(true);
|
||||
if (json_save_data != json_load_data) this.fs.writeFileSync(this.session_storage + this.path.sep + this.ssid + ".json", JSON.stringify(this.session_store), "Utf8");
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(" # Error saving session data for", this.filterSSID(this.ssid), e);
|
||||
@@ -205,7 +215,7 @@ class WTVClientSessionData {
|
||||
|
||||
retrieveSessionData() {
|
||||
// alias
|
||||
this.loadSessionData();
|
||||
return this.loadSessionData();
|
||||
}
|
||||
|
||||
storeSessionData() {
|
||||
@@ -213,16 +223,32 @@ class WTVClientSessionData {
|
||||
return this.saveSessionData();
|
||||
}
|
||||
|
||||
SaveIfRegistered() {
|
||||
if (this.isRegistered()) return this.saveSessionData();
|
||||
return false;
|
||||
}
|
||||
|
||||
isRegistered() {
|
||||
var self = this;
|
||||
var ssid_match = false;
|
||||
this.fs.readdirSync(this.session_storage).forEach(file => {
|
||||
if (!file.match(/.*\.json/ig)) return;
|
||||
if (ssid_match) return;
|
||||
if (file.split('.')[0] == self.ssid) ssid_match = true;
|
||||
});
|
||||
return ssid_match;
|
||||
}
|
||||
|
||||
unregisterBox() {
|
||||
try {
|
||||
if (this.fs.lstatSync(this.session_storage + this.path.sep + this.ssid + ".json")) {
|
||||
return this.fs.unlinkSync(this.session_storage + this.path.sep + this.ssid + ".json");
|
||||
this.fs.unlinkSync(this.session_storage + this.path.sep + this.ssid + ".json");
|
||||
this.session_store = {};
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
// Don't log error 'file not found', it just means the client isn't registered yet
|
||||
if (e.code != "ENOENT") console.error(" # Error deleting session data for", this.filterSSID(this.ssid), e);
|
||||
console.error(" # Error deleting session data for", this.filterSSID(this.ssid), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ class WTVFlashrom {
|
||||
}
|
||||
|
||||
|
||||
async doLocalFlashROM(flashrom_file_path, callback, info_only = false) {
|
||||
async doLocalFlashROM(flashrom_file_path, request_path, callback, info_only = false) {
|
||||
// use local flashrom files;
|
||||
console.log(info_only);
|
||||
var self = this;
|
||||
@@ -56,7 +56,7 @@ class WTVFlashrom {
|
||||
callback(data, headers);
|
||||
} else {
|
||||
if (info_only) {
|
||||
callback(self.getFlashromData(data, flashrom_file_path));
|
||||
callback(self.getFlashromInfo(data, request_path));
|
||||
} else {
|
||||
self.sendToClient(data, flashrom_file_path, callback);
|
||||
}
|
||||
@@ -117,7 +117,7 @@ class WTVFlashrom {
|
||||
flashrom_info.message = new Buffer.from(part_header.toString('hex').substring(36 * 2, 68 * 2), 'hex').toString('ascii').replace(/[^0-9a-z\ \.\-]/gi, "");
|
||||
|
||||
flashrom_info.is_last_part = ((flashrom_info.byte_progress + flashrom_info.part_total_size) == flashrom_info.total_parts_size) ? true : false;
|
||||
flashrom_info.rompath = 'wtv-flashrom:/get-by-path?path=' + path + '&raw=true';
|
||||
flashrom_info.rompath = `wtv-flashrom:/${path}`;
|
||||
if (this.zdebug) console.log(" # Flashrom Part Bytes Sent (after this part):", flashrom_info.byte_progress + flashrom_info.part_total_size);
|
||||
if (this.zdebug) console.log(" # Flashrom Part is Last Part", flashrom_info.is_last_part);
|
||||
|
||||
@@ -202,7 +202,7 @@ class WTVFlashrom {
|
||||
});
|
||||
req.end();
|
||||
} else {
|
||||
this.doLocalFlashROM(flashrom_file_path, callback, ((length != 0) ? true : false));
|
||||
this.doLocalFlashROM(flashrom_file_path, request_path, callback, ((length != 0) ? true : false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
/**
|
||||
* Pure-JS implementation of WebTV's LZPF compression
|
||||
*
|
||||
@@ -25,6 +23,7 @@ class WTVLzpf {
|
||||
encoded_data = [];
|
||||
|
||||
nomatchEncode = [
|
||||
|
||||
[0x0000, 0x10], [0x0001, 0x10], [0x0002, 0x10],
|
||||
[0x0003, 0x10], [0x0004, 0x10], [0x009A, 0x0F],
|
||||
[0x0005, 0x10], [0x009C, 0x0F], [0x009E, 0x0F],
|
||||
@@ -413,8 +412,8 @@ class WTVLzpf {
|
||||
* @returns {Buffer} Lzpf compression data
|
||||
*/
|
||||
Finish() {
|
||||
var code_length = -1
|
||||
var code = -1
|
||||
var code_length = -1;
|
||||
var code = -1;
|
||||
|
||||
if (this.type_index == 2) {
|
||||
this.EncodeLiteral(0x10, 0x00990000);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const zlib = require('zlib');
|
||||
const http = require('http');
|
||||
const https = require('https');
|
||||
const strftime = require('strftime'); // used externally by service scripts
|
||||
@@ -73,24 +74,31 @@ function getFileExt(path) {
|
||||
return path.reverse().split(".")[0].reverse();
|
||||
}
|
||||
|
||||
function doErrorPage(code, data = null) {
|
||||
function doErrorPage(code, data = null, pc_mode = false) {
|
||||
var headers = null;
|
||||
switch (code) {
|
||||
case 404:
|
||||
if (data === null) data = "The service could not find the requested page.";
|
||||
headers = "404 " + data + "\r\n";
|
||||
headers += "Content-Type: text/html\r\n";
|
||||
if (pc_mode) headers = "404 Not Found\n";
|
||||
else headers = code + " "+ data + "\n";
|
||||
headers += "Content-Type: text/html\n";
|
||||
break;
|
||||
case 400:
|
||||
case 500:
|
||||
if (data === null) data = "HackTV ran into a technical problem.";
|
||||
headers = "400 " + data + "\r\n";
|
||||
headers += "Content-Type: text/html\r\n";
|
||||
if (pc_mode) headers = "500 Internal Server Error\n";
|
||||
else headers = code + " " + data + "\n";
|
||||
headers += "Content-Type: text/html\n";
|
||||
break;
|
||||
case 401:
|
||||
if (data === null) data = "Access Denied.";
|
||||
if (pc_mode) headers = "401 Access Denied\n";
|
||||
else headers = code + " " + data + "\n";
|
||||
headers += "Content-Type: text/html\n";
|
||||
break;
|
||||
default:
|
||||
// what we send when we did not detect a wtv-url.
|
||||
// e.g. when a pc browser connects
|
||||
headers = "HTTP/1.1 200 OK\r\n";
|
||||
headers += "Content-Type: text/html\r\n";
|
||||
headers = code + " " + data + "\n";
|
||||
headers += "Content-Type: text/html\n";
|
||||
break;
|
||||
}
|
||||
console.error("doErrorPage Called:", code, data);
|
||||
@@ -100,68 +108,94 @@ function doErrorPage(code, data = null) {
|
||||
|
||||
function getConType(path) {
|
||||
var file_ext = getFileExt(path).toLowerCase();
|
||||
var wtv_mime_type = "";
|
||||
var modern_mime_type = "";
|
||||
// process WebTV overrides, fall back to generic mime lookup
|
||||
switch (file_ext) {
|
||||
case "aif":
|
||||
return "audio/x-aif";
|
||||
wtv_mime_type = "audio/x-aif";
|
||||
break;
|
||||
case "aifc":
|
||||
return "audio/x-aifc";
|
||||
wtv_mime_type = "audio/x-aifc";
|
||||
break;
|
||||
case "aiff":
|
||||
return "audio/x-aiff";
|
||||
wtv_mime_type = "audio/x-aiff";
|
||||
break;
|
||||
case "ani":
|
||||
return "x-wtv-animation";
|
||||
wtv_mime_type = "x-wtv-animation";
|
||||
break;
|
||||
case "brom":
|
||||
return "binary/x-wtv-bootrom";
|
||||
wtv_mime_type = "binary/x-wtv-bootrom";
|
||||
break;
|
||||
case "cdf":
|
||||
return "application/netcdf";
|
||||
wtv_mime_type = "application/netcdf";
|
||||
break;
|
||||
case "dat":
|
||||
return "binary/cache-data";
|
||||
wtv_mime_type = "binary/cache-data";
|
||||
break;
|
||||
case "dl":
|
||||
return "wtv/download-list";
|
||||
wtv_mime_type = "wtv/download-list";
|
||||
break;
|
||||
case "gsm":
|
||||
return "audio/x-gsm";
|
||||
wtv_mime_type = "audio/x-gsm";
|
||||
break;
|
||||
case "gz":
|
||||
return "application/gzip";
|
||||
wtv_mime_type = "application/gzip";
|
||||
break;
|
||||
case "ini":
|
||||
return "wtv/jack-configuration";
|
||||
wtv_mime_type = "wtv/jack-configuration";
|
||||
break;
|
||||
case "mips-code":
|
||||
return "code/x-wtv-code-mips";
|
||||
wtv_mime_type = "code/x-wtv-code-mips";
|
||||
break;
|
||||
case "o":
|
||||
return "binary/x-wtv-approm";
|
||||
wtv_mime_type = "binary/x-wtv-approm";
|
||||
break;
|
||||
case "ram":
|
||||
return "audio/x-pn-realaudio";
|
||||
wtv_mime_type = "audio/x-pn-realaudio";
|
||||
break;
|
||||
case "rom":
|
||||
return "binary/x-wtv-flashblock";
|
||||
wtv_mime_type = "binary/x-wtv-flashblock";
|
||||
break;
|
||||
case "rsp":
|
||||
return "wtv/jack-response";
|
||||
wtv_mime_type = "wtv/jack-response";
|
||||
break;
|
||||
case "swa":
|
||||
case "swf":
|
||||
return "application/x-shockwave-flash";
|
||||
wtv_mime_type = "application/x-shockwave-flash";
|
||||
break;
|
||||
case "srf":
|
||||
case "spl":
|
||||
return "wtv/jack-data";
|
||||
wtv_mime_type = "wtv/jack-data";
|
||||
break;
|
||||
case "ttf":
|
||||
return "wtv/jack-fonts";
|
||||
wtv_mime_type = "wtv/jack-fonts";
|
||||
break;
|
||||
case "tvch":
|
||||
return "wtv/tv-channels";
|
||||
wtv_mime_type = "wtv/tv-channels";
|
||||
break;
|
||||
case "tvl":
|
||||
return "wtv/tv-listings";
|
||||
wtv_mime_type = "wtv/tv-listings";
|
||||
break;
|
||||
case "tvsl":
|
||||
return "wtv/tv-smartlinks";
|
||||
wtv_mime_type = "wtv/tv-smartlinks";
|
||||
break;
|
||||
case "wad":
|
||||
return "binary/doom-data";
|
||||
wtv_mime_type = "binary/doom-data";
|
||||
break;
|
||||
case "mp2":
|
||||
case "hsb":
|
||||
case "rmf":
|
||||
case "s3m":
|
||||
case "mod":
|
||||
case "xm":
|
||||
return "application/Music";
|
||||
wtv_mime_type = "application/Music";
|
||||
break;
|
||||
}
|
||||
|
||||
// if we reach here, its not a WebTV specific override
|
||||
// or we are not yet aware of said override
|
||||
return mime.lookup(path);
|
||||
modern_mime_type = mime.lookup(path);
|
||||
if (wtv_mime_type == "") wtv_mime_type = modern_mime_type;
|
||||
return new Array(wtv_mime_type, modern_mime_type);
|
||||
}
|
||||
|
||||
async function processPath(socket, service_vault_file_path, request_headers = new Array(), service_name) {
|
||||
@@ -174,15 +208,33 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
|
||||
if (service_vault_found) return;
|
||||
service_vault_file_path = makeSafePath(service_vault_dir, service_path);
|
||||
|
||||
// deny access to catchall file name directly
|
||||
var service_path_split = service_path.split("/");
|
||||
var service_path_request_file = service_path_split[service_path_split.length - 1];
|
||||
if (minisrv_config.config.catchall_file_name) {
|
||||
var minisrv_catchall = null;
|
||||
if (minisrv_config.services[service_name]) minisrv_catchall = minisrv_config.services[service_name].catchall_file_name || minisrv_config.config.catchall_file_name || null;
|
||||
else minisrv_catchall = minisrv_config.config.catchall_file_name || null;
|
||||
if (minisrv_catchall) {
|
||||
if (service_path_request_file == minisrv_catchall) {
|
||||
var errpage = doErrorPage(401, "Access Denied");
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
minisrv_catchall, service_path_split, service_path_request_file = null;
|
||||
|
||||
if (fs.existsSync(service_vault_file_path)) {
|
||||
// file exists, read it and return it
|
||||
service_vault_found = true;
|
||||
request_is_async = true;
|
||||
if (!zquiet) console.log(" * Found " + service_vault_file_path + " to handle request (Direct File Mode) [Socket " + socket.id + "]");
|
||||
var contype = getConType(service_vault_file_path);
|
||||
var contypes = getConType(service_vault_file_path);
|
||||
headers = "200 OK\n"
|
||||
headers += "Content-Type: " + contype;
|
||||
headers += "Content-Type: " + contypes[0] + "\n";
|
||||
headers += "wtv-modern-content-type" + contypes[1];
|
||||
fs.readFile(service_vault_file_path, null, function (err, data) {
|
||||
sendToClient(socket, headers, data);
|
||||
});
|
||||
@@ -238,6 +290,31 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
|
||||
fs.readFile(service_vault_file_path + ".html", null, function (err, data) {
|
||||
sendToClient(socket, headers, data);
|
||||
});
|
||||
} else {
|
||||
// look for a catchallin the current path and all parent paths up until the service root
|
||||
if (minisrv_config.config.catchall_file_name) {
|
||||
var minisrv_catchall_file_name = null;
|
||||
if (minisrv_config.services[service_name]) minisrv_catchall_file_name = minisrv_config.services[service_name].catchall_file_name || minisrv_config.config.catchall_file_name || null;
|
||||
else minisrv_catchall_file_name = minisrv_config.config.catchall_file_name || null;
|
||||
if (minisrv_catchall_file_name) {
|
||||
var service_check_dir = service_vault_file_path.split(path.sep);
|
||||
service_check_dir.pop(); // pop filename
|
||||
|
||||
while (service_check_dir.join(path.sep) != service_vault_dir) {
|
||||
var catchall_file = service_check_dir.join(path.sep) + path.sep + minisrv_catchall_file_name;
|
||||
if (fs.existsSync(catchall_file)) {
|
||||
if (!zquiet) console.log(" * Found catchall at " + catchall_file + ".html to handle request (HTML Mode) [Socket " + socket.id + "]");
|
||||
var jscript_eval = fs.readFileSync(catchall_file).toString();
|
||||
// don't pass these vars to the script
|
||||
var service_check_dir, minisrv_catchall_file_name = null;
|
||||
eval(jscript_eval);
|
||||
if (request_is_async && !zquiet) console.log(" * Script requested Asynchronous mode");
|
||||
} else {
|
||||
service_check_dir.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// either `request_is_async`, or `headers` and `data` MUST be defined by this point!
|
||||
});
|
||||
@@ -250,12 +327,12 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
|
||||
if (!request_is_async) {
|
||||
if (!service_vault_found) {
|
||||
console.error(" * Could not find a Service Vault for " + service_name + ":/" + service_path.replace(service_name + path.sep, ""));
|
||||
var errpage = doErrorPage(404);
|
||||
var errpage = doErrorPage(404, null, socket.minisrv_pc_mode);
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
}
|
||||
if (headers == null && !request_is_async) {
|
||||
var errpage = doErrorPage(400);
|
||||
var errpage = doErrorPage(400, null, socket.minisrv_pc_mode);
|
||||
headers = errpage[0];
|
||||
data = errpage[1];
|
||||
console.error(" * Scripting or Data error: Headers were not defined. (headers,data) as follows:")
|
||||
@@ -279,8 +356,8 @@ function filterSSID(obj) {
|
||||
return obj.substr(0, 6) + ('*').repeat(9);
|
||||
}
|
||||
} else {
|
||||
if (obj["wtv-client-serial-number"]) {
|
||||
var ssid = obj["wtv-client-serial-number"];
|
||||
if (makeSafeSSID(obj["wtv-client-serial-number"])) {
|
||||
var ssid = makeSafeSSID(obj["wtv-client-serial-number"]);
|
||||
if (ssid.substr(0, 8) == "MSTVSIMU") {
|
||||
obj["wtv-client-serial-number"] = ssid.substr(0, 10) + ('*').repeat(10) + ssid.substr(20);
|
||||
} else if (ssid.substr(0, 5) == "1SEGA") {
|
||||
@@ -296,6 +373,12 @@ function filterSSID(obj) {
|
||||
}
|
||||
}
|
||||
|
||||
function makeSafeSSID(ssid = "") {
|
||||
ssid = ssid.replace(/[^a-zA-Z0-9]/g, "");
|
||||
if (ssid.length == 0) ssid = null;
|
||||
return ssid;
|
||||
}
|
||||
|
||||
function makeSafePath(base, target) {
|
||||
target.replace(/[\|\&\;\$\%\@\"\<\>\+\,\\]/g, "");
|
||||
if (path.sep != "/") target = target.replace(/\//g, path.sep);
|
||||
@@ -304,9 +387,6 @@ function makeSafePath(base, target) {
|
||||
}
|
||||
|
||||
async function processURL(socket, request_headers) {
|
||||
if (request_headers === null) {
|
||||
return;
|
||||
}
|
||||
var shortURL, headers, data = "";
|
||||
request_headers.query = new Array();
|
||||
if (request_headers.request_url) {
|
||||
@@ -353,11 +433,46 @@ async function processURL(socket, request_headers) {
|
||||
}
|
||||
}
|
||||
|
||||
if ((shortURL.indexOf("http") != 0 && shortURL.indexOf("ftp") != 0 && shortURL.indexOf(":") > 0 && shortURL.indexOf(":/") == -1)) {
|
||||
// Apparently it is within WTVP spec to accept urls without a slash (eg wtv-home:home)
|
||||
// Here, we just reassemble the request URL as if it was a proper URL (eg wtv-home:/home)
|
||||
// we will allow this on any service except http(s) and ftp
|
||||
var shortURL_split = shortURL.split(':');
|
||||
var shortURL_service_name = shortURL_split[0];
|
||||
shortURL_split.shift();
|
||||
var shortURL_service_path = shortURL_split.join(":");
|
||||
shortURL = shortURL_service_name + ":/" + shortURL_service_path;
|
||||
} else if (shortURL.indexOf(":") == -1 && request_headers.request.indexOf("HTTP/1") > 0) {
|
||||
if (request_headers.Host) {
|
||||
if (minisrv_config.config.pc_server_hidden_service_enabled) {
|
||||
// browsers typically send a Host header
|
||||
service_name = minisrv_config.config.pc_server_hidden_service;
|
||||
socket.minisrv_pc_mode = true;
|
||||
shortURL = service_name + ":" + shortURL;
|
||||
|
||||
// if a directory, request index
|
||||
if (shortURL.substring(shortURL.length - 1) == "/") shortURL += "index";
|
||||
} else {
|
||||
// minimal pc mode to send error
|
||||
socket.minisrv_pc_mode = true;
|
||||
var errpage = doErrorPage(401, "PC services are disabled on this server", socket.minisrv_pc_mode);
|
||||
headers = errpage[0];
|
||||
data = errpage[1]
|
||||
socket_sessions[socket.id].close_me = true;
|
||||
sendToClient(socket, headers, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shortURL.indexOf(':/') >= 0 && shortURL.indexOf('://') < 0) {
|
||||
var ssid = socket.ssid;
|
||||
if (ssid == null) {
|
||||
ssid = request_headers["wtv-client-serial-number"];
|
||||
// prevent possible injection attacks via SSID and filesystem SessionStore
|
||||
ssid = makeSafeSSID(request_headers["wtv-client-serial-number"]);
|
||||
if (ssid == "") ssid = null;
|
||||
}
|
||||
|
||||
var reqverb = "Request";
|
||||
if (request_headers.encrypted || request_headers.secure) {
|
||||
reqverb = "Encrypted " + reqverb;
|
||||
@@ -475,6 +590,7 @@ async function doHTTPProxy(socket, request_headers) {
|
||||
]);
|
||||
if (data_hex.substring(0, 8) == "0d0a0d0a") data_hex = data_hex.substring(8);
|
||||
if (data_hex.substring(0, 4) == "0a0a") data_hex = data_hex.substring(4);
|
||||
headers["wtv-http-proxy"] = true;
|
||||
sendToClient(socket, headers, Buffer.from(data_hex,'hex'));
|
||||
});
|
||||
}).on('error', function (err) {
|
||||
@@ -554,8 +670,69 @@ function headerStringToObj(headers, response = false) {
|
||||
return headers_obj;
|
||||
}
|
||||
|
||||
async function sendToClient(socket, headers_obj, data) {
|
||||
function shouldWeCompress(ssid, headers_obj) {
|
||||
var compress_data = false;
|
||||
var compression_type = 0; // no compression
|
||||
if (ssid_sessions[ssid]) {
|
||||
if (ssid_sessions[ssid].capabilities) {
|
||||
if (ssid_sessions[ssid].capabilities['client-can-receive-compressed-data']) {
|
||||
|
||||
if (minisrv_config.config.enable_lzpf_compression || minisrv_config.config.force_compression_type) {
|
||||
compression_type = 1; // lzpf
|
||||
}
|
||||
|
||||
if (ssid_sessions[ssid]) {
|
||||
// if gzip is enabled...
|
||||
if (minisrv_config.config.enable_gzip_compression || minisrv_config.config.force_compression_type) {
|
||||
var is_bf0app = ssid_sessions[ssid].get("wtv-client-rom-type") == "bf0app";
|
||||
var is_minibrowser = (ssid_sessions[ssid].get("wtv-needs-upgrade") || ssid_sessions[ssid].get("wtv-used-8675309"));
|
||||
var is_softmodem = ssid_sessions[ssid].get("wtv-client-rom-type").match(/softmodem/);
|
||||
if (!is_bf0app && ((!is_softmodem && !is_minibrowser) || (is_softmodem && !is_minibrowser))) {
|
||||
// softmodem boxes do not appear to support gzip in the minibrowser
|
||||
// LC2 appears to support gzip even in the MiniBrowser
|
||||
// LC2 and newer approms appear to support gzip
|
||||
// bf0app does not appear to support gzip
|
||||
compression_type = 2; // gzip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// mostly for debugging
|
||||
if (minisrv_config.config.force_compression_type == "lzpf") compression_type = 1;
|
||||
if (minisrv_config.config.force_compression_type == "gzip") compression_type = 2;
|
||||
|
||||
// do not compress if already encoded
|
||||
if (headers_obj["Content-Encoding"]) return 0;
|
||||
|
||||
// should we bother to compress?
|
||||
var content_type = "";
|
||||
if (typeof (headers_obj) == 'string') content_type = headers_obj;
|
||||
else content_type = (typeof (headers_obj["wtv-modern-content-type"]) != 'undefined') ? headers_obj["wtv-modern-content-type"] : headers_obj["Content-Type"];
|
||||
|
||||
if (content_type) {
|
||||
// both lzpf and gzip
|
||||
if (content_type.match(/^text\//) && content_type != "text/tellyscript") compress_data = true;
|
||||
else if (content_type.match(/^application\/(x-?)javascript$/)) compress_data = true;
|
||||
else if (content_type == "application/json") compress_data = true;
|
||||
if (compression_type == 2) {
|
||||
// gzip only
|
||||
if (content_type.match(/^audio\/(x-)?[s3m|mod|xm]$/)) compress_data = true; // s3m, mod, xm
|
||||
if (content_type.match(/^audio\/(x-)?[midi|wav|wave]$/)) compress_data = true; // midi & wav
|
||||
if (content_type.match(/^binary\/x-wtv-approm$/)) compress_data = true; // midi & wav
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return compression_type if compress_data = true
|
||||
return (compress_data) ? compression_type : 0;
|
||||
}
|
||||
|
||||
async function sendToClient(socket, headers_obj, data) {
|
||||
var headers = "";
|
||||
var content_length = 0;
|
||||
if (typeof (data) === 'undefined') data = '';
|
||||
@@ -576,11 +753,11 @@ async function sendToClient(socket, headers_obj, data) {
|
||||
headers_obj = moveObjectElement('Connection', 'http_response', headers_obj);
|
||||
}
|
||||
|
||||
var clen = 0;
|
||||
var content_length = 0;
|
||||
if (typeof data.length !== 'undefined') {
|
||||
clen = data.length;
|
||||
content_length = data.length;
|
||||
} else if (typeof data.byteLength !== 'undefined') {
|
||||
clen = data.byteLength;
|
||||
content_length = data.byteLength;
|
||||
}
|
||||
|
||||
// fix captialization
|
||||
@@ -589,31 +766,50 @@ async function sendToClient(socket, headers_obj, data) {
|
||||
delete headers_obj["Content-type"];
|
||||
}
|
||||
|
||||
|
||||
// if box can do compression, see if its worth enabling
|
||||
if (ssid_sessions[socket.ssid].capabilities) {
|
||||
if (ssid_sessions[socket.ssid].capabilities['client-can-receive-compressed-data'] && minisrv_config.config.enable_lzpf_compression) {
|
||||
compress_data = shouldWeCompress(headers_obj["Content-Type"]);
|
||||
}
|
||||
}
|
||||
// small files actually get larger, so don't compress them
|
||||
var compression_type = 0;
|
||||
if (content_length >= 256) compression_type = shouldWeCompress(socket.ssid, headers_obj);
|
||||
|
||||
// compress if needed
|
||||
if (compress_data && clen > 0) {
|
||||
content_length = clen;
|
||||
|
||||
if (compression_type > 0 && content_length > 0 && headers_obj['http_response'].substring(0,3) == "200") {
|
||||
var uncompressed_content_length = content_length;
|
||||
switch (compression_type) {
|
||||
case 1:
|
||||
// wtv-lzpf implementation
|
||||
headers_obj["wtv-lzpf"] = 0;
|
||||
|
||||
var wtvcomp = new WTVLzpf();
|
||||
data = wtvcomp.Compress(data);
|
||||
|
||||
wtvcomp = null; // Makes the garbage gods happy so it cleans up our mess
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// zlib gzip implementation
|
||||
headers_obj['Content-Encoding'] = 'gzip';
|
||||
data = zlib.gzipSync(data, {
|
||||
'level': 9
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
var compressed_content_length = 0;
|
||||
if (content_length == 0 || compression_type != 1) {
|
||||
// ultimately send compressed content length
|
||||
compressed_content_length = data.byteLength;
|
||||
content_length = compressed_content_length;
|
||||
} else {
|
||||
// ultimately send original content length if lzpf
|
||||
compressed_content_length = data.byteLength;
|
||||
}
|
||||
var compression_percentage = ((compressed_content_length / uncompressed_content_length) * 100).toFixed(1).toString() + "%";
|
||||
if (uncompressed_content_length != compressed_content_length) if (zdebug) console.log(" # Compression stats: Orig Size:", uncompressed_content_length, "~ Comp Size:", compressed_content_length, "~ Ratio:", compression_percentage);
|
||||
}
|
||||
|
||||
// encrypt if needed
|
||||
if (socket_sessions[socket.id].secure == true) {
|
||||
headers_obj["wtv-encrypted"] = 'true';
|
||||
headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj);
|
||||
if (clen > 0 && socket_sessions[socket.id].wtvsec) {
|
||||
if (content_length > 0 && socket_sessions[socket.id].wtvsec) {
|
||||
if (!zquiet) console.log(" * Encrypting response to client ...")
|
||||
var enc_data = socket_sessions[socket.id].wtvsec.Encrypt(1, data);
|
||||
data = enc_data;
|
||||
@@ -625,14 +821,6 @@ async function sendToClient(socket, headers_obj, data) {
|
||||
if (headers_obj["Content-Length"]) delete headers_obj["Content-Length"];
|
||||
if (headers_obj["Content-length"]) delete headers_obj["Content-length"];
|
||||
|
||||
if (content_length == 0) {
|
||||
if (typeof data.length !== 'undefined') {
|
||||
content_length = data.length;
|
||||
} else if (typeof data.byteLength !== 'undefined') {
|
||||
content_length = data.byteLength;
|
||||
}
|
||||
}
|
||||
|
||||
headers_obj["Content-length"] = content_length;
|
||||
|
||||
if (ssid_sessions[socket.ssid]) {
|
||||
@@ -648,10 +836,10 @@ async function sendToClient(socket, headers_obj, data) {
|
||||
}
|
||||
|
||||
var end_of_line = "\n";
|
||||
if (headers_obj['minisrv-use-carriage-return'] == "true") end_of_line = "\r\n";
|
||||
if (headers_obj['minisrv-use-carriage-return']) delete headers_obj['minisrv-use-carriage-return'];
|
||||
|
||||
if (end_of_line == "\r\n" && zdebug) console.log(" * Script requested to send headers with carriage return (out of WTVP Spec)");
|
||||
if (socket.minisrv_pc_mode) {
|
||||
end_of_line = "\r\n";
|
||||
headers_obj['http_response'] = "HTTP/1.0 " + headers_obj['http_response'];
|
||||
}
|
||||
|
||||
// header object to string
|
||||
if (zshowheaders) console.log(" * Outgoing headers on socket ID", socket.id, (await filterSSID(headers_obj)));
|
||||
@@ -684,7 +872,7 @@ async function sendToClient(socket, headers_obj, data) {
|
||||
} else {
|
||||
socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + end_of_line), data)));
|
||||
}
|
||||
if (zquiet) console.log(" * Sent" + verbosity_mod + " " + headers_obj.http_response + " to client (Content-Type:", headers_obj['Content-Type'], "~", headers_obj['Content-Length'], "bytes)");
|
||||
if (zquiet) console.log(" * Sent" + verbosity_mod + " " + headers_obj.http_response + " to client (Content-Type:", headers_obj['Content-Type'], "~", headers_obj['Content-length'], "bytes)");
|
||||
}
|
||||
|
||||
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
|
||||
@@ -698,25 +886,12 @@ async function sendToClient(socket, headers_obj, data) {
|
||||
|
||||
if (socket_sessions[socket.id].close_me) socket.end();
|
||||
if (headers_obj["Connection"]) {
|
||||
if (headers_obj["Connection"].toLowerCase() == "close" || wtv_connection_close == "true") {
|
||||
if (headers_obj["Connection"].toLowerCase() == "close" && wtv_connection_close == "true") {
|
||||
socket.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function shouldWeCompress(content_type) {
|
||||
if (typeof (content_type) != 'undefined') {
|
||||
if ((content_type.match(/^text\//) && content_type != "text/tellyscript") ||
|
||||
content_type.match(/^application\/(x-?)javascript$/) ||
|
||||
content_type.match(/^audio\/(x-)?midi/) ||
|
||||
content_type.match(/^audio\/(x-)?wav/) ||
|
||||
content_type == "application/json") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function concatArrayBuffer(buffer1, buffer2) {
|
||||
var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
|
||||
tmp.set(new Uint8Array(buffer1), 0);
|
||||
@@ -757,7 +932,7 @@ function isUnencryptedString(string, verbose = false) {
|
||||
}
|
||||
|
||||
function filterSSID(ssid) {
|
||||
var WTVCSD = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs);
|
||||
var WTVCSD = new WTVClientSessionData(null,minisrv_config.config.hide_ssid_in_logs);
|
||||
return WTVCSD.filterSSID(ssid);
|
||||
}
|
||||
|
||||
@@ -827,15 +1002,18 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
||||
|
||||
if (!headers) return;
|
||||
|
||||
if (headers["wtv-client-serial-number"] != null) {
|
||||
socket.ssid = headers["wtv-client-serial-number"];
|
||||
if (headers["wtv-client-serial-number"] != null && socket.ssid == null) {
|
||||
socket.ssid = makeSafeSSID(headers["wtv-client-serial-number"]);
|
||||
if (socket.ssid != null) {
|
||||
if (!ssid_sessions[socket.ssid]) {
|
||||
ssid_sessions[socket.ssid] = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs);
|
||||
ssid_sessions[socket.ssid] = new WTVClientSessionData(socket.ssid,minisrv_config.config.hide_ssid_in_logs);
|
||||
ssid_sessions[socket.ssid].SaveIfRegistered();
|
||||
}
|
||||
if (!ssid_sessions[socket.ssid].data_store.sockets) ssid_sessions[socket.ssid].data_store.sockets = new Set();
|
||||
ssid_sessions[socket.ssid].ssid = socket.ssid;
|
||||
ssid_sessions[socket.ssid].data_store.sockets.add(socket);
|
||||
}
|
||||
}
|
||||
|
||||
var ip2long = function (ip) {
|
||||
var components;
|
||||
@@ -920,7 +1098,8 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
|
||||
|
||||
if (headers["wtv-capability-flags"] != null) {
|
||||
if (!ssid_sessions[socket.ssid]) {
|
||||
ssid_sessions[socket.ssid] = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs);
|
||||
ssid_sessions[socket.ssid] = new WTVClientSessionData(socket.ssid,minisrv_config.config.hide_ssid_in_logs);
|
||||
ssid_sessions[socket.ssid].SaveIfRegistered();
|
||||
}
|
||||
if (!ssid_sessions[socket.ssid].capabilities) ssid_sessions[socket.ssid].capabilities = new WTVClientCapabilities(headers["wtv-capability-flags"]);
|
||||
}
|
||||
@@ -1249,7 +1428,10 @@ async function cleanupSocket(socket) {
|
||||
// set timer to destroy entirety of session data if client does not return in X time
|
||||
var timeout = 180000; // timeout is in milliseconds, default 180000 (3 min) .. be sure to allow time for dialup reconnections
|
||||
|
||||
if (!ssid_sessions[socket.ssid].data_store.socket_check) {
|
||||
// clear any existing timeout check
|
||||
if (ssid_sessions[socket.ssid].data_store.socket_check) clearTimeout(ssid_sessions[socket.ssid].data_store.socket_check);
|
||||
|
||||
// set timeout to check
|
||||
ssid_sessions[socket.ssid].data_store.socket_check = setTimeout(function (ssid) {
|
||||
if (ssid_sessions[ssid].currentConnections() === 0) {
|
||||
if (!zquiet) console.log(" * WebTV SSID", filterSSID(ssid), " has not been seen in", (timeout / 1000), "seconds, cleaning up session data for this SSID");
|
||||
@@ -1258,7 +1440,6 @@ async function cleanupSocket(socket) {
|
||||
}, timeout, socket.ssid);
|
||||
}
|
||||
}
|
||||
}
|
||||
socket.end();
|
||||
} catch (e) {
|
||||
console.error(" # Could not clean up socket data for socket ID", socket.id, e);
|
||||
@@ -1270,6 +1451,7 @@ async function handleSocket(socket) {
|
||||
// create unique socket id with client address and port
|
||||
socket.id = parseInt(crc16('CCITT-FALSE', Buffer.from(String(socket.remoteAddress) + String(socket.remotePort), "utf8")).toString(16), 16);
|
||||
socket_sessions[socket.id] = [];
|
||||
socket.minisrv_pc_mode = false;
|
||||
socket.setEncoding('hex'); //set data encoding (Text: 'ascii', 'utf8' ~ Binary: 'hex', 'base64' (do not trust 'binary' encoding))
|
||||
socket.setTimeout(10800000); // 3 hours
|
||||
socket.on('data', function (data_hex) {
|
||||
|
||||
@@ -14,8 +14,12 @@
|
||||
"post_percentages": [ 0, 25, 50, 100 ],
|
||||
"verbosity": 2,
|
||||
"error_log_file": "errors.log",
|
||||
"allow_guests": true,
|
||||
"enable_lzpf_compression": true
|
||||
"catchall_file_name": "catchall.js",
|
||||
"enable_lzpf_compression": false,
|
||||
"enable_gzip_compression": true,
|
||||
"pc_server_hidden_service": "http_pc",
|
||||
"pc_server_hidden_service_enabled": false,
|
||||
"allow_guests": true
|
||||
},
|
||||
"services": {
|
||||
"wtv-head-waiter": {
|
||||
@@ -52,7 +56,8 @@
|
||||
"flags": "0x00000040",
|
||||
"debug": false,
|
||||
"use_zefie_server": true,
|
||||
"bf0app_default_rom": "content/artemis-webtv-000/build7181/daily-nondebug/bf0app-part000.rom"
|
||||
"bf0app_default_rom": "content/artemis-webtv-000/build7181/daily-nondebug/bf0app-part000.rom",
|
||||
"catchall_file_name": "content-serve.js"
|
||||
},
|
||||
"wtv-setup": {
|
||||
"port": 1613,
|
||||
@@ -67,7 +72,7 @@
|
||||
"port": 1630,
|
||||
"connections": 3
|
||||
},
|
||||
"wtv-update": {
|
||||
"wtv-disk": {
|
||||
"port": 1635,
|
||||
"connections": 3
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "zefie_wtvp_minisrv",
|
||||
"version": "0.9.13",
|
||||
"version": "0.9.16",
|
||||
"description": "WebTV Service (WTVP) Emulation Server",
|
||||
"main": "app.js",
|
||||
"homepage": "https://github.com/zefie/zefie_wtvp_minisrv",
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
<Content Include=".gitignore" />
|
||||
<Content Include="app.js" />
|
||||
<Content Include="config.json" />
|
||||
<Content Include="ServiceVault\http_pc\get.js" />
|
||||
<Content Include="ServiceVault\http_pc\index.js" />
|
||||
<Content Include="ServiceVault\wtv-1800\noflash.js" />
|
||||
<Content Include="ServiceVault\wtv-1800\offer-open-isp-suggest.js" />
|
||||
<Content Include="ServiceVault\wtv-chat\home.js" />
|
||||
@@ -50,6 +52,7 @@
|
||||
<Content Include="ServiceVault\wtv-cookie\reset.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-flashrom\content\content-serve.js" />
|
||||
<Content Include="ServiceVault\wtv-flashrom\current-noflash.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
@@ -71,6 +74,9 @@
|
||||
<Content Include="ServiceVault\wtv-flashrom\ROMCache\up-arrows.swf" />
|
||||
<Content Include="ServiceVault\wtv-flashrom\ROMCache\WebTVLogoJewel.gif" />
|
||||
<Content Include="ServiceVault\wtv-flashrom\willie.js" />
|
||||
<Content Include="ServiceVault\wtv-head-waiter\relogin.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-music\demo\hacktv4.gif" />
|
||||
<Content Include="ServiceVault\wtv-music\demo\index.html" />
|
||||
<Content Include="ServiceVault\wtv-music\demo\midi\acey.mid" />
|
||||
@@ -247,15 +253,13 @@
|
||||
<Content Include="ServiceVault\wtv-tricks\unregister.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-update\content\diskmaps\DealerDemo.json">
|
||||
<Content Include="ServiceVault\wtv-disk\content\diskmaps\DealerDemo.json">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-update\sync.js">
|
||||
<Content Include="ServiceVault\wtv-disk\sync.js">
|
||||
<SubType>Code</SubType>
|
||||
</Content>
|
||||
<Content Include="ServiceVault\wtv-update\DealerDemo.js" />
|
||||
<Content Include="ServiceVault\wtv-home\home.js" />
|
||||
<Content Include="ServiceVault\wtv-update\updatesuccess.txt" />
|
||||
<Content Include="ServiceVault\wtv-1800\preregister.js" />
|
||||
<Content Include="ServiceVault\wtv-head-waiter\finalize-security.js" />
|
||||
<Content Include="ServiceVault\wtv-head-waiter\login-stage-two.js" />
|
||||
@@ -287,10 +291,12 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="ServiceVault\" />
|
||||
<Folder Include="ServiceVault\http_pc\" />
|
||||
<Folder Include="ServiceVault\wtv-chat\" />
|
||||
<Folder Include="ServiceVault\wtv-chat\images\" />
|
||||
<Folder Include="ServiceVault\wtv-cookie\" />
|
||||
<Folder Include="ServiceVault\wtv-flashrom\" />
|
||||
<Folder Include="ServiceVault\wtv-flashrom\content\" />
|
||||
<Folder Include="ServiceVault\wtv-flashrom\ROMCache\" />
|
||||
<Folder Include="ServiceVault\wtv-music\" />
|
||||
<Folder Include="ServiceVault\wtv-music\demo\" />
|
||||
@@ -300,13 +306,13 @@
|
||||
<Folder Include="ServiceVault\wtv-star\" />
|
||||
<Folder Include="ServiceVault\wtv-star\ROMCache\" />
|
||||
<Folder Include="ServiceVault\wtv-tricks\" />
|
||||
<Folder Include="ServiceVault\wtv-update\" />
|
||||
<Folder Include="ServiceVault\wtv-disk\" />
|
||||
<Folder Include="ServiceVault\wtv-1800\" />
|
||||
<Folder Include="ServiceVault\wtv-head-waiter\" />
|
||||
<Folder Include="ServiceVault\wtv-home\" />
|
||||
<Folder Include="ServiceVault\wtv-log\" />
|
||||
<Folder Include="ServiceVault\wtv-update\content\" />
|
||||
<Folder Include="ServiceVault\wtv-update\content\diskmaps\" />
|
||||
<Folder Include="ServiceVault\wtv-disk\content\" />
|
||||
<Folder Include="ServiceVault\wtv-disk\content\diskmaps\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\Node.js Tools\Microsoft.NodejsToolsV2.targets" />
|
||||
</Project>
|
||||