From 6f2fa1d5107e4b4ddb9fdc347adf73985d9b4d44 Mon Sep 17 00:00:00 2001 From: zefie Date: Sun, 8 Aug 2021 18:19:56 -0400 Subject: [PATCH] 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 --- README.md | 4 +- docker-compose/docker-compose.yml | 5 +- docker-compose/minisrv/Dockerfile | 2 + user_config_README.md | 5 + .../ServiceVault/http_pc/get.js | 37 ++ .../ServiceVault/http_pc/index.js | 31 ++ .../ServiceVault/wtv-1800/preregister.js | 2 +- .../content/DealerDemo/allyouneed.html | 0 .../content/DealerDemo/allyouneed.swf | Bin .../content/DealerDemo/attractloop.swf | Bin .../content/DealerDemo/communicate.html | 0 .../content/DealerDemo/communicate.swf | Bin .../DealerDemo/images/buttonsplus_all.gif | Bin .../DealerDemo/images/buttonsplus_comm.gif | Bin .../images/buttonsplus_interactive.gif | Bin .../images/buttonsplus_internet.gif | Bin .../DealerDemo/images/buttonsplus_try.gif | Bin .../content/DealerDemo/images/spacer.gif | Bin .../content/DealerDemo/index.html | 0 .../content/DealerDemo/interactive.html | 0 .../content/DealerDemo/interactive.swf | Bin .../content/DealerDemo/internet.html | 0 .../content/DealerDemo/internet.swf | Bin .../content/DealerDemo/mainmenu.html | 0 .../content/DealerDemo/mainmenu.swf | Bin .../content/DealerDemo/trymsntv.html | 0 .../content/DealerDemo/trymsntv.swf | Bin .../content/diskmaps/DealerDemo.json | 0 .../ServiceVault/wtv-disk/sync.js | 311 ++++++++++++++ .../wtv-flashrom/content/content-serve.js | 23 + .../ServiceVault/wtv-flashrom/get-by-path.js | 6 +- .../ServiceVault/wtv-flashrom/get-lc2-page.js | 21 +- .../wtv-flashrom/initiate-lc2-download.js | 7 +- .../wtv-flashrom/lc2-download-complete.js | 10 +- .../wtv-flashrom/lc2-download-failed.js | 12 +- .../ServiceVault/wtv-flashrom/willie.js | 6 +- .../wtv-head-waiter/login-stage-two.js | 11 +- .../ServiceVault/wtv-head-waiter/login.js | 6 +- .../ServiceVault/wtv-head-waiter/relogin.js | 20 + .../ServiceVault/wtv-home/home.js | 25 +- .../ServiceVault/wtv-register/ServeLegal.js | 8 +- .../ServiceVault/wtv-register/register.js | 2 +- .../ServiceVault/wtv-tricks/tricks.js | 4 +- .../ServiceVault/wtv-update/DealerDemo.js | 51 --- .../ServiceVault/wtv-update/sync.js | 187 -------- .../ServiceVault/wtv-update/updatesuccess.txt | 4 - zefie_wtvp_minisrv/WTVClientSessionData.js | 56 ++- zefie_wtvp_minisrv/WTVFlashrom.js | 8 +- zefie_wtvp_minisrv/WTVLzpf.js | 9 +- zefie_wtvp_minisrv/app.js | 400 +++++++++++++----- zefie_wtvp_minisrv/config.json | 13 +- zefie_wtvp_minisrv/package.json | 2 +- zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj | 20 +- 53 files changed, 863 insertions(+), 445 deletions(-) create mode 100644 zefie_wtvp_minisrv/ServiceVault/http_pc/get.js create mode 100644 zefie_wtvp_minisrv/ServiceVault/http_pc/index.js rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/allyouneed.html (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/allyouneed.swf (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/attractloop.swf (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/communicate.html (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/communicate.swf (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/images/buttonsplus_all.gif (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/images/buttonsplus_comm.gif (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/images/buttonsplus_interactive.gif (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/images/buttonsplus_internet.gif (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/images/buttonsplus_try.gif (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/images/spacer.gif (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/index.html (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/interactive.html (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/interactive.swf (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/internet.html (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/internet.swf (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/mainmenu.html (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/mainmenu.swf (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/trymsntv.html (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/DealerDemo/trymsntv.swf (100%) rename zefie_wtvp_minisrv/ServiceVault/{wtv-update => wtv-disk}/content/diskmaps/DealerDemo.json (100%) create mode 100644 zefie_wtvp_minisrv/ServiceVault/wtv-disk/sync.js create mode 100644 zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/content/content-serve.js create mode 100644 zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js delete mode 100644 zefie_wtvp_minisrv/ServiceVault/wtv-update/DealerDemo.js delete mode 100644 zefie_wtvp_minisrv/ServiceVault/wtv-update/sync.js delete mode 100644 zefie_wtvp_minisrv/ServiceVault/wtv-update/updatesuccess.txt diff --git a/README.md b/README.md index 9d146267..ea305a88 100644 --- a/README.md +++ b/README.md @@ -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)*** diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml index c6ef8b6b..ee9b08bd 100644 --- a/docker-compose/docker-compose.yml +++ b/docker-compose/docker-compose.yml @@ -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 diff --git a/docker-compose/minisrv/Dockerfile b/docker-compose/minisrv/Dockerfile index 447186f9..547cefc5 100644 --- a/docker-compose/minisrv/Dockerfile +++ b/docker-compose/minisrv/Dockerfile @@ -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 + diff --git a/user_config_README.md b/user_config_README.md index 392e5398..8b8c0cfe 100644 --- a/user_config_README.md +++ b/user_config_README.md @@ -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] ``` diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/get.js b/zefie_wtvp_minisrv/ServiceVault/http_pc/get.js new file mode 100644 index 00000000..658b975a --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/http_pc/get.js @@ -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]; +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/index.js b/zefie_wtvp_minisrv/ServiceVault/http_pc/index.js new file mode 100644 index 00000000..802a1f4b --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/http_pc/index.js @@ -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 = ` + + +zefie minisrv ${minisrv_config.version} + + + +
+ +
+ +


+


+


+ +
+Mini service +
+zefie minisrv v${minisrv_config.version}`; +if (minisrv_config.config.git_commit) data += " (git " + minisrv_config.config.git_commit + ")"; +data += ` +
+

+ +`; \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js index 49ae3d46..fd2bfc70 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js @@ -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"; } diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/allyouneed.html b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/allyouneed.html similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/allyouneed.html rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/allyouneed.html diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/allyouneed.swf b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/allyouneed.swf similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/allyouneed.swf rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/allyouneed.swf diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/attractloop.swf b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/attractloop.swf similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/attractloop.swf rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/attractloop.swf diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/communicate.html b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/communicate.html similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/communicate.html rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/communicate.html diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/communicate.swf b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/communicate.swf similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/communicate.swf rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/communicate.swf diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/buttonsplus_all.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/buttonsplus_all.gif similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/buttonsplus_all.gif rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/buttonsplus_all.gif diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/buttonsplus_comm.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/buttonsplus_comm.gif similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/buttonsplus_comm.gif rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/buttonsplus_comm.gif diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/buttonsplus_interactive.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/buttonsplus_interactive.gif similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/buttonsplus_interactive.gif rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/buttonsplus_interactive.gif diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/buttonsplus_internet.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/buttonsplus_internet.gif similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/buttonsplus_internet.gif rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/buttonsplus_internet.gif diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/buttonsplus_try.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/buttonsplus_try.gif similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/buttonsplus_try.gif rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/buttonsplus_try.gif diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/spacer.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/spacer.gif similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/images/spacer.gif rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/images/spacer.gif diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/index.html b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/index.html similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/index.html rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/index.html diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/interactive.html b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/interactive.html similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/interactive.html rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/interactive.html diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/interactive.swf b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/interactive.swf similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/interactive.swf rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/interactive.swf diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/internet.html b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/internet.html similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/internet.html rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/internet.html diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/internet.swf b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/internet.swf similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/internet.swf rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/internet.swf diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/mainmenu.html b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/mainmenu.html similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/mainmenu.html rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/mainmenu.html diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/mainmenu.swf b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/mainmenu.swf similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/mainmenu.swf rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/mainmenu.swf diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/trymsntv.html b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/trymsntv.html similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/trymsntv.html rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/trymsntv.html diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/trymsntv.swf b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/trymsntv.swf similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/DealerDemo/trymsntv.swf rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/DealerDemo/trymsntv.swf diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/content/diskmaps/DealerDemo.json b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/diskmaps/DealerDemo.json similarity index 100% rename from zefie_wtvp_minisrv/ServiceVault/wtv-update/content/diskmaps/DealerDemo.json rename to zefie_wtvp_minisrv/ServiceVault/wtv-disk/content/diskmaps/DealerDemo.json diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-disk/sync.js b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/sync.js new file mode 100644 index 00000000..8f8429b6 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-disk/sync.js @@ -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 = ` + + + + + Retrieving files... + + + + + + + +
+ + + + + + +
+ ${message} +
+
+
+
+ + + +
+ + + ${main_message} +

This may take a while. + +

+ +

+ + + +
+ + +`; + +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/content/content-serve.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/content/content-serve.js new file mode 100644 index 00000000..b8209c2a --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/content/content-serve.js @@ -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); +}); diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js index 33f19f0e..a2ad57e0 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-by-path.js @@ -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) diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js index 25a2368b..a7f93034 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/get-lc2-page.js @@ -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"> - + - +
Updating now
@@ -56,7 +55,7 @@ Updating now
- + @@ -92,7 +91,7 @@ data += `





-
+
${flashrom_info.message}

- + @@ -119,7 +118,7 @@ ${flashrom_info.message} - + diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js index b22756f3..3a00509a 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/initiate-lc2-download.js @@ -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 { diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-complete.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-complete.js index 61ee429e..b072fe81 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-complete.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-complete.js @@ -25,12 +25,12 @@ hspace=0 vspace=0 fontsize="large"> - + - +
Updating complete
@@ -38,7 +38,7 @@ Updating complete
- + @@ -65,7 +65,7 @@ The update is complete.
- + @@ -74,7 +74,7 @@ The update is complete.
- + diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.js index 3cb3fa17..3f6e1b91 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/lc2-download-failed.js @@ -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 = ` - + - +
Updating failed
@@ -66,7 +66,7 @@ data = `
- + @@ -96,7 +96,7 @@ data = ` - + @@ -105,7 +105,7 @@ data = ` - + diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js index 2600705c..765de4e3 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-flashrom/willie.js @@ -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); }); diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js index 415f3b64..fde0566b 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js @@ -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?"; diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js index ae847962..9f44b498 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js @@ -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 = ''; } \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js new file mode 100644 index 00000000..52cb2023 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js @@ -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 = ''; \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js b/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js index 214d201b..56e1609a 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js @@ -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 = ` @@ -24,13 +34,16 @@ function go() { location.href=document.access.url.value; } -Welcome to `+ z_title + `
-`; -if (minisrv_config.config.git_commit) data += "" + "  ".repeat(32) + "git revision " + minisrv_config.config.git_commit + "
"; +Welcome to ${z_title}`; +if (ssid_sessions[socket.ssid].getSessionData("registered")) data += ", " + ssid_sessions[socket.ssid].getSessionData("subscriber_username") + "!"; +data += "
"; +if (minisrv_config.config.git_commit) data += `
git revision ${minisrv_config.config.git_commit}

`; + data += ` -Encryption Status: ${cryptstatus}
+
+Status: ${cryptstatus} (${compstatus})
Connection Speed: &rate; -

+


  • client:relog (direct)
  • @@ -45,7 +58,7 @@ if (ssid_sessions[socket.ssid].hasCap("client-has-disk")) { data += "
  • DiskHax ~ VFatHax
  • \n"; if (ssid_sessions[socket.ssid].hasCap("client-can-do-macromedia-flash2")) { // only show demo if client can do flash2 - data += "
  • Old MSNTV DealerDemo: Download ~ Access (after Download)
  • \n"; + data += "
  • Old MSNTV DealerDemo: Download ~ Access (after Download)
  • \n"; } } diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-register/ServeLegal.js b/zefie_wtvp_minisrv/ServiceVault/wtv-register/ServeLegal.js index c14144b4..44a7168f 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-register/ServeLegal.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-register/ServeLegal.js @@ -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. diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-register/register.js b/zefie_wtvp_minisrv/ServiceVault/wtv-register/register.js index aecdd722..12092688 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-register/register.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-register/register.js @@ -40,7 +40,7 @@ Welcome ENCTYPE="x-www-form-encoded" METHOD="POST"> -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.

    Press the "Continue" button below to begin setup.

    diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/tricks.js b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/tricks.js index f994ee0f..acc79f73 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/tricks.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-tricks/tricks.js @@ -20,13 +20,13 @@ data = ` Info -List Cookies +List Cookies Visit Ultra Willie's! -Clear Cookies +Clear Cookies diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/DealerDemo.js b/zefie_wtvp_minisrv/ServiceVault/wtv-update/DealerDemo.js deleted file mode 100644 index ecf03f93..00000000 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-update/DealerDemo.js +++ /dev/null @@ -1,51 +0,0 @@ -headers = `200 OK -Content-Type: text/html` - -data = ` - - - - Retrieving Files - - - - - - - -
    - - - - - - -
    - Retrieving Files -
    -
    -
    -
    - - - -
    - - - Your Internet terminal is retrieving some files. -

    This may take a while. - -

    - -

    - - - -
    - -` \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/sync.js b/zefie_wtvp_minisrv/ServiceVault/wtv-update/sync.js deleted file mode 100644 index 032a8dc5..00000000 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-update/sync.js +++ /dev/null @@ -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"); -} - diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-update/updatesuccess.txt b/zefie_wtvp_minisrv/ServiceVault/wtv-update/updatesuccess.txt deleted file mode 100644 index 9655cb3d..00000000 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-update/updatesuccess.txt +++ /dev/null @@ -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 \ No newline at end of file diff --git a/zefie_wtvp_minisrv/WTVClientSessionData.js b/zefie_wtvp_minisrv/WTVClientSessionData.js index bf1099dd..d44c948d 100644 --- a/zefie_wtvp_minisrv/WTVClientSessionData.js +++ b/zefie_wtvp_minisrv/WTVClientSessionData.js @@ -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; } } diff --git a/zefie_wtvp_minisrv/WTVFlashrom.js b/zefie_wtvp_minisrv/WTVFlashrom.js index 478e5629..986c4666 100644 --- a/zefie_wtvp_minisrv/WTVFlashrom.js +++ b/zefie_wtvp_minisrv/WTVFlashrom.js @@ -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)); } } } diff --git a/zefie_wtvp_minisrv/WTVLzpf.js b/zefie_wtvp_minisrv/WTVLzpf.js index 27b09cf8..5bfea2ea 100644 --- a/zefie_wtvp_minisrv/WTVLzpf.js +++ b/zefie_wtvp_minisrv/WTVLzpf.js @@ -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); @@ -482,4 +481,4 @@ class WTVLzpf { } } -module.exports = WTVLzpf; \ No newline at end of file +module.exports = WTVLzpf; diff --git a/zefie_wtvp_minisrv/app.js b/zefie_wtvp_minisrv/app.js index 95752d97..ac1624bb 100644 --- a/zefie_wtvp_minisrv/app.js +++ b/zefie_wtvp_minisrv/app.js @@ -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) { @@ -172,17 +206,35 @@ async function processPath(socket, service_vault_file_path, request_headers = ne try { service_vaults.forEach(function (service_vault_dir) { if (service_vault_found) return; - service_vault_file_path = makeSafePath(service_vault_dir,service_path); + service_vault_file_path = 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; - headers_obj["wtv-lzpf"] = 0; + case 2: + // zlib gzip implementation + headers_obj['Content-Encoding'] = 'gzip'; + data = zlib.gzipSync(data, { + 'level': 9 + }); + break; + } - var wtvcomp = new WTVLzpf(); - data = wtvcomp.Compress(data); - - wtvcomp = null; // Makes the garbage gods happy so it cleans up our mess + 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,14 +1002,17 @@ 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 (!ssid_sessions[socket.ssid]) { - ssid_sessions[socket.ssid] = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs); + 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(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); } - 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) { @@ -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,14 +1428,16 @@ 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) { - 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"); - delete ssid_sessions[ssid]; - } - }, timeout, socket.ssid); - } + // 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"); + delete ssid_sessions[ssid]; + } + }, timeout, socket.ssid); } } socket.end(); @@ -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) { diff --git a/zefie_wtvp_minisrv/config.json b/zefie_wtvp_minisrv/config.json index 91767a6f..80bd772d 100644 --- a/zefie_wtvp_minisrv/config.json +++ b/zefie_wtvp_minisrv/config.json @@ -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 }, diff --git a/zefie_wtvp_minisrv/package.json b/zefie_wtvp_minisrv/package.json index 6ae035e2..f16d9473 100644 --- a/zefie_wtvp_minisrv/package.json +++ b/zefie_wtvp_minisrv/package.json @@ -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", diff --git a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj index 1e623a83..17205247 100644 --- a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj +++ b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj @@ -32,6 +32,8 @@ + + @@ -50,6 +52,7 @@ Code + Code @@ -71,6 +74,9 @@ + + Code + @@ -247,15 +253,13 @@ Code - + Code - + Code - - @@ -287,10 +291,12 @@ + + @@ -300,13 +306,13 @@ - + - - + + \ No newline at end of file