- convert post_data to query if valid query data
 - wtv-register system
 - Store Session data as JSON flat file
 - wtv-cookie support
 - spent way too much time on a page no one will read
 - move filterSSID to WTVClientSessionData
 - disable compression until fixed
 - do not delete WTVSec on last socket, instead recreate on prereg
 - set 'wtv-bypass-proxy' to false
 - rework header whitelist system for HTTP(s) proxy
 - clean up SSID session data only if client is not seen for 3 minutes
 - add shouldWeCompress() function
 - add additional headers to wtv-setup:/get
 - add initial blank wtv-music:/get-playlist
 - update: WTVClientCapabilities: add unknown bits instead of logging error
 - update: fix flashrom system
 - update: webone example config
 - update: app.js: more 'binary block' exclusions
 - update: fix tellyscript folder name for case-sensitive filesystems
 - add Lzpf compression
This commit is contained in:
zefie
2021-08-06 00:05:58 -04:00
parent b4a04d49cd
commit 622afce5c7
45 changed files with 2424 additions and 206 deletions

6
.gitignore vendored
View File

@@ -361,9 +361,9 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
/hacktv_updsrv/ServiceLogPost/1626307222_warning_812bf30600b002bb
/hacktv_updsrv/ServiceVault/wtv-music/midi
/zefie_wtvp_minisrv/ServiceVault/wtv-home/6969.html
/zefie_wtvp_minisrv/user_config.json
/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.zefie.html
/zefie_wtvp_minisrv/UserServiceVault/wtv-update
/zefie_wtvp_minisrv/UserServiceVault/*-*/
/zefie_wtvp_minisrv/ServiceLogPost/*.log
/zefie_wtvp_minisrv/SessionStore/*.json

View File

@@ -162,6 +162,20 @@ AddRedirect=http://web.archive.org/web/1997/%URL%
[Edit:^(http://www\.|http://)microsoft.com/IE/]
AddRedirect=http://web.archive.org/web/1997/%URL%
; WebTV
[Edit:^http://developer.webtv.net/]
AddRedirect=http://web.archive.org/web/20010118212000/%URL%
[Edit:^http://www.crosswinds.net/~lsyndicate/cara/]
AddRedirect=http://web.archive.org/web/20000815230842/%URL%
[Edit:^http://www.webtvaudio.com/]
AddRedirect=https://web.archive.org/web/20010720053557/%URL%
[Edit:^http://soweird.mine.nu/]
AddRedirect=https://web.archive.org/web/20010720053557/%URL%
[Edit:\.cdf$]
IgnoreUrl=web.archive.org
AddRedirect=http://web.archive.org/web/1998/%URL%
@@ -259,6 +273,7 @@ OnHeader=User-Agent: Mozilla/0
OnHeader=User-Agent: Mozilla/1
OnHeader=User-Agent: Mozilla/2
OnHeader=User-Agent: Mozilla/3
OnHeader=User-Agent: WebTV
IgnoreUrl=webdav
AddConvert=convert
AddConvertDest=gif
@@ -267,13 +282,14 @@ AddResponseHeader=Content-Type: image/gif
; uncomment section below to enable JPG recompression
[Edit]
OnContentType=image/jpeg
OnContentType=image/jpg
;OnContentType=image/png
;OnContentType=image/webp
OnCode=200
IgnoreUrl=webdav
AddConvert=convert
AddConvertDest=jpg
AddConvertArg1=-quality 50
AddConvertArg1=-quality 35 -resize 640x480>
AddResponseHeader=Content-Type: image/jpeg

View File

@@ -6,10 +6,13 @@
### `config` section
Some values are available that are not defined in `config.json` by default. I will attempt to cover them here.
```
"service_name": "CoolTV",
"service_owner": "CoolDude",
"service_logo": "WebTVLogoJewel.gif",
"service_splash_logo": "file://ROM/images/SplashLogo1.gif"
```
You can set the image to be loaded in the top left in place of the WebTV or MSN logo, as well as the main Splash image shown on login.
You can set the service name and service owner, which will be used across the service when referencing itself.
You can set the image to be loaded in the top left in place of the WebTV or HackTV logo, as well as the main Splash image shown on login.
If an absolute path (`wtv-url:/`, `file://` url, or `http(s)://` url) is not passed, the server will search for the specified filename in `wtv-star/images` of any Service Vault. You'll want to keep the filesizes low.
```
"post_debug": true

View File

@@ -1,8 +1,13 @@
var gourl = "wtv-head-waiter:/login?";
if (request_headers.query.relogin) gourl += "relogin=true";
if (request_headers.query.reconnect) gourl += "reconnect=true";
if (socket.ssid) {
if (ssid_sessions[socket.ssid].loadSessionData() == true) {
console.log(" * Loaded session data from disk for", filterSSID(socket.ssid))
ssid_sessions[socket.ssid].setSessionData("registered", (ssid_sessions[socket.ssid].getSessionData("registered") == true) ? true : false);
} else {
ssid_sessions[socket.ssid].session_data = {};
ssid_sessions[socket.ssid].setSessionData("registered", false);
}
if (ssid_sessions[socket.ssid].data_store) {
if (ssid_sessions[socket.ssid].data_store.sockets) {
var i = 0;
@@ -19,19 +24,23 @@ if (socket.ssid) {
}
}
if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
if (zdebug) console.log(" # Recreating primary WTVSec login instance for", filterSSID(socket.ssid));
delete ssid_sessions[socket.ssid].data_store.wtvsec_login;
}
ssid_sessions[socket.ssid].data_store.wtvsec_login = new WTVSec();
ssid_sessions[socket.ssid].data_store.wtvsec_login.IssueChallenge();
ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(request_headers["wtv-incarnation"]);
ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(request_headers["wtv-incarnation"] || 1);
} else {
console.log(" * Something bad happened (we don't know the client ssid???)");
var errpage = doErrorCode(400)
var errpage = doErrorPage(400)
headers = errpage[0];
data = errpage[1];
}
if (request_headers.query.relogin && ssid_sessions[socket.ssid].getSessionData("registered")) gourl += "relogin=true";
if (request_headers.query.reconnect && ssid_sessions[socket.ssid].getSessionData("registered")) gourl += "reconnect=true";
if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
var prereg_contype = "text/html";
@@ -110,7 +119,6 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
gourl = null;
}
if (!file_path != null && !zquiet) console.log(" * Sending TellyScript", file_path, "on socket", socket.id);
headers = "200 OK\n"
@@ -126,7 +134,7 @@ if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
if (bf0app_update) headers += getServiceString('wtv-star', { "no_star_word": true }) + "\n";
else headers += getServiceString('wtv-star') + "\n";
if (request_headers.query.reconnect && !ssid_sessions[socket.ssid].session_data.registered) headers += getServiceString('wtv-register') + "\n";
headers += getServiceString('wtv-flashrom') + "\n";
if (bf0app_update) headers += "wtv-boot-url: " + gourl + "\n";
else headers += "wtv-boot-url: wtv-1800:/preregister?relogin=true\n";

View File

@@ -1,10 +1,10 @@
var irc_nick = "";
headers = "200 OK";
if (request_headers.query.nick) headers += "\n" + ssid_sessions[socket.ssid].setIRCNick(request_headers.query.nick);
else if (!ssid_sessions[socket.ssid].get("wtv-irc-nick")) ssid_sessions[socket.ssid].setIRCNick(minisrv_config.config.service_name + '_' + Math.floor(Math.random() * 100000)).substring(0, 16);
else if (!ssid_sessions[socket.ssid].getSessionData("subscriber_irc_nick")) ssid_sessions[socket.ssid].getSessionData("subscriber_username") || ssid_sessions[socket.ssid].setIRCNick(minisrv_config.config.service_name + '_' + Math.floor(Math.random() * 100000)).substring(0, 16);
headers += "\nContent-Type: text/html";
var irc_nick = ssid_sessions[socket.ssid].get("wtv-irc-nick");
var irc_nick = ssid_sessions[socket.ssid].getSessionData("subscriber_irc_nick") || ssid_sessions[socket.ssid].getSessionData("subscriber_username");
data = `<html>
<head>

View File

@@ -0,0 +1,15 @@
if (socket.ssid) {
if (request_headers.post_data) {
if (ssid_sessions[socket.ssid]) {
ssid_sessions[socket.ssid].addCookie(cookie_data);
headers = "200 OK\n";
headers += "Content-Type: text/html";
}
}
}
if (!headers) {
var errpage = doErrorPage(400)
headers = errpage[0];
data = errpage[1];
}

View File

@@ -0,0 +1,18 @@
if (request_headers.post_data) {
if (request_headers.query.domain && request_headers.query.path) {
if (socket.ssid) {
if (ssid_sessions[socket.ssid]) {
data = ssid_sessions[socket.ssid].getCookieString(unescape(request_headers.query.domain), unescape(request_headers.query.path));
headers = "200 OK\n";
headers += "Content-Type: text/plain";
}
}
}
}
if (!headers) {
var errpage = doErrorPage(400)
headers = errpage[0];
data = errpage[1];
}

View File

@@ -1,6 +1,14 @@
if (socket.ssid) {
if (ssid_sessions[socket.ssid]) {
headers =`200 OK
Connection: Keep-Alive
Content-type: text/plain`
data = ssid_sessions[socket.ssid].listCookies();
headers = "200 OK\n";
headers += "Content-Type: text/plain";
}
}
data=`.passporttest.com/ppsecure.passporttest.com/`
if (!headers) {
var errpage = doErrorPage(400)
headers = errpage[0];
data = errpage[1];
}

View File

@@ -3,8 +3,10 @@ request_is_async = true;
var bf0app_update = false;
var request_path = unescape(request_headers.query.path);
var romtype = ssid_sessions[socket.ssid].get("wtv-client-rom-type");
var bootver = ssid_sessions[socket.ssid].get("wtv-client-bootrom-version")
if (ssid_sessions[socket.ssid].get("wtv-client-rom-type") == "bf0app" && ssid_sessions[socket.ssid].get("wtv-client-bootrom-version") == "105") {
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;

View File

@@ -1,7 +1,6 @@
const WTVFlashrom = require("./WTVFlashrom.js");
var wtvflashrom;
var flashrom_info;
request_is_async = true;
if (!request_headers.query.path) {
@@ -12,19 +11,18 @@ if (!request_headers.query.path) {
var wtvflashrom = new WTVFlashrom(service_vaults, service_name, minisrv_config.services[service_name].use_zefie_server);
var request_path = unescape(request_headers.query.path);
// read 512 bytes of rom
flashrom_info = wtvflashrom.getFlashRom(request_path, function (data, headers = null) {
// read flashrom header info into array using WTVFlashrom class
wtvflashrom.getFlashromMeta(request_path, function (data) {
processLC2DownloadPage(request_headers.query.path, data, (request_headers.query.numparts || null));
}, 512);
});
}
async function processLC2DownloadPage(path, flashrom_info, numparts = null) {
var flashrom_numparts = null;
if (numparts != null) flashrom_numparts = parseInt(numparts);
if (!flashrom_numparts) flashrom_numparts = parseInt(flashrom_info.message.substring(flashrom_info.message.length - 4).replace(/\D/g, ''));
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=" + parseInt(flashrom_numparts));
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) {
@@ -99,8 +97,8 @@ blockurl="${flashrom_info.rompath}"
lastblock="${flashrom_info.is_last_part}"
curblock="` + (flashrom_info.part_number + 1) + `"
`
if (flashrom_numparts) {
data += `totalblocks="${flashrom_numparts}"`;
if (flashrom_info.part_count) {
data += `totalblocks="${flashrom_info.part_count}"`;
}
data += `>
<font size="-1" color="#D6DFD0">

View File

@@ -24,6 +24,8 @@ if (socket.ssid !== null) {
if (challenge_response.toString(CryptoJS.enc.Base64) == client_challenge_response) {
console.log(" * wtv-challenge-response success for " + filterSSID(socket.ssid));
wtvsec_login.PrepareTicket();
if (!ssid_sessions[socket.ssid].getSessionData("registered")) gourl = "wtv-register:/splash";
} else {
console.log(" * wtv-challenge-response FAILED for " + filterSSID(socket.ssid));
if (zdebug) console.log("Response Expected:", challenge_response.toString(CryptoJS.enc.Base64));
@@ -39,66 +41,97 @@ if (socket.ssid !== null) {
if (gourl) {
headers = `200 OK
Connection: Keep-Alive
Connection: Close
wtv-open-isp-disabled: false
wtv-visit: ${gourl}
`;
if (!ssid_sessions[socket.ssid].session_data.registered && !request_headers.query.guest_mode) {
headers += `wtv-encrypted: true
wtv-ticket: ${wtvsec_login.ticket_b64}
${getServiceString('wtv-register')}
${getServiceString('wtv-head-waiter')}
${getServiceString('wtv-star')}
wtv-boot-url: wtv-register:/splash
`
}
headers += `wtv-visit: ${gourl}
Content-type: text/html`;
data = '';
}
else {
if (request_headers.query.guest_mode) {
var namerand = Math.floor(Math.random() * 100000);
var nickname = (minisrv_config.config.service_name + '_' + namerand)
var human_name = nickname;
var userid = '1' + Math.floor(Math.random() * 1000000000000000000);
var messenger_enabled = 0;
var messenger_authorized = 0;
var home_url = "wtv-home:/home?";
} else if (!ssid_sessions[socket.ssid].getSessionData("registered")) {
var errpage = doErrorPage(400);
headers = errpage[0];
data = errpage[1];
} else {
var userid = ssid_sessions[socket.ssid].getSessionData("subscriber_userid")
var nickname = ssid_sessions[socket.ssid].getSessionData("subscriber_username");
var human_name = ssid_sessions[socket.ssid].getSessionData("subscriber_name");
var messenger_enabled = ssid_sessions[socket.ssid].getSessionData("messenger_enabled") || 0;
var messenger_authorized = ssid_sessions[socket.ssid].getSessionData("messenger_authorized") || 0;
var home_url = "wtv-home:/splash?";
}
var offline_user_list = CryptoJS.enc.Latin1.parse("<user-list>\n\t<user userid=\"" + userid + " user-name=\"" + nickname + "\" first-name=\"" + minisrv_config.config.service_name + "User \" last-name=\\" + namerand + "\" password=\"\" mail-enabled=\"true\" />\n</user-list>").toString(CryptoJS.enc.Base64);
data = '';
headers = `200 OK
Connection: Keep-Alive
wtv-encrypted: true
wtv-client-time-zone: GMT -0000
wtv-client-time-dst-rule: GMT
wtv-client-date: `+ strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString())) + ` GMT
wtv-country: US
wtv-language-header: en-US,en
wtv-visit: client:closeallpanels
wtv-expire-all: client:closeallpanels
wtv-transition-override: off
wtv-force-lightweight-targets: webtv.net:/
wtv-smartcard-inserted-message: Contacting service
wtv-bypass-proxy: false
wtv-offline-user-list: ${offline_user_list}
wtv-bypass-proxy: true
wtv-messenger-authorized: ${messenger_authorized}
wtv-messenger-enable: ${messenger_enabled}
wtv-noback-all: wtv-
wtv-service: reset
`+ getServiceString('all', { "exceptions": ["wtv-register"] } ) + `
user-id: ${userid}
wtv-human-name: ${human_name}
${ssid_sessions[socket.ssid].setIRCNick(nickname)}
wtv-domain: wtv.zefie.com
wtv-input-timeout: 14400
wtv-ticket: ${wtvsec_login.ticket_b64}
wtv-messagewatch-checktimeoffset: off
wtv-input-timeout: 14400
wtv-connection-timeout: 90
wtv-fader-timeout: 900
wtv-ssl-log-url: wtv-log:/log
wtv-smartcard-inserted-message: Contacting service
user-id: ${userid}
wtv-transition-override: off
wtv-allow-dsc: true
wtv-messenger-enable: 0
wtv-noback-all: wtv-
wtv-service: reset
`+ getServiceString('all') + `
wtv-boot-url: wtv-1800:/preregister?relogin=true
wtv-human-name: ${nickname}
${ssid_sessions[socket.ssid].setIRCNick(nickname)}
wtv-home-url: wtv-home:/home?
wtv-domain: wtv.zefie.com
wtv-inactive-timeout: 0
wtv-connection-timeout: 90
wtv-show-time-enabled: true
wtv-fader-timeout: 900
wtv-tourist-enabled: true
wtv-connection-timeout: 180
wtv-boot-url: wtv-1800:/preregister?relogin=true
wtv-allow-dsc: true
wtv-home-url: wtv-home:/home?
`
if (ssid_sessions[socket.ssid].get('wtv-need-upgrade') != 'true' && !request_headers.query.reconnect) {
headers += "\nwtv-settings-url: wtv-setup:/get";
}
headers += `
wtv-log-url: wtv-log:/log
wtv-ssl-log-url: wtv-log:/log
wtv-ssl-timeout: 240
wtv-login-timeout: 7200
wtv-open-isp-disabled: false
wtv-log-url: wtv-log:/log
wtv-offline-mail-enable: false
wtv-demo-mode: 0
wtv-wink-deferrer-retries: 3
wtv-offline-mail-enable: false
wtv-name-server: 8.8.8.8
`;
if (ssid_sessions[socket.ssid].get('wtv-need-upgrade') != 'true' && !request_headers.query.reconnect) {
headers += "wtv-settings-url: wtv-setup:/get\n";
}
headers += `wtv-visit: wtv-home:/splash?
wtv-visit: ${home_url}
Content-Type: text/html`;
}

View File

@@ -1,72 +1,59 @@
var challenge_response, challenge_header = '';
var challenge_response, challenge_header = "";
var gourl = "wtv-head-waiter:/login-stage-two?";
if (request_headers.query.relogin) gourl += "relogin=true";
if (request_headers.query.reconnect) gourl += "reconnect=true";
var send_to_relogin = true;
if (socket.ssid !== null) {
var wtvsec_login = ssid_sessions[socket.ssid].get("wtvsec_login");
if (socket.ssid) {
if (ssid_sessions[socket.ssid]) {
if (request_headers["wtv-ticket"]) {
if (wtvsec_login.ticket_b64 == null) {
if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 == null) {
if (request_headers["wtv-ticket"].length > 8) {
wtvsec_login.DecodeTicket(request_headers["wtv-ticket"]);
wtvsec_login.ticket_b64 = request_headers["wtv-ticket"];
ssid_sessions[socket.ssid].data_store.wtvsec_login.DecodeTicket(request_headers["wtv-ticket"]);
ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 = request_headers["wtv-ticket"];
send_to_relogin = false;
}
}
} else {
if (wtvsec_login) {
challenge_response = wtvsec_login.challenge_response;
if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
var client_challenge_response = request_headers["wtv-challenge-response"] || null;
if (challenge_response && client_challenge_response) {
if (challenge_response.toString(CryptoJS.enc.Base64).substring(0, 85) == client_challenge_response.substring(0, 85)) {
console.log(" * wtv-challenge-response success for " + socket.ssid);
wtvsec_login.PrepareTicket();
ssid_sessions[socket.ssid].data_store.wtvsec_login.PrepareTicket();
send_to_relogin = false;
} else {
challenge_header = "wtv-challenge: " + wtvsec_login.IssueChallenge();
challenge_header = "wtv-challenge: " + ssid_sessions[socket.ssid].data_store.wtvsec_login.IssueChallenge();
send_to_relogin = false;
}
} else {
challenge_header = "wtv-challenge: " + wtvsec_login.IssueChallenge();
challenge_header = "wtv-challenge: " + ssid_sessions[socket.ssid].data_store.wtvsec_login.IssueChallenge();
send_to_relogin = false;
}
}
} else {
wtvsec_login = new WTVSec();
}
}
}
/*
if (request_headers) {
var cookiedata = {};
Object.keys(request_headers).forEach(function (k) {
switch (k) {
case "wtv-capability-flags":
case "wtv-system-version":
case "wtv-client-rom-type":
case "wtv-client-bootrom-version":
case "wtv-system-chipversion":
case "wtv-system-sysconfig":
case "wtv-system-cpuspeed":
cookiedata[k] = request_headers[k];
break;
}
});
}
*/
if (!send_to_relogin) {
if (challenge_header != '') {
headers = `200 OK
Connection: Keep-Alive
Expires: Wed, 09 Oct 1991 22:00:00 GMT
wtv-expire-all: wtv-head-waiter:
`+ getServiceString('wtv-log') + `
wtv-log-url: wtv-log:/log
${challenge_header}
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-visit: ${gourl}
Content-type: text/html`;
data = '';
} else {
headers = `200 OK
Connection: Keep-Alive
Expires: Wed, 09 Oct 1991 22:00:00 GMT
@@ -74,5 +61,5 @@ wtv-expire-all: wtv-head-waiter:
wtv-expire-all: wtv-1800:
wtv-visit: wtv-1800:/preregister?relogin=true
Content-type: text/html`;
data = '';
}

View File

@@ -15,7 +15,7 @@ if (ssid_sessions[socket.ssid].get('box-does-psuedo-encryption')) {
data = `<html>
<head>
<title>Home for minisrv</title>
<title>Home for ${ssid_sessions[socket.ssid].getSessionData("subscriber_username") || "minisrv"}</title>
<DISPLAY NoLogo hideoptions noscroll>
</head>
<body bgcolor="black" link="gold" vlink="gold" alink="gold" text="gold">
@@ -24,14 +24,14 @@ function go() {
location.href=document.access.url.value;
}
</script>
<h3>Welcome to `+ z_title + `</h3>
<h4>Welcome to `+ z_title + `</h4>
<b>Encryption Status</b>: ${cryptstatus}<br>
<b>Connection Speed</b>: &rate;
<p>
<form name=access onsubmit="go()">
<ul>
<li><a href="client:relog">client:relog (direct)</a> ~ <a href="wtv-tricks:/blastcache?return_to=wtv-home:/home">Clear Cache</a></li>
<li><a href="wtv-flashrom:/willie" selected>Ultra Willies</a> ~ <a href="wtv-tricks:/info">Tricks Info</a></li>
<li><a href="client:relog">client:relog (direct)</a></li>
<li><a href="wtv-flashrom:/willie" selected>Ultra Willies</a> ~ <a href="wtv-tricks:/tricks">Tricks</a></li>
<li><a href="wtv-music:/demo/index">MIDI Music Demo</a></li>
`;
if (ssid_sessions[socket.ssid].hasCap("client-can-do-chat")) {

View File

@@ -8,7 +8,7 @@ data = `<html>
<head>
<display hideoptions nostatus showwhencomplete skipback clearback fontsize=medium>
<title>Engaging zefie...</title>
<meta http-equiv=Refresh content="5; url=wtv-home:/home?">
<meta http-equiv=Refresh content="4; url=wtv-home:/home?">
</head>
<body bgcolor="#000000" text="#449944">
<bgsound src="file://ROM/Sounds/Splash.mid">

View File

@@ -0,0 +1,34 @@
headers = `200 OK
Content-Type: text/html`;
// unfunctional example for documentation purposes
/*
headers += `
wtv-backgroundmusic-clear: no_zits
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/moods/mystical.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/moods/quietude.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/mellow/sunlane.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/ambient/byzantium.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/ambient/overmind.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/ambient/precipice.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/classical/moonlight_sonata.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/classical/mendelssohn-prelude.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/classical/mouret-rondeau.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/classical/la-barriera.rmf
wtv-backgroundmusic-add: wtv-music:/music/classicl/bach/bach_cmaj_prelude.mid
wtv-backgroundmusic-add: wtv-music:/music/classicl/bach/bach_fugue_cmajor.mid
wtv-backgroundmusic-add: wtv-music:/music/classicl/bach/bach_menuet_in_G.mid
wtv-backgroundmusic-add: wtv-music:/music/classicl/bach/bach_violin_partita_in_e.mid
wtv-backgroundmusic-add: wtv-music:/music/newmusic/keyboards/cata_wtv.mid
wtv-backgroundmusic-add: wtv-music:/music/newmusic/keyboards/home_wtv.mid
wtv-backgroundmusic-add: wtv-music:/music/newmusic/keyboards/just_wtv.mid
wtv-backgroundmusic-add: wtv-music:/music/newmusic/keyboards/nite_wtv.mid
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/moods/grandeur.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/moods/loungy-sixties.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/upbeat/tropicalist-full.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/upbeat/jetset.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/underground/renegado.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/moods/affectionate.rmf
wtv-backgroundmusic-add: wtv-music:/MusicCache/headspace/RMF/moods/sociable.rmf`;
*/

View File

@@ -0,0 +1,13 @@
headers = `300 Moved
Connection: Close
wtv-noback-all: wtv-register:
wtv-expire-all: wtv-
wtv-ticket: ${ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64}
wtv-service: reset
${getServiceString('wtv-1800')}
${getServiceString('wtv-head-waiter')}
${getServiceString('wtv-star')}
wtv-relogin-url: wtv-1800:/preregister?relogin=true
wtv-reconnect-url: wtv-1800:/preregister?reconnect=true
wtv-boot-url: wtv-1800:/preregister?relogin=true
Location: client:relogin`;

View File

@@ -0,0 +1,79 @@
headers = `200 OK
Content-Type: text/html`
data = `<html>
<head>
<title>
Are you sure you want to decline?
</title>
<display nooptions noscroll >
<FORM ACTION="client:goback" ENCTYPE="x-www-form-encoded" METHOD="POST">
</head>
<body noscroll
bgcolor="#171726" text="#D1D3D3" link=#FFEA9C vlink=#FFEA9C
hspace=0 vspace=0 fontsize="large"
>
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td align=middle bgcolor="#5b6c81" border=0 colspan= 3 width="100" height="80">
<img src="${minisrv_config.config.service_logo}" WIDTH="87" HEIGHT="67">
<td colspan= 6 bgcolor="#5b6c81" border=0 width=100% absheight="80" valign=bottom >
<img src="images/head_registration.gif" >
<tr>
<td bgcolor= "#5b6c81" border=0 rowspan=2 width=21 height= 220></td>
<td bgcolor="#171726" border=0 width=9 height=25 align=left valign=top>
<img src="images/L_corner.gif" width=8 height=8>
<td bgcolor="#171726" border=1 colspan=1 width=70 height=25>
<td colspan=6 bgcolor="#171726" border=1 height=25 align=left valign=bottom gradcolor=#262E3D gradangle=90>
<font color=#d1d3d3 size=+1>
<blackface>
Are you sure you want to decline?
</blackface></font>
<tr> <td border=0 width=40 bgcolor="#171726" rowspan="2" >
<td absheight=20 width=100 bgcolor="#171726" colspan=6>
</tr>
</table>
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td bgcolor= "#5b6c81" border=0 rowspan=6 abswidth=21 height= 220></td>
<td border=0 abswidth=40 bgcolor="#171726" rowspan="6" >
<form >
<td height=230 width= 300 bgcolor="#171726" colspan=5 valign=top align=left>
You have declined the agreements on the previous page.
You won't be able to access the ${minisrv_config.config.service_name} service unless you
accept these agreements. To return to the previous page and
accept these agreements, choose <b>Continue</b>.
<p>
To exit the registration, choose <b>Power Off</b>.
Remember: you won't be able to access the ${minisrv_config.config.service_name} service without
accepting the agreement.
</font>
<td abswidth=20 bgcolor=#171726>
</tr>
<tr>
<td valign= bottom height=15 colspan=7 bgcolor=#171726>
<shadow>
<hr size=5 valign=bottom>
</shadow>
</tr>
<tr>
<td border=2 height=50 colspan=4 bgcolor=#171726 valign=top align=right width=600 >
<font size=-1 color=#e7ce4a>
<input type=submit borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=150
name="Power_Off" width="100"
value="Power Off"
action="client:poweroff" >
&nbsp;&nbsp;</font>
<td bgcolor=#171726 height=50 valign=top align=right width=150>
<font size=-1 color=#e7ce4a>
<shadow>
<input type=submit borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=150
selected
name="Continue"
width="100"
action="client:goback"
value="Continue">
</shadow>
</font> </form> </tr> </table>
</body>
</html>`;

View File

@@ -0,0 +1,446 @@
const WTVReg = require("./WTVRegister.js")
var WTVRegister = new WTVReg(minisrv_config.config.service_owner);
headers = `200 OK
Content-Type: text/html`;
data = `<html>
<head>
<title>
</title>
<display nooptions
>
</head>
<sidebar width=110 bgcolor=#5b6c81 fontsize="large" font color="#171726" absheight=300> <table width=150 height=450 cellspacing=0 cellpadding=2 BGCOLOR="#171726">
<tr>
<td align=middle valign=top bgcolor="#5b6c81" border=0 abswidth="200" height="80"><font color="#171726" >
<img src="${minisrv_config.config.service_logo}">
<p><br> <font size=-1 color="#171726"> <i> To read <br>more of this <br>agreement, press <b>scroll down</b>
<br><br>
<form name="theForm"
action="client:goback">
<input type=hidden name=any-promotions value="">
<input type=hidden name=subscriber-card-type value="">
<input type=hidden name=qString value="">
<input type=hidden name=passport-force-create value="false">
<input type=hidden name=passport-allow-existing-at-registration value="false">
<input type=hidden name=passport-allow-existing-at-add-user value="false">
<input type=hidden name=passport-supported value="false">
</i></font><p>
<font size="-1" color="#E7CE4A">
<shadow>
<img src="wtv-register:/ROMCache/Spacer.gif" width=18 height=1><p>
<input type=submit Value="Go Back"
name="Agree" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=100
selected>
</shadow>
</font>
</form>
</tr>
</table>
</sidebar>
<BODY bgcolor="#171726" hspace=0 vspace=0 fontsize=large text=#d1d3d3 link=#FFEA9C vlink=#FFEA9C>
<form name="theForm" action="client:goback">
<input type=hidden name=any-promotions value="">
<input type=hidden name=subscriber-card-type value="">
<input type=hidden name=qString value="">
<input type=hidden name=passport-force-create value="false">
<input type=hidden name=passport-allow-existing-at-registration value="false">
<input type=hidden name=passport-allow-existing-at-add-user value="false">
<input type=hidden name=passport-supported value="false">
<BODY bgcolor="#171726" hspace=0 vspace=0 fontsize=large text=#d1d3d3>
<TABLE width=450 height=200 ALIGN=left VALIGN=BOTTOM vspace=0 hspace=0 cellspacing=0 cellpadding=0>
<tr>
<td colspan= 8 height="30">
<tr>
<td abswidth=20 bgcolor="#171726">
<td height=202 width= 300 bgcolor="#171726" colspan=6 valign=top align=left>
<P ALIGN="CENTER">TERMS OF SERVICE AND NOTICES</P>
<P ALIGN="CENTER">Version Release Date 8/7/2021</P>
<P align="center"><b>${minisrv_config.config.service_name.toUpperCase()} SERVICE USER AGREEMENT</b></P>
<P>&nbsp;</P>
<P>This ${minisrv_config.config.service_name} Mini service ("${minisrv_config.config.service_name} service") is operated by
${(minisrv_config.config.service_owner != "a minisrv user") ? minisrv_config.config.service_owner : "an anonymous user"}<br><br>
Your registration and use of the ${minisrv_config.config.service_name} service constitutes your acceptance of the terms, conditions, and notices set forth in this Agreement.
${WTVRegister.getServiceOperator().toUpperCase()} RESERVES THE RIGHT TO MODIFY THIS AGREEMENT AT ANY TIME, IN ITS SOLE DISCRETION, BY POSTING CHANGES ONLINE.
YOU ARE RESPONSIBLE FOR REGULARLY REVIEWING THIS AGREEMENT IN ORDER TO OBTAIN TIMELY NOTICE OF SUCH MODIFICATIONS.
THIS INCLUDES ANY AND ALL CHANGES TO SERVICE OPERATION AND EQUIPMENT, AND USER RIGHTS AND RESPONSIBILITIES.
YOUR CONTINUED USE OF THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE FOLLOWING ANY SUCH CHANGE TO THIS AGREEMENT CONSTITUTES YOUR ACCEPTANCE OF THIS
AGREEMENT AS MODIFIED BY THE POSTED CHANGES. IF ANY OF THE CHANGES MADE TO THIS AGREEMENT ARE UNACCEPTABLE TO YOU, YOU MUST IMMEDIATELY TERMINATE YOUR
${minisrv_config.config.service_name.toUpperCase()} SERVICE ACCOUNT ("ACCOUNT"), AS PROVIDED BELOW.
This Agreement takes effect on the date on which you accept this Agreement and continues until your ${minisrv_config.config.service_name}
service membership is terminated either by you or by ${WTVRegister.getServiceOperator(true)}.</P>
<P>
<p><b>Statement of Privacy</b></p>
<p>${WTVRegister.getServiceOperator()} may collect information that identifies your WebTV client device.
Types of data that may be collected, overseen by ${WTVRegister.getServiceOperator(true)}, or logged to disk are:<br><br>
<ul>
<li>- Client SSID</li>
<li>- Chosen Account and IRC Name</li>
<li>- Service URLs accessed, including data submitted during requests</li>
<li>- HTTP and HTTPS URLs accessed, including data submitted during requests</li>
<li>- Any other information you voluntarely submit to the ${minisrv_config.config.service_name} service</li>
</ul>
<table></table>
<p><a name="use"><b>1. <u>Use of the ${minisrv_config.config.service_name} service</u></b></a>
<P><B>2.1 Personal and Non-Commercial Use.</B> The ${minisrv_config.config.service_name} service is offered solely for your personal and non-commercial use.
Any commercial use of the ${minisrv_config.config.service_name} service, or the resale of any of its services or content, is expressly prohibited.
You agree to use all of the ${minisrv_config.config.service_name} service to post, send and receive messages and material that are appropriate.
These services are public so any communications you post or transmit are not private and can be printed and used by others.</P>
<P><B>1.2 Unlawful or Prohibited Use.</B> As a condition of your use of the
${minisrv_config.config.service_name} service, you warrant that you will not use the ${minisrv_config.config.service_name} service for any purpose
that is unlawful or prohibited by this Agreement. You agree to abide by all
applicable local, state, national and international laws and regulations in
your use of the ${minisrv_config.config.service_name} service. You are solely responsible for all acts or
omissions that occur under your Account, including the content of your transmissions through the ${minisrv_config.config.service_name} service. You may not modify,
copy, distribute, transmit, display, perform, reproduce, publish, license,
create derivative works from, transfer, or sell any information, software or
services obtained from or through ${minisrv_config.config.service_name}.</P>
<P><B>1.3 Restrictions on General Use.</B> You agree that when using the ${minisrv_config.config.service_name} service, you will not:
<ul>
<li type=disc> - Use the ${minisrv_config.config.service_name} service or any communication service in connection with surveys, contests, sweepstakes, lotteries, games of chance, pyramid schemes, chain letters, junk email, spamming or any duplicative or unsolicited messages to parties with whom you have no prior relationship (commercial or otherwise).
<li type=disc> - Defame, abuse, harass, stalk, threaten or otherwise violate the legal rights of others, such as, but not limited to, the rights of privacy and publicity.
<li type=disc> - Publish, post, upload, transmit, distribute or disseminate any inappropriate, profane, defamatory, infringing, obscene, indecent or unlawful topic, name, material, file or information.
<li type=disc> - Advertise or offer to sell or buy any goods or services for any non-personal purpose.
<li type=disc> - Download any file or other material posted by another user of a service that you know, or reasonably should know, cannot be legally distributed in such manner.
<li type=disc> - Falsify or delete any author attributions, legal or other proper notices or proprietary designations or labels of the origin or source of software or other material contained in a file that is transmitted or uploaded.
<li type=disc> - Send unsolicited e-mail or instant messages through third-party mail servers to relay your message or hide the origin of your message or any other message to others.
<li type=disc> - Use your e-mail account in the text of unsolicited email messages or Web sites as an address to which others can respond.
<li type=disc> - Mass-post, cross-post, or post off-topic messages to any newsgroup or bulletin board service.
<li type=disc> - Use simultaneous, unattended, or continuous connections to the ${minisrv_config.config.service_name} service with your account.
<li type=disc> - Harvest or otherwise collect information about others, including e-mail addresses, without their consent.
<li type=disc> - Create a false identity for the purpose of misleading others as to the identity of the sender or the origin of a message.
<li type=disc> - Use, download, or otherwise copy, or provide (whether or not for a fee) to a person or entity that is not a ${minisrv_config.config.service_name} service user any directory of ${minisrv_config.config.service_name} service users, or any other user or usage information.
<li type=disc> - Transmit or upload any file that contains software or other material protected by intellectual property laws, rights of privacy or publicity, or any other applicable law unless you own or control the rights thereto, have the legal right to do so, or have received all necessary consents.
<li type=disc> - Transmit or upload any file that contains viruses, Trojan horses, worms, time bombs, cancelbots, corrupted files, malicious scripts, or any other harmful or deleterious software or programs that may damage the operation of any computer network or other property.
<li type=disc> - Interfere with or disrupt networks connected to the ${minisrv_config.config.service_name} service or violate the regulations, policies, or procedures of such networks.
<li type=disc> - Use the ${minisrv_config.config.service_name} service in any manner that could damage, disable, overburden, or impair the ${minisrv_config.config.service_name} service (or the network(s) connected to the ${minisrv_config.config.service_name} service).
<li type=disc> - Attempt to gain or gain unauthorized access to any part of the ${minisrv_config.config.service_name} service, other accounts, Internet units, computer systems or networks connected to the ${minisrv_config.config.service_name} service, through hacking, password mining or by any other means.
<li type=disc> - Violate any applicable laws or regulations including, without limitation, laws regarding the transmission of technical data, software or hardware exported from the United States and/or Canada.
<li type=disc> - Interfere with another member's use and enjoyment of the ${minisrv_config.config.service_name} service or another individual's or entity's use and enjoyment of similar services.
<li type=disc> - View, intercept, or attempt to intercept e-mail or other private communication not intended for you.
<li type=disc> - Violate any posted guidelines or codes relating to the use of the ${minisrv_config.config.service_name} service or a particular service.
</ul>
<P>Without limiting any of ${WTVRegister.getServiceOperator(true)}'s rights to terminate your Account as described elsewhere in this Agreement, ${WTVRegister.getServiceOperator(true)}
may immediately terminate your Account at any time without notice for violation of any of the foregoing rules, as it determines in their sole discretion.
<p>Always use caution when giving out any personal information about yourself or your children. ${WTVRegister.getServiceOperator()} does not control or endorse the content,
messages or information found in any service or advertising content on ${minisrv_config.config.service_name} service, therefore, ${WTVRegister.getServiceOperator(true)}
specifically disclaims any liability with regard to the services or advertising content and any actions resulting from your participation in any service or
offers from advertising content providers. Managers and hosts of such services and advertising content are not authorized ${minisrv_config.config.service_name}
service spokespersons, and their views do not necessarily reflect those of ${WTVRegister.getServiceOperator()}.</P>
<P><B>1.4 Right to Monitor and Disclose.</B> ${WTVRegister.getServiceOperator()} has no obligation to monitor any member's use of the
${minisrv_config.config.service_name} service or retain the content of any user session. However, ${WTVRegister.getServiceOperator(true)} reserves the right at all times
and without notice to delete any content, remove any materials, monitor, review, retain and/or disclose any content or other information in ${WTVRegister.getServiceOperator(true)}'s
possession, however obtained, about or related to you and your use of the ${minisrv_config.config.service_name} service. ${WTVRegister.getServiceOperator()} reserves the
right at all times to disclose any information that ${WTVRegister.getServiceOperator(true)} deems necessary to satisfy any applicable law, regulation, legal process or
governmental request, or to edit, refuse to post or to remove any information or materials, in whole or in part, in ${WTVRegister.getServiceOperator(true)}'s sole discretion.
<P><B>1.5 Links to Other Websites.</B> THE LINKS INCLUDED WITHIN THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE AND/OR ITS RELATED WEB SITES
MAY LET YOU LEAVE THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE AND VISIT NON-RELATED SITES ("LINKED SITES"). THE LINKED SITES ARE NOT UNDER THE CONTROL OF ${WTVRegister.getServiceOperator().toUpperCase()}
AND ${WTVRegister.getServiceOperator().toUpperCase()} IS NOT RESPONSIBLE FOR THE CONTENTS OF ANY LINKED SITE, INCLUDING ANY LINK CONTAINED IN A LINKED SITE,
OR ANY CHANGES OR UPDATES TO A LINKED SITE. ${WTVRegister.getServiceOperator().toUpperCase()} IS NOT RESPONSIBLE FOR WEBCASTING OR ANY OTHER FORM OF TRANSMISSION RECEIVED
FROM ANY LINKED SITE, NOR IS ${WTVRegister.getServiceOperator().toUpperCase()} RESPONSIBLE IF THE LINKED SITE IS NOT WORKING PROPERLY. ${WTVRegister.getServiceOperator().toUpperCase()}
PROVIDES THESE LINKS TO YOU ONLY AS A CONVENIENCE, AND THE INCLUSION OF ANY LINK DOES NOT IMPLY ENDORSEMENT BY ${WTVRegister.getServiceOperator().toUpperCase()}
OF THE LINKED SITE OR ANY ASSOCIATION WITH THE LINKED SITE'S OPERATORS, NOR DOES IT CREATE AN OBLIGATION ON THE PART OF ${WTVRegister.getServiceOperator().toUpperCase()}
TO MAINTAIN OR PRESERVE SUCH LINK.</P>
<P><B>1.6 Dealings with Third Parties.</B>
You are subject to all the terms specified by the Linked Sites you visit. If another party reports that you have violated its terms of service agreement,
${WTVRegister.getServiceOperator(true)} may treat your violation as a violation of this Agreement. Any dealings with third parties (including advertisers)
included within the ${minisrv_config.config.service_name} service or participation in promotions,
including the delivery of and the payment for goods and services, and any other terms, conditions, warranties or representations associated with such dealings or promotions,
are solely between you and the advertiser or other third party. ${WTVRegister.getServiceOperator()} will not be responsible or liable for any aspect of any such dealings or promotions,
nor will ${WTVRegister.getServiceOperator(true)} be responsible for any purchases or charges incurred by you or any Secondary User through use of the
${minisrv_config.config.service_name} service.</P>
<P><B>1.7 Copyrighted Materials, Software and Intellectual Property.</B>
You agree to hold ${WTVRegister.getServiceOperator(true)} harmless for any improper use of copyrighted materials accessed through the ${minisrv_config.config.service_name}
service by you. ${WTVRegister.getServiceOperator()} bears no responsibility for, and you agree to assume all risks regarding, the alteration, falsification, misrepresentation,
reproduction, or distribution of copyrighted materials without the proper permission of the copyright owner. Furthermore, you agree and acknowledge that ${WTVRegister.getServiceOperator(true)},
its partners and its suppliers retain title to and ownership of all software and intellectual property that is part of the ${minisrv_config.config.service_name} service.
You will not acquire any right, title or interest in the same except for the limited rights expressly granted to you in this Agreement.</P>
<P><B>1.8 Posting to ${minisrv_config.config.service_name} service.</B> ${WTVRegister.getServiceOperator()} does not claim ownership of the materials, feedback and suggestions
you provide to ${WTVRegister.getServiceOperator(true)} or post, upload, input, or submit to ${WTVRegister.getServiceOperator(true)} operated Web Site or its associated services ("Submission").
However, by posting, uploading, inputting, providing, or submitting your Submission, you grant ${WTVRegister.getServiceOperator(true)} and its affiliates permission to use
your Submission in connection with the operation of their Internet businesses including, without limitation, the rights to: </P>
<P>
&nbsp;&nbsp;&nbsp a. use, copy, distribute, transmit, publicly display, publicly perform, reproduce, edit, translate, reformat, create derivative works from, transfer, or sell your Submission;
<br>
&nbsp;&nbsp;&nbsp b. sublicense to third parties the unrestricted right to exercise any of the foregoing rights granted with respect to your Submission.
<P>
The foregoing grants shall include the right to exploit any proprietary rights in your Submission, including but not limited to rights under copyright,
trademark, service mark or patent laws under any relevant jurisdiction. No compensation will be paid with respect to the use of your Submission.
${WTVRegister.getServiceOperator()} is under no obligation to post or use any Submission you may provide and may remove any Submission at any time, in
${WTVRegister.getServiceOperator(true)}'s sole discretion. By posting, uploading, inputting, providing, or submitting your Submission, you warrant and represent
that you own or otherwise control all of the rights to your Submission, as described in this section including, without limitation, all the legal rights
necessary for you to provide, post, upload, input, or submit the Submission. This section is inapplicable to any personally identifiable information that
you provide in connection with your registration for the ${minisrv_config.config.service_name} service. For terms and conditions governing use of such information,
please refer to the ${minisrv_config.config.service_name} Service Statement of Privacy at the bottom of this document. This privacy statement is controlling and
overrides any conflicting language contained in these Terms of Service concerning use of such information.
<P>&nbsp;</P>
<p><a name="termination"><b>2. <u>Termination of Service</u></b></a>
<P><B>2.1 Termination.</B> You may terminate your Account at any time, with or without cause, by visiting your Account Settings within the ${minisrv_config.config.service_name} service.
${WTVRegister.getServiceOperator()}, at their sole discretion, may also delete your Account upon request. Termination via the service shall be effective immediately, while terimation via
manual contact may take longer. For guaranteed termination, you should use the option provided within the ${minisrv_config.config.service_name} service.
<P><B>2.2 User Information Unavailable After Termination.</B> Upon termination,
the registration and user information for you will no longer be available to you from ${WTVRegister.getServiceOperator()}.
This includes e-mail, address book information and other stored user preferences on the ${minisrv_config.config.service_name} service. If you wish to retain such information,
you must make your own copies prior to the termination of your Account. Upon termination, all stored data is immediately destroyed, and unrecoverable.
In the event that ${WTVRegister.getServiceOperator()} retains backups, restoration MAY be possible, but should not be expected.
If your Account is terminated for abuse, your Internet unit will be designated as "suspended" and will not be cleared for re-registration with the
${minisrv_config.config.service_name} service for a period of one year or longer, in the sole discretion of ${WTVRegister.getServiceOperator()}.
${minisrv_config.config.service_name} service will not be able to retrieve or forward to you any e-mail from your account in any format.</P>
<P>&nbsp;</P>
<p><a name="service"><b>3. <u>Service Operation and Equipment</u></b></a>
<P><B>3.1 Provision and Use of Equipment.</B> The ${minisrv_config.config.service_name} service may only be accessed with an authorized Internet unit.
Only products labeled with a ${minisrv_config.config.service_name}, or WebTV&reg; product logo or trademark may be used to access the ${minisrv_config.config.service_name}
service. You agree that in the event of any malfunction of your Internet unit, you will repair it to the best of your ability. If the unit is problematic, and cannot be repaired,
you agree to NOT continue to use the malfunctioning device with the ${minisrv_config.config.service_name} service.</P>
<P><B>3.2 Account Limitations and Transfers</B> The ${minisrv_config.config.service_name} service can only associate your account with ONE Internet receiver at a time. In the event
that the Internet receiver associated to your account is no longer suitable for use on the ${minisrv_config.config.service_name} service, you will need to either (i) create a new
account; or (ii) contact ${WTVRegister.getServiceOperator(true)} and ask to transfer your account to your new Internet receiver. Please be aware that in order to transfer your account,
${WTVRegister.getServiceOperator(true)} will need to know both the SSID (Silicon Serial Identifier) of the old Internet receiver, and the new Interner reciever. ${WTVRegister.getServiceOperator()} may
also require additional verification from you to prove that the account belongs to you.
<P><B>3.3 Limited Storage Space.</B> The amount of storage space per user on the ${minisrv_config.config.service_name} service is limited. Some messages may not be
processed due to space constraints or outbound message limitations. You agree that ${WTVRegister.getServiceOperator()} is not responsible or liable for any deletion or
failure to store messages or other information. You agree to delete old messages from the ${minisrv_config.config.service_name} service in order to make room in
your mailboxes for new messages. From time to time, ${WTVRegister.getServiceOperator()} may delete old messages from your mailbox that are older than a certain date
or that exceed certain storage limitations.</P>
<P><B>3.4 Right to Suspend the ${minisrv_config.config.service_name}service.</B> ${WTVRegister.getServiceOperator()} may, in its sole discretion and without prior notice:
(i) restrict or limit access to the ${minisrv_config.config.service_name} service; or (ii) terminate an account or user sessions at any time.
The above described actions are not ${WTVRegister.getServiceOperator()}'s exclusive remedies, and, notwithstanding any action taken or failure thereof, ${WTVRegister.getServiceOperator()}
may take any other legal or technical action it deems appropriate. Users who violate ${WTVRegister.getServiceOperator()}'s systems or network security may also incur
criminal and/or civil liability.</P>
<P><B>3.5 Updates to the ${minisrv_config.config.service_name} service.</B> ${WTVRegister.getServiceOperator()} has the right to update or modify the ${minisrv_config.config.service_name}
service from time to time without notice, including, but not limited to, access procedures, menu structures, commands, documentation, features, functionality
and services offered. Updates will be offered at no cost.
<P><B>3.6 Complaints About ${WTVRegister.getServiceOperator()} Users.</B> All complaints regarding any ${minisrv_config.config.service_name} service user must
be sent directly to <b>${WTVRegister.getServiceOperator()}</b> along with a copy of any e-mail, posting or other proof of offensive conduct in violation of this Agreement.</P>
<P>&nbsp;</P>
<p><a name="disclaimer"><b>4. <u>Disclaimer, Warranties and Indemnification</u></b></a>
<P><B>4.1 Disclaimer and Warranties.</B> You specifically agree that ${WTVRegister.getServiceOperator()}
shall not be responsible for unauthorized access to or alteration of your
transmissions or data, any material or data sent or received or not sent or
received, or any transactions entered into through or using the ${minisrv_config.config.service_name} service.
You specifically agree that ${WTVRegister.getServiceOperator()} is not responsible or liable for any act
or omission of any third party including but not limited to any threatening,
defamatory, obscene, offensive or illegal content or conduct of any other
party or any infringement of another's rights, including intellectual property
rights. You specifically agree that ${WTVRegister.getServiceOperator()} is not responsible for any
content sent using and/or included in the ${minisrv_config.config.service_name} service by you or any third
party. YOUR USE OF THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE AND ALL ${WTVRegister.getServiceOperator().toUpperCase()} SOFTWARE AND SERVICES
IS AT YOUR OWN RISK. ${WTVRegister.getServiceOperator().toUpperCase()}, ITS RESELLERS, DISTRIBUTORS AND/OR SUPPLIERS
MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY, RELIABILITY, USABILITY,
AVAILABILITY, TIMELINESS, LACK OF VIRUSES OR OTHER HARMFUL COMPONENTS AND
ACCURACY OF THE INFORMATION, SOFTWARE, PRODUCTS, SERVICES AND RELATED GRAPHICS
CONTAINED WITHIN THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE FOR ANY PURPOSE. ALL SUCH INFORMATION,
SOFTWARE, PRODUCTS, SERVICES AND RELATED GRAPHICS ARE PROVIDED "AS IS" WITHOUT
WARRANTY OF ANY KIND. THE INFORMATION, SOFTWARE, PRODUCTS, AND SERVICES INCLUDED IN OR AVAILABLE
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,
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,
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
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
PROFITS, ARISING OUT OF OR IN ANY WAY CONNECTED WITH THE USE OR PERFORMANCE
OF THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE, ${WTVRegister.getServiceOperator().toUpperCase()} SOFTWARE OR RELATED WEB SITES, ANY DELAY OR
INABILITY TO USE THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE, ANY ${WTVRegister.getServiceOperator().toUpperCase()} SOFTWARE, OR RELATED WEB
SITES, THE PROVISION OF OR FAILURE TO PROVIDE SERVICES, LOST, DAMAGED, OR
DESTROYED E-MAIL OR THE FAILURE TO DELIVER ANY E-MAIL, OR FOR ANY INFORMATION,
SOFTWARE, PRODUCTS, SERVICES AND RELATED GRAPHICS OBTAINED THROUGH THE ${minisrv_config.config.service_name.toUpperCase()}
SERVICE, OR OTHERWISE ARISING OUT OF THE USE OF THE ${minisrv_config.config.service_name.toUpperCase()} SERVICE, WHETHER
BASED ON CONTRACT, TORT, NEGLIGENCE, STRICT LIABILITY OR OTHERWISE, EVEN IF
${WTVRegister.getServiceOperator().toUpperCase()} OR ANY OF ITS SUPPLIERS HAS BEEN ADVISED OF THE POSSIBILITY OF
DAMAGES.
${WTVRegister.getServiceOperator().toUpperCase()}'S LIABILITY TO YOU FOR BREACH OF THIS AGREEMENT IS LIMITED TO THE
AMOUNT ACTUALLY PAID BY YOU TO ${WTVRegister.getServiceOperator().toUpperCase()} FOR ACCESS TO AND USE OF THE ${minisrv_config.config.service_name.toUpperCase()}
SERVICE. YOU HEREBY RELEASE ${WTVRegister.getServiceOperator().toUpperCase()} FROM ANY AND ALL OBLIGATIONS, LIABILITIES,
AND CLAIMS IN EXCESS OF THIS LIMITATION. BECAUSE SOME STATES/JURISDICTIONS
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,
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.
</P>
<P><B>4.2 Indemnification</B> You agree to indemnify, defend, and hold ${WTVRegister.getServiceOperator()}, its parents, subsidiaries, members, affiliates,
officers, directors, employees, and agents harmless from any claim, demand, liability, expense, or damage, including costs and reasonable
attorneys' fees, asserted by any third party relating to or arising out of your use of or conduct on the ${minisrv_config.config.service_name} service.
${WTVRegister.getServiceOperator()} will notify you within a reasonable period of time of any claim for which ${WTVRegister.getServiceOperator()} seeks indemnification and will
afford you the opportunity to participate in the defense of such claim, provided that your participation will not be conducted in a manner prejudicial
to ${WTVRegister.getServiceOperator()}'s interests, as reasonably determined by ${WTVRegister.getServiceOperator()}.</P>
<P>&nbsp;</P>
<p><a name="notices"><b>5. <u>Notices; Consent.</u></b></a>
<p>Notices given by ${WTVRegister.getServiceOperator()} to you may be given by e-mail via the ${minisrv_config.config.service_name} service,
by a general posting on the ${minisrv_config.config.service_name} service, or by conventional mail. Notices given by you to ${minisrv_config.config.service_name} must
be given by e-mail via the ${minisrv_config.config.service_name} service or directly from ${WTVRegister.getServiceOperator()} via other forms of communication.
<p>
<P>&nbsp;</P>
<p><a name="spam"><b>6. <u>No "Spam"; Damages.</u></b></a>
<p>${WTVRegister.getServiceOperator()} may immediately terminate any account that it determines, in its sole discretion, is transmitting or is otherwise connected
with any "spam" or other unsolicited bulk e-mail. In addition, because damages are often difficult to quantify, if actual damages cannot be reasonably calculated,
you agree to pay ${WTVRegister.getServiceOperator()} liquidated damages of five dollars (U.S. $5.00) for each piece of "spam" or unsolicited bulk e-mail transmitted from or otherwise connected
with your account. Otherwise you agree to pay ${WTVRegister.getServiceOperator()}'s actual damages, to the extent such actual damages can be reasonably calculated.
You agree that ${WTVRegister.getServiceOperator()} may seek legal ramifications for such damages.</p>
<P>&nbsp;</P>
<p><a name="provisions"><b>7. <u>Additional Provisions</u></b></a>
<P><B>7.1 Disclosure of Information.</B> ${WTVRegister.getServiceOperator()} reserves the right to disclose any information necessary without your prior permission,
if ${WTVRegister.getServiceOperator()} has a good faith belief that such action is necessary to (1) comply with governmental,
court and law enforcement requests or requirements; (2) protect and defend the rights or property of ${WTVRegister.getServiceOperator()},
its affiliated companies, the ${minisrv_config.config.service_name} service or the users of the ${minisrv_config.config.service_name} service, whether or not required
to do so by law; (3) enforce this Agreement; (4) protect the personal safety of users of the ${minisrv_config.config.service_name} service or the public.
${WTVRegister.getServiceOperator()}'s performance of this Agreement is subject to existing laws and legal process, and nothing contained in this Agreement
is in derogation of ${WTVRegister.getServiceOperator()}'s right to comply with governmental, court and law enforcement requests or requirements relating
to your use of the ${minisrv_config.config.service_name} service. You are advised that certain unauthorized uses of the ${minisrv_config.config.service_name}
service, including but not limited to admissions of illegal behavior or the posting of pornography, may result in additional fees, fines or charges,
the suspension or termination of your Account, and/or civil or criminal liability. In addition, ${WTVRegister.getServiceOperator()} may, in its discretion, report incidents
of child pornography to the Cyber Tip Line at the National Center for Missing and Exploited Children.</P>
<P><B>7.2 Entire Agreement.</B> This Agreement, including the Statement of Privacy, and any other notices and disclaimers posted on the service,
constitutes the entire agreement between ${WTVRegister.getServiceOperator()} and you, the Primary User, with respect to your use of the ${minisrv_config.config.service_name}
service and your Account (excluding the use of any software which may be subject to an end-user license agreement), and it supersedes all prior or
contemporaneous communications and proposals, whether oral or written, between ${WTVRegister.getServiceOperator()} and you with respect to the ${minisrv_config.config.service_name} service.</P>
<P><B>7.3 Enforcement.</B> In the event that any portion of this Agreement is held to be unenforceable, the unenforceable portion shall be construed
in accordance with applicable law to reflect the original intentions of the parties and the remaining provisions shall remain in full force and effect.
${WTVRegister.getServiceOperator()}'s failure to insist upon or enforce strict performance of any provision of this Agreement does not mean that ${WTVRegister.getServiceOperator()}
has waived any provision or right in this Agreement.</P>
<P><b>7.4 Assignment.</b> ${WTVRegister.getServiceOperator()} may assign this Agreement, in whole or in part, at any time with or without notice to you. You may not assign or transfer this Agreement.
<P><b>7.5 Miscellaneous.</b> A printed copy of this Agreement and of any notice given by ${WTVRegister.getServiceOperator()} in electronic form shall be
admissible in judicial or administrative proceedings based upon or relating to this Agreement to the same extent and subject to the same conditions
as other business documents and records originally generated and maintained in printed form. You and ${WTVRegister.getServiceOperator()} agree that any cause of
action arising out of or related to the ${minisrv_config.config.service_name} service must commence within one (1) year after the cause of action arises;
otherwise, such cause of action is permanently barred. The section titles in the Agreement are provided solely for the convenience of the parties and have
no legal or contractual significance.</P>
<P><b>7.6 Agreement Drawn in English.</B> The parties to this Agreement confirm that it is their wish that this Agreement, as well as all other documents
relating to it, have been and shall be drawn up in the English language only. Any conflict between this Agreement and any translations provided
by ${WTVRegister.getServiceOperator()} or its partners or providers in other languages, either orally or in printed form, shall be resolved in favor of this English language version.
Les parties aux pr<70>sentes confirment leur volont<6E> que cette convention, de m<>me que tous les documents qui s'y rattachent, soient r<>dig<69>s en langue anglaise.</P>
<P><B>8. <u>Copyright and Trademark Notices</u></B>
<P><B>8.1 Copyright and Trademark.</B> All contents of the ${minisrv_config.config.service_name} service are: Copyright <20> ${new Date().getFullYear()} ${WTVRegister.getServiceOperator()}
and/or its suppliers, All rights reserved.
<P><B>8.2 Notices and Procedure for Making Claims of Copyright Infringement.</B>
Pursuant to Title 17, United States Code, Section 512(c)(2), notifications of claimed copyright infringement should be sent to the ${WTVRegister.getServiceOperator()}.
<P>END of TERMS of SERVICE</P>
<p>
<p>
<CENTER><B>${minisrv_config.config.service_name} Service Privacy Statement</B></font><br>
<B><font size="-1">(Release date August 7, 2021)</B></CENTER></font>
<P>&nbsp;</P>
<p>The ${minisrv_config.config.service_name} service is a limited Internet access service for television brought to you by ${WTVRegister.getServiceOperator(true)}. ${WTVRegister.getServiceOperator()}
is committed to maintaining the privacy and accuracy of your personal information.
<p>This Privacy Statement describes how ${WTVRegister.getServiceOperator(true)} treats information received about you when you use the ${minisrv_config.config.service_name} service. Please read it carefully.
<p><b>Collection and Use of Personal Information</b><br>
When you register as a primary user of the ${minisrv_config.config.service_name} service, ${WTVRegister.getServiceOperator()} will request information that personally identifies
you or allows us to contact you, such as your name, and e-mail address. Personal information is also collected at other times by specifically requesting it from you,
such as when you request other promotional material, when we ask you to complete customer surveys, and in other circumstances when you interact with the
${minisrv_config.config.service_name}service or our employees, agents and contractors working to provide the ${minisrv_config.config.service_name} service to you.
Information collected by ${WTVRegister.getServiceOperator(true)} may be combined with information obtained from other ${WTVRegister.getServiceOperator(true)} operations and other services.
<p>${WTVRegister.getServiceOperator()} collects, stores and processes personal information for the following purposes:
<ul>
<li>To service accounts, process or collect payments, and otherwise operate and deliver the ${minisrv_config.config.service_name} service.
<li>To assist you with questions about use of the ${minisrv_config.config.service_name} service.
<li>To conduct both business and individual surveys to be used for the purposes set forth in the survey.
<li>To alert you to new products, product upgrades, special offers and other information related to the ${minisrv_config.config.service_name} service.
<li>To inform you of other products or services available from ${WTVRegister.getServiceOperator(true)} and its affiliates and external business partners.
</ul>
<p><b>With Whom Personal Information Is Shared</b><br>
Personal information collected by ${WTVRegister.getServiceOperator(true)} may be combined with information obtained from other ${WTVRegister.getServiceOperator(true)} operations and other services.
This combined information may be shared with business units within ${WTVRegister.getServiceOperator(true)}. ${WTVRegister.getServiceOperator()} may also share your personal information with
third parties for their use to provide services to ${WTVRegister.getServiceOperator(true)} in the operation and delivery of the ${minisrv_config.config.service_name} service,
such as to process or collect payments, service ${minisrv_config.config.service_name} service accounts, or provide the products and services associated with the
${minisrv_config.config.service_name} service. Third parties to whom we provide this personal information are prohibited from using it except to provide these services.
These third parties are also required to maintain the confidentiality of the personal information we provide to them.
<p>Occasionally we may send you information or special offerings about products or services from ${WTVRegister.getServiceOperator(true)} or third parties that we believe may be of
interest to you.
<p>Except under the circumstances described above, or as described below under "Other Situations in which Personal and/or Operating Information May Be Disclosed,"
${WTVRegister.getServiceOperator(true)} does not disclose your personal information to third parties. <p><b>How To Access and Modify Personal Information</b><br>
<p><b>How We Help Protect Children's Privacy</b><br>
${WTVRegister.getServiceOperator()} currently does not knowingly collect or use personal information from children under 13 on the ${minisrv_config.config.service_name} service.
Should a child on the ${minisrv_config.config.service_name} service whom we know to be under 13 send personal information to us,
we will only use that information to respond directly to that child or seek parental consent. Parents are ultimately responsible for the use of the
${minisrv_config.config.service_name} service by their children. We encourage parents to talk to their children about safe and responsible use of their
personal information while using the Internet. <p><b>Collection and Use of Operating Information</b><br>
${WTVRegister.getServiceOperator()} collects and stores operating information, which consists of the electronic instructions and data communicated from your
set-top device to the ${minisrv_config.config.service_name} service. Operating information includes the websites you have chosen to access.
The ${minisrv_config.config.service_name} service may also contain electronic images known as "Web beacons" that allow us to count users who
have visited a particular area of the service. On certain ${minisrv_config.config.service_name} service receivers (known as "Plus" receivers),
you may select television channels using the ${minisrv_config.config.service_name}service or with the remote control for the ${minisrv_config.config.service_name} receiver.
${WTVRegister.getServiceOperator()} does not collect any information regarding these television channels selected by you however.
<p>We use operating information to effectively operate the ${minisrv_config.config.service_name} service and enhance your experience on the Internet.
For example, we store the websites that you have selected to be part of your list of favorite sites so that you can access them quickly.
We also store the most recent websites that you have visited to make browsing more efficient. Operating information may also be used to customize
the advertising, content, information and services that are delivered to your set top device.
<p>${WTVRegister.getServiceOperator()} also uses operating information to understand how our system is being used and navigated.
For example, we process aggregated operating information concerning the number of visits to certain websites, the use of certain features,
such as "Mail" and "Search," and the number of set-top devices that are exposed to certain advertisements placed by advertisers on our system.
In general, the collection and use of operating information allows us to analyze the use of the ${minisrv_config.config.service_name} service to continue to develop and provide
improved advertising, content, features and services that are of the most interest to our subscribers. <p><b>With Whom Operating Information Is Shared</b><br>
We may provide operating information to third parties for their use to provide services to us in the operation and delivery of the ${minisrv_config.config.service_name} service.
These third parties are prohibited from using this operating information except to provide these services. They are also required to maintain the confidentiality
of the operating information we provide to them. <p>We may also provide operating information in anonymous form to third parties. This anonymous information contains
no personal information about any of our individual subscribers. Except under the circumstances described above, or as described below under
"Other Situations in which Personal and/or Operating Information May Be Disclosed," we will only share operating information with third parties if the operating
information is in anonymous form. <p><b>How We Help Protect Personal and Operating Information</b><br>
We take reasonable steps to help protect personal and operating information. We use technologies and processes such as encryption, access control procedures,
network firewalls and physical security. These technologies and methods limit unauthorized access to information collected through the ${minisrv_config.config.service_name}
service. <p>Furthermore, most operating information is maintained in databases that are separate from those containing personal information, and only
${WTVRegister.getServiceOperator()} or authorized agents carrying out permitted business functions are permitted to access this information.
<p>You should explain this privacy statement to others that use the ${minisrv_config.config.service_name} service through your account, including other members of your household.
If you allow others to access the ${minisrv_config.config.service_name} service through your account, including other members of your household,
please understand that you are responsible for the actions of those individuals. <p><b>Other Situations in which Personal and/or Operating Information May Be Disclosed</b><br>
${WTVRegister.getServiceOperator()} may disclose personal or operating information if required to do so by law or in the good-faith belief that such action is necessary or
appropriate to (a) conform to the edicts of the law or comply with legal process served on ${WTVRegister.getServiceOperator(true)}, (b) protect and defend the rights or property
of ${WTVRegister.getServiceOperator(true)}, the ${minisrv_config.config.service_name} service, or users of the ${minisrv_config.config.service_name} service, whether
or not required to do so by law, or (c) protect the personal safety of users of the ${minisrv_config.config.service_name} service or the public.
${WTVRegister.getServiceOperator()} reserves the right to contact and disclose personal information to appropriate authorities at its discretion when it appears that
activities that are illegal or violate the ${minisrv_config.config.service_name} Service User Agreement are taking place within the context of a user account.
<p><b>Cookies</b><br>
Cookies are pieces of information that a website creates for record-keeping purposes. The ${minisrv_config.config.service_name} service does not create or use cookies,
but the websites you access, might create cookies and transfer these cookies to ${minisrv_config.config.service_name} service servers. Cookies can make your experience
on the Internet more useful by storing information about your preferences and choices on a particular site. This enables websites to customize delivery of their website
content and advertisements. ${WTVRegister.getServiceOperator()} does not control the use of cookies by other website operators, website page builders or their advertisers.
<p><b>Changes to the ${minisrv_config.config.service_name} Service Privacy Statement</b><br>
${WTVRegister.getServiceOperator()} may make changes to this statement from time to time. We will post changes to our privacy statement here, so be sure to check back periodically.
We will also notify you of significant changes by e-mail or in other ways. <p>
</BODY>
</HTML>
</tr>
<tr>
<td valign= bottom height=15 colspan=7>
<hr size=5 valign=bottom>
</tr>
<tr>
<td border=2 absheight=50 colspan=5 bgcolor="#171726" valign=top align=left style="margin-right:50">
<td bgcolor="#171726" height=50 abswidth=100 valign=top align=right style="padding-right:13">
</form>
<td abswidth=13 absheight=50 bgcolor="#171726">
</tr>
</table>
</body>
</html>
`

View File

@@ -0,0 +1,79 @@
const WTVReg = require("./WTVRegister.js")
var WTVRegister = new WTVReg(minisrv_config.config.service_owner);
if (!request_headers.query.registering) {
var errpage = doErrorPage(400);
headers = errpage[0];
data = errpage[1];
} else {
headers = `200 OK
Content-Type: text/html`;
data = `<html>
<head>
<title>Terms of Service</title>
<display nooptions>
</head>
<sidebar width=110 bgcolor=#5b6c81 fontsize="large" font color="#171726" absheight=300> <table width=150 height=450 cellspacing=0 cellpadding=2 BGCOLOR="#171726">
<tr>
<td align=middle valign=top bgcolor="#5b6c81" border=0 abswidth="200" height="80"><font color="#171726" >
<img src="${minisrv_config.config.service_logo}" >
<p><br> <font size=-1 color="#171726"> <i> To read <br>more of this <br>page, press <b>scroll down</b>
<br><br>
<form name="theForm"
action="/ValidateAgreement" method="POST">
<input type=hidden name=registering value="true">
To agree<br> to these terms<br> and go on, <br>choose <b>Accept</b><br>
</i></font><p>
<font size="-1" color="#E7CE4A">
<shadow>
<img src="wtv-star:/ROMCache/Spacer.gif" width=18 height=1><p>
<input type=submit Value=Accept name="Agree" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=100>
<img src="wtv-star:/ROMCache/Spacer.gif" width=18 height=1><p>
<input type=submit Value=Decline
name="Decline"
action="/ServeAgreementDeclinePage"
borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=100
selected>
</shadow>
</font>
</form>
</tr>
</table>
</sidebar>
<BODY bgcolor="#171726" hspace=0 vspace=0 fontsize=large text=#d1d3d3 link=#FFEA9C vlink=#FFEA9C>
<form name="theForm" action="/ValidateAgreement">
<input type=hidden name=registering value="true">
<BODY bgcolor="#171726" hspace=0 vspace=0 fontsize=large text=#d1d3d3>
<TABLE width=450 height=200 ALIGN=left VALIGN=BOTTOM vspace=0 hspace=0 cellspacing=0 cellpadding=0>
<tr>
<td colspan= 8 height="30">
<tr>
<td abswidth=20 bgcolor="#171726">
<td height=202 width= 300 bgcolor="#171726" colspan=6 valign=top align=left>
<P ALIGN="CENTER">TERMS OF SERVICE AND NOTICES</P>
To create your ${minisrv_config.config.service_name} account, you must review and agree to the agreements and statements below. Use these links to review the documents: <br>
<br>
<a href="wtv-register:/ServeLegal">Review the ${minisrv_config.config.service_name} Subscription Agreement and ${minisrv_config.config.service_name} Privacy Statement</a>
<br>
<br>
By choosing <b>Accept</b>, you acknowledge that you have read the documents listed above and are agreeing to be bound by them.
You are also consenting to receive all information from ${WTVRegister.getServiceOperator()} in electronic form including the documents listed above.
</BODY>
</HTML>
</tr>
<tr>
<td valign= bottom height=15 colspan=7>
<hr size=5 valign=bottom>
</tr>
<tr>
<td border=2 absheight=50 colspan=5 bgcolor="#171726" valign=top align=left style="margin-right:50">
<td bgcolor="#171726" height=50 abswidth=100 valign=top align=right style="padding-right:13">
</form>
<td abswidth=13 absheight=50 bgcolor="#171726">
</tr>
</table>
</body>
</html>
`;
}

View File

@@ -0,0 +1,130 @@
const WTVReg = require("./WTVRegister.js")
var WTVRegister = new WTVReg(minisrv_config.config.service_owner, SessionStore);
if (!request_headers.query.registering) {
var errpage = doErrorPage(400);
headers = errpage[0];
data = errpage[1];
} else {
var errpage = null;
if (!request_headers.query.registering) errpage = doErrorPage(400);
else if (!request_headers.query.subscriber_name) errpage = doErrorPage(400, "Please enter your name. This can be your real name, or your well-known online alias.");
else if (!request_headers.query.subscriber_username) errpage = doErrorPage(400, "Please enter a username.");
else if (unescape(request_headers.query.subscriber_username).length < 5) errpage = doErrorPage(400, "Please choose a username with 5 or more characters.");
else if (unescape(request_headers.query.subscriber_username).length > 16) errpage = doErrorPage(400, "Please choose a username with 16 or less characters.");
else if (!WTVRegister.checkUsernameSanity(unescape(request_headers.query.subscriber_username))) errpage = doErrorPage(400, "The username you have chosen contains invalid characters. Please choose a username with only <b>letters</b>, <b>numbers</b>, <b>_</b> or <b>-</b>. Also, please be sure your username begins with a letter.");
else if (!WTVRegister.checkUsernameAvailable(request_headers.query.subscriber_username, ssid_sessions)) errpage = doErrorPage(400, "The username you have selected is already in use. Please select another username.");
else if (!request_headers.query.subscriber_contact) errpage = doErrorPage(400, "Please enter your contact information.");
else if (request_headers.query.subscriber_contact_method == "") errpage = doErrorPage(400, "Please select the type of contact information you provided.");
if (errpage) {
headers = errpage[0];
data = errpage[1];
} else {
headers = `200 OK
wtv-noback-all: wtv-register:
Content-Type: text/html`;
data = `<html>
<head>
<title>
Review </title>
<display nooptions noscroll NoScroll
>
</head>
<body noscroll
bgcolor="#171726" text="#D1D3D3" link=#FFEA9C vlink=#FFEA9C
hspace=0 vspace=0 fontsize="large"
link="36d5ff" vlink="36d5ff" >
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td align=middle bgcolor="#5b6c81" border=0 colspan= 3 width="100" height="80">
<img src="${minisrv_config.config.service_logo}" WIDTH="87" HEIGHT="67">
<td colspan= 6 bgcolor="#5b6c81" border=0 width=100% absheight="80" valign=bottom >
<img src="images/head_registration.gif" >
<tr>
<td bgcolor= "#5b6c81" border=0 rowspan=2 width=21 height= 220></td>
<td bgcolor="#171726" border=0 width=9 height=25 align=left valign=top>
<img src="images/L_corner.gif" width=8 height=8>
<td bgcolor="#171726" border=1 colspan=1 width=70 height=25>
<td colspan=6 bgcolor="#171726" border=1 height=25 align=left valign=bottom gradcolor=#262E3D gradangle=90>
<font color=#d1d3d3 size=+1>
<blackface>
Review account info
</blackface></font>
<tr> <td border=0 width=40 bgcolor="#171726" rowspan="2" >
<td absheight=20 width=100 bgcolor="#171726" colspan=6>
</tr>
</table>
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td bgcolor= "#5b6c81" border=0 rowspan=6 abswidth=21 height= 220></td>
<td border=0 abswidth=40 bgcolor="#171726" rowspan="6" >
<form ACTION="ValidateReviewAccountInfo" ENCTYPE="x-www-form-encoded" METHOD="POST">
<input type=hidden name=registering value="true">
<input type=hidden name=subscriber_name value="${unescape(request_headers.query.subscriber_name)}">
<input type=hidden name=subscriber_username value="${unescape(request_headers.query.subscriber_username)}">
<input type=hidden name=subscriber_contact value="${unescape(request_headers.query.subscriber_contact)}">
<input type=hidden name=subscriber_contact_method value="${unescape(request_headers.query.subscriber_contact_method)}">
<td height=50 width= 300 bgcolor="#171726" colspan=6 valign=top align=left>
Here is your account information. If you need to<br>
correct an item, press <b>Back</b>.
<p>
<tr>
<td width=260 valign=top align=left colspan=4>
<table cellspacing=0 cellpadding=0 border=0 >
<img src="images/arrow.gif">&nbsp;&nbsp;<font size=-2><b>NAME</b></font><br>
<tt><font color=#d1d3d3 size=-2><spacer type=horizontal size=17> ${unescape(request_headers.query.subscriber_name)}</font></tt></a>
</table>
<p>
<table cellspacing=0 cellpadding=0 border=0>
<img src="images/arrow.gif">&nbsp;&nbsp;<font size=-2><b>CONTACT</b></font><br>
<tt><font color=#d1d3d3 size=-2><spacer type=horizontal size=17> ${unescape(request_headers.query.subscriber_contact)}</font></tt></a>
</table>
</TD>
<td abswidth=200 bgcolor=#171726 valign=top align=left>
<table cellspacing=0 cellpadding=0 border=0> <TR><TD>
<img src="images/arrow.gif"><font size=-2>&nbsp;&nbsp;<b>USERNAME</b></font><br>
<tr><td maxlines=1 >
<tt><font color=#d1d3d3><spacer type=horizontal size=17>${unescape(request_headers.query.subscriber_name)}</font></tt></a>
</table>
<p>
<table cellspacing=0 cellpadding=0 border=0>
<img src="images/arrow.gif">&nbsp;&nbsp;<font size=-2><b>CONTACT TYPE</b></font><br>
<tt><font color=#d1d3d3 size=-2><spacer type=horizontal size=17>${unescape(request_headers.query.subscriber_contact_method)}</font></tt>
</table> <P>&nbsp;<P>&nbsp;
<td abswidth=20 bgcolor=#171726 >
</tr>
<tr>
<td valign= bottom height=39 colspan=7 bgcolor=#171726>
<shadow>
<hr size=5 valign=bottom></shadow>
</tr>
<tr>
<td border=2 colspan=4 width=300 height=50 bgcolor=#171726 valign=top align=left>
<font size=-1><i>
To go on, highlight
<b>Sign Up</b>
and<br> press <b>Return</b>.
</i></font>
<td bgcolor=#171726 height=50 width=150 valign=top align=right>
<font size=-1 color=#e7ce4a>
<shadow>
<input selected
Value="Sign Up"
name="Sign Up" usestyle width=100
width="100"
type=submit Value=Continue name="Continue" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=110>
</shadow>
</font>
</form> <td abswidth=13 absheight=50 bgcolor=#171726>
</tr> </table>
</body>
</html>
`;
}
}

View File

@@ -0,0 +1,109 @@
const WTVReg = require("./WTVRegister.js")
var WTVRegister = new WTVReg(minisrv_config.config.service_owner);
if (!request_headers.query.registering) {
var errpage = doErrorPage(400);
headers = errpage[0];
data = errpage[1];
} else {
headers = `200 OK
Content-Type: text/html`;
data = `<html>
<head>
<title>
${minisrv_config.config.service_name} Account Setup
</title>
<display nooptions noscroll NoScroll>
</head>
<body noscroll
bgcolor="#171726" text="#D1D3D3" link=#FFEA9C vlink=#FFEA9C
hspace=0 vspace=0 fontsize="large"
>
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td align=middle bgcolor="#5b6c81" border=0 colspan= 3 width="100" height="80">
<img src="${minisrv_config.config.service_logo}" WIDTH="87" HEIGHT="67">
<td colspan= 6 bgcolor="#5b6c81" border=0 width=100% absheight="80" valign=bottom >
<img src="images/head_registration.gif" >
<tr>
<td bgcolor="#5b6c81" border=0 rowspan=2 width=21 height= 220></td>
<td bgcolor="#171726" border=0 width=9 height=25 align=left valign=top>
<img src="images/L_corner.gif" width=8 height=8>
<td bgcolor="#171726" border=1 colspan=1 width=70 height=25>
<td colspan=6 bgcolor="#171726" border=1 height=25 align=left valign=bottom gradcolor=#262E3D gradangle=90>
<font color=#d1d3d3 size=+1>
<blackface>
Account Information
</blackface></font>
<tr> <td border=0 width=40 bgcolor="#171726" rowspan="2" >
<td absheight=20 width=100 bgcolor="#171726" colspan=6>
</tr>
</table>
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td bgcolor= "#5b6c81" border=0 rowspan=6 abswidth=21 height= 220></td>
<td border=0 abswidth=40 bgcolor="#171726" rowspan="6" >
<form action="ValidateAccountInfo"
ENCTYPE="x-www-form-encoded" METHOD="POST">
<input type=hidden name=registering value="true">
<td height=230 width=300 bgcolor="#171726" colspan=5 valign=top align=left>
Please set up your account:<br><br>
<font size="-2"><b>YOUR NAME:</b></font><img src="ROMCache/spacer.gif" width="7">
<img src="ROMCache/spacer.gif" width="78" height="5"><INPUT NAME="subscriber_name"
ID="subscriber_name"
bgcolor=#444444 text=#ffdd33 cursor=#cc9933
VALUE="${request_headers.query.subscriber_name || ""}" TYPE="text" SIZE="19"
MAXLENGTH="18"
AutoCaps selected>
<p>
<font size="-2"><b>DESIRED USERNAME:</b></font><img src="ROMCache/spacer.gif" width="7">
<img src="ROMCache/spacer.gif" width="5"><INPUT NAME="subscriber_username"
ID="subscriber_username"
bgcolor=#444444 text=#ffdd33 cursor=#cc9933
VALUE="${request_headers.query.subscriber_username || ""}" TYPE="text" SIZE="19"
MAXLENGTH="16"
AutoCaps selected>
<p>
<font size="-2"><b>YOUR CONTACT INFO:</b></font><img src="ROMCache/spacer.gif" width="7">
<INPUT NAME="subscriber_contact"
ID="subscriber_contact"
bgcolor=#444444 text=#ffdd33 cursor=#cc9933
VALUE="" TYPE="text" SIZE="19"
MAXLENGTH="64"
AutoCaps selected>
<p>
<font size="-2"><b>CONTACT INFO TYPE:</b></font><img src="ROMCache/spacer.gif" width="7">
<img src="ROMCache/spacer.gif" width="3"><select usestyle id="subscriber_contact_method" name="subscriber_contact_method">
<option value="">Type</option>
<option>E-Mail</option>
<option>Discord</option>
<option>Twitter</option>
<option>Telegram</option>
<option>Instagram</option>
</select>
<p>
<td abswidth=20 bgcolor=#171726 >
</tr>
<tr>
<td valign= bottom height=15 colspan=7 bgcolor=#171726>
<shadow>
<hr size=5 valign=bottom></shadow>
</tr>
<tr>
<td border=2 colspan=4 width=560 height=50 bgcolor=#171726 valign=top align=left>
<font size=-1><i>
</i></font>
<td bgcolor=#171726 height=50 width=150 valign=top align=right>
<font size=-1 color=#e7ce4a>
<shadow>
<input type=submit Value=Continue name="Continue" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=110>
</shadow>
</font>
</form> <td abswidth=13 absheight=50 bgcolor=#171726>
</tr> </table>
</body>
</html>
`;
}

View File

@@ -0,0 +1,99 @@
if (!request_headers.query.registering ||
!request_headers.query.subscriber_name ||
!request_headers.query.subscriber_username ||
!request_headers.query.subscriber_contact ||
!request_headers.query.subscriber_contact_method ||
!ssid_sessions[socket.ssid].session_store ||
!ssid_sessions[socket.ssid] ||
!socket.ssid
) {
var errpage = doErrorPage(400);
headers = errpage[0];
data = errpage[1];
} else {
ssid_sessions[socket.ssid].setSessionData("subscriber_name", unescape(request_headers.query.subscriber_name));
ssid_sessions[socket.ssid].setSessionData("subscriber_username", unescape(request_headers.query.subscriber_username));
ssid_sessions[socket.ssid].setSessionData("subscriber_contact", unescape(request_headers.query.subscriber_contact));
ssid_sessions[socket.ssid].setSessionData("subscriber_contact_method", unescape(request_headers.query.subscriber_contact_method));
ssid_sessions[socket.ssid].setSessionData("subscriber_userid", '1' + Math.floor(Math.random() * 1000000000000000000));
ssid_sessions[socket.ssid].setSessionData("registered", true);
if (!ssid_sessions[socket.ssid].storeSessionData()) {
var errpage = doErrorPage(400);
headers = errpage[0];
data = errpage[1];
} else {
headers = `200 OK
Content-Type: text/html`;
data = `<html>
<head>
<title>
Finished signing up
</title>
<display nooptions noscroll ClearBack
NoScroll
>
</head>
<body noscroll
bgcolor="#171726" text="#D1D3D3" link=#FFEA9C vlink=#FFEA9C
hspace=0 vspace=0 fontsize="large"
>
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td align=middle bgcolor="#5b6c81" border=0 colspan= 3 width="100" height="80">
<img src="${minisrv_config.config.service_logo}" WIDTH="87" HEIGHT="67">
<td colspan= 6 bgcolor="#5b6c81" border=0 width=100% absheight="80" valign=bottom >
<img src="images/head_registration.gif" >
<tr>
<td bgcolor= "#5b6c81" border=0 rowspan=2 width=21 height= 220></td>
<td bgcolor="#171726" border=0 width=9 height=25 align=left valign=top>
<img src="images/L_corner.gif" width=8 height=8>
<td bgcolor="#171726" border=1 colspan=1 width=70 height=25>
<td colspan=6 bgcolor="#171726" border=1 height=25 align=left valign=bottom gradcolor=#262E3D gradangle=90>
<font color=#d1d3d3 size=+1>
<blackface>
You've finished signing up
</blackface></font>
<tr> <td border=0 width=40 bgcolor="#171726" rowspan="2" >
<td absheight=20 width=100 bgcolor="#171726" colspan=6>
</tr>
</table>
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td bgcolor= "#5b6c81" border=0 rowspan=6 abswidth=21 height= 220></td>
<td border=0 abswidth=40 bgcolor="#171726" rowspan="6" >
<form action="FinishRegistration"
>
<td height=230 width= 300 bgcolor="#171726" colspan=5 valign=top align=left>
Thank you for signing up for ${minisrv_config.config.service_name}.
<p>
You will now go
to your <b>Web Home</b> page. You can always
connect to the Internet by choosing
<b>Web Home</b> on your TV Home page.
</font>
<td abswidth=20 bgcolor=#171726 >
</tr>
<tr>
<td valign= bottom height=15 colspan=7 bgcolor=#171726>
<shadow>
<hr size=5 valign=bottom></shadow>
</tr>
<tr>
<td border=2 colspan=4 width=300 height=50 bgcolor=#171726 valign=top align=left>
<font size=-1><i>
</i></font>
<td bgcolor=#171726 height=50 width=150 valign=top align=right>
<font size=-1 color=#e7ce4a>
<shadow>
<input type=submit Value=Continue name="Continue" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=110>
</shadow>
</font>
</form> <td abswidth=13 absheight=50 bgcolor=#171726>
</tr> </table>
</body>
</html>
`;
}
}

View File

@@ -0,0 +1,83 @@
if (request_headers.query.noreg) {
headers = `302 Moved
Connection: Close
wtv-noback-all: wtv-register:
wtv-expire-all: wtv-
wtv-open-isp-disabled: false
wtv-visit: wtv-head-waiter:/login-stage-two?guest_mode=true
Location: wtv-head-waiter:/login-stage-two?guest_mode=true
Content-type: text/html`;
} else if (!request_headers.query.registering) {
var errpage = doErrorPage(400);
headers = errpage[0];
data = errpage[1];
} else {
headers = `200 OK
wtv-noback-all: wtv-
Content-Type: text/html`;
data = `<html>
<head>
<title>
Using ${minisrv_config.config.service_name}
</title>
<display nooptions noscroll NoScroll>
</head>
<body noscroll
bgcolor="#171726" text="#D1D3D3" link=#FFEA9C vlink=#FFEA9C
hspace=0 vspace=0 fontsize="large"
>
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td align=middle bgcolor="#5b6c81" border=0 colspan= 3 width="100" height="80">
<img src="${minisrv_config.config.service_logo}" WIDTH="87" HEIGHT="67">
<td colspan= 6 bgcolor="#5b6c81" border=0 width=100% absheight="80" valign=bottom >
<img src="images/head_registration.gif" >
<tr>
<td bgcolor="#5b6c81" border=0 rowspan=2 width=21 height= 220></td>
<td bgcolor="#171726" border=0 width=9 height=25 align=left valign=top>
<img src="images/L_corner.gif" width=8 height=8>
<td bgcolor="#171726" border=1 colspan=1 width=70 height=25>
<td colspan=6 bgcolor="#171726" border=1 height=25 align=left valign=bottom gradcolor=#262E3D gradangle=90>
<font color=#d1d3d3 size=+1>
<blackface>
Welcome
</blackface></font>
<tr> <td border=0 width=40 bgcolor="#171726" rowspan="2" >
<td absheight=20 width=100 bgcolor="#171726" colspan=6>
</tr>
</table>
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td bgcolor= "#5b6c81" border=0 rowspan=6 abswidth=21 height= 220></td>
<td border=0 abswidth=40 bgcolor="#171726" rowspan="6" >
<form action="ShowTOS"
ENCTYPE="x-www-form-encoded" METHOD="POST">
<input type=hidden name=registering value="true">
<td height=230 width= 300 bgcolor="#171726" colspan=5 valign=top align=left>
Before we can begin collecting information for your account on the ${minisrv_config.config.service_name} Mini Service, you must first agree to the Terms of Service.<br><br>
The next screen will allow you to review, accept, or decline the Terms of Service for the ${minisrv_config.config.service_name} Mini Service.
<td abswidth=20 bgcolor=#171726 >
</tr>
<tr>
<td valign= bottom height=15 colspan=7 bgcolor=#171726>
<shadow>
<hr size=5 valign=bottom></shadow>
</tr>
<tr>
<td border=2 colspan=4 width=300 height=50 bgcolor=#171726 valign=top align=left>
<font size=-1><i>
</i></font>
<td bgcolor=#171726 height=50 width=150 valign=top align=right>
<font size=-1 color=#e7ce4a>
<shadow>
<input type=submit Value=Continue name="Continue" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=110>
</shadow>
</font>
</form> <td abswidth=13 absheight=50 bgcolor=#171726>
</tr> </table>
</body>
</html>
`;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,73 @@
headers = `200 OK
Content-Type: text/html`;
data = `<html>
<head>
<title>
Using ${minisrv_config.config.service_name}
</title>
<display nooptions noscroll NoScroll>
</head>
<body noscroll
bgcolor="#171726" text="#D1D3D3" link=#FFEA9C vlink=#FFEA9C
hspace=0 vspace=0 fontsize="large"
>
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td align=middle bgcolor="#5b6c81" border=0 colspan= 3 width="100" height="80">
<img src="${minisrv_config.config.service_logo}" WIDTH="87" HEIGHT="67">
<td colspan= 6 bgcolor="#5b6c81" border=0 width=100% absheight="80" valign=bottom >
<img src="images/head_registration.gif" >
<tr>
<td bgcolor="#5b6c81" border=0 rowspan=2 width=21 height= 220></td>
<td bgcolor="#171726" border=0 width=9 height=25 align=left valign=top>
<img src="images/L_corner.gif" width=8 height=8>
<td bgcolor="#171726" border=1 colspan=1 width=70 height=25>
<td colspan=6 bgcolor="#171726" border=1 height=25 align=left valign=bottom gradcolor=#262E3D gradangle=90>
<font color=#d1d3d3 size=+1>
<blackface>
Welcome
</blackface></font>
<tr> <td border=0 width=40 bgcolor="#171726" rowspan="2" >
<td absheight=20 width=100 bgcolor="#171726" colspan=6>
</tr>
</table>
<table cellspacing=0 cellpadding=0 border=0 width=560 bgcolor=#171726>
<tr>
<td bgcolor= "#5b6c81" border=0 rowspan=6 abswidth=21 height= 220></td>
<td border=0 abswidth=40 bgcolor="#171726" rowspan="6" >
<form action="ValidateWelcome"
ENCTYPE="x-www-form-encoded" METHOD="POST">
<input type=hidden name=registering value="true">
<td height=230 width= 300 bgcolor="#171726" colspan=5 valign=top align=left>
Welcome to the ${minisrv_config.config.service_name} Mini Service, operated by ${minisrv_config.config.service_owner}
The next screens will lead you through a quick setup process for using this service.<p> Press the "Continue" button below to begin setup.<p>
<td abswidth=20 bgcolor=#171726 >
</tr>
<tr>
<td valign= bottom height=15 colspan=7 bgcolor=#171726>
<shadow>
<hr size=5 valign=bottom></shadow>
</tr>
<tr>
<td border=2 colspan=4 width=100 height=50 bgcolor=#171726 valign=top align=left>
<font size=-1><i>
</i></font>
<td bgcolor=#171726 height=50 width=560 valign=top align=right>
<font size=-1 color=#e7ce4a>
`;
var namerand = Math.floor(Math.random() * 100000);
var nickname = (minisrv_config.config.service_name + '_' + namerand)
var human_name = nickname;
data += `
<shadow>
<input type=button action="ValidateAgreement?registering=true&subscriber_name=${human_name}&subscriber_username=${nickname}" Value="Quick Reg" name="speedyreg" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=130>
<input type=button action="ValidateWelcome" Value="Sign in as Guest" name="noreg" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=170>
<input type=submit Value=Continue name="Continue" borderimage="file://ROM/Borders/ButtonBorder2.bif" usestyle width=110 selected>
</shadow>
</font>
</form> <td abswidth=13 absheight=50 bgcolor=#171726>
</tr> </table>
</body>
</html>
`;

View File

@@ -0,0 +1,35 @@
headers = `200 OK
Connection: Keep-Alive
wtv-expire-all: wtv-
wtv-expire-all: http
Content-Type: text/html`
data = `<html>
<head>
<display hideoptions nostatus showwhencomplete skipback clearback fontsize=medium>
<title>Engaging zefie...</title>
<meta http-equiv=Refresh content="4; url=wtv-register:/register?">
</head>
<body bgcolor="#000000" text="#449944">
<bgsound src="file://ROM/Sounds/Splash.mid">
<center>
<spacer type=block height=88 width=21>
<img src="file://ROM/Images/spacer.gif" height=4><br>
<img src="${minisrv_config.config.service_splash_logo}">
<br><br><br>
<p><br>
<p><br>
<table border>
<tr><td width=150>
Mini service
<tr><td>
zefie minisrv v${minisrv_config.version}`;
if (getGitRevision()) {
data += " (git " + getGitRevision().substring(0, 8) + ")";
}
data += `
<tr><td>&rate;
</table>
</center>
</body>
</html>`;

View File

@@ -1,4 +1,9 @@
headers = `200 OK
wtv-backgroundmusic-load-playlist: wtv-music:/get-playlist
wtv-printer-model: -1,-1
wtv-printer-pen: 0,0,1,0
wtv-printer-setup: 0,0,1,0
wtv-language-header: en-US,en
Content-Type: text/html`
var settings_obj = new Array();

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -0,0 +1,71 @@
headers = `200 OK
Content-Type: text/html`
data = `<html>
<body>
<display nosave nosend>
<title>${minisrv_config.config.service_name} Tricks</title>
<sidebar width=20%>
<img src="wtv-tricks:/images/Favorites_bg.jpg">
</sidebar>
<body bgcolor="#191919" text="#44cc55" link="36d5ff" vlink="36d5ff" vspace=0>
<br>
<br>
<h1>${minisrv_config.config.service_name} Tricks</h1>
<br>
<table>
<tr>
<td colspan=3 height=6>
<tr>
<td><a href="wtv-tricks:/info">Info</a>
<td width = 25>
<td><a href="wtv-cookie:/list">List Cookies</a>
<tr>
<td colspan=3 height=6>
<tr>
<td><a href="wtv-flashrom:/willie">Visit Ultra Willie's!</a>
<td width = 25>
<td><a href="wtv-cookie:/reset">Clear Cookies</a>
<tr>
<td colspan=3 height=6>
<tr>
<td><a href="wtv-tricks:/blastbacklist?return_to=wtv-tricks%3A%2Ftricks">Blast Backlist</a>
<td width = 25>
<td><a href="client:ResetNVAndPowerOff">Blast NVRAM</a>
<tr>
<td colspan=3 height=6>
<tr>
<td><a href="client:showservices">Show Services</a>
<td width = 25>
<td><a href="wtv-tricks:/unregister">Unregister This Box</a>
<tr>
<td colspan=3 height=6>
<tr>
<td><!-- TODO -->
<td width = 25>
<td><!-- TODO -->
<tr>
<td colspan=3 height=6>
<tr>
<td><!-- TODO -->
<td width = 25>
<td><!-- TODO -->
<tr>
<td colspan=3 height=6>
<tr>
<td><!-- TODO -->
<td width = 25>
<td><!-- TODO -->
<tr>
<td colspan=3 height=6>
<tr>
<td><!-- TODO -->
<td width = 25>
<td>
<!-- TODO -->
<td width = 25>
</table>
</body>
</html>
`;

View File

@@ -122,6 +122,7 @@ class WTVClientCapabilities {
capabilities[flag_name] = flag;
}
var i = 0;
// process bitfield and set capabilities
Object.keys(bitfield).forEach(function (k) {
// Convert binary to boolean, 0 to false, 1 to true
@@ -131,7 +132,9 @@ class WTVClientCapabilities {
try {
add(capabilities_table[k][0], bitfield_result);
} catch (ex) {
console.error(" * Unknown configuration bit", k);
add('unknown-capability-' + i, bitfield_result);
i++;
//console.error(" * Unknown configuration bit", k, "with value", bitfield_result);
}
});

View File

@@ -1,19 +1,201 @@
class WTVClientSessionData {
/***********************************\
|* Special Thanks to: *|
|* No one *|
|* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *|
|* There is literally nothing *|
|* special about this class *|
\***********************************/
fs = require('fs');
path = require('path');
ssid = null;
data_store = null;
session_store = null;
login_security = null;
capabilities = null;
session_storage = "";
hide_ssid_in_logs = true;
constructor() {
this.data_store = new Array();
filterSSID(obj) {
if (this.hide_ssid_in_logs === true) {
if (typeof (obj) == "string") {
if (obj.substr(0, 8) == "MSTVSIMU") {
return obj.substr(0, 10) + ('*').repeat(10) + obj.substr(20);
} else if (obj.substr(0, 5) == "1SEGA") {
return obj.substr(0, 6) + ('*').repeat(6) + obj.substr(13);
} else {
return obj.substr(0, 6) + ('*').repeat(9);
}
} else {
if (obj["wtv-client-serial-number"]) {
var ssid = 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") {
obj["wtv-client-serial-number"] = ssid.substr(0, 6) + ('*').repeat(6) + ssid.substr(13);
} else {
obj["wtv-client-serial-number"] = ssid.substr(0, 6) + ('*').repeat(9);
}
}
return obj;
}
} else {
return obj;
}
}
constructor(hide_ssid_in_logs, session_storage_directory) {
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;
this.data_store = new Array();
this.session_store = {};
}
getUTCTime(offset = 0) {
return new Date((new Date).getTime() + offset).toUTCString();
}
countCookies() {
return Object.keys(this.session_store.cookies).length || 0;
}
resetCookies() {
this.session_store.cookies = {};
// webtv likes to have at least one cookie in the list, set a dummy cookie for zefie's site expiring in 1 year.
this.addCookie("wtv.zefie.com", "/", this.getUTCTime(365 * 86400000), "cookie_type=chocolatechip");
}
addCookie(domain, path = null, expires = null, data = null) {
if (!this.checkCookies()) this.resetCookies();
if (!domain) return false;
else if (typeof (domain) == 'object') {
// accept array as first argument
if (domain.domain && domain.path && domain.expires && domain.data) var cookie_data = domain;
else return false;
} else {
if (path && expires && data) {
var cookie_data = new Array();
cookie_data['cookie'] = unescape(data);
cookie_data['expires'] = unescape(expires);
cookie_data['path'] = unescape(path);
cookie_data['domain'] = unescape(domain);
} else {
return false;
}
}
this.session_store.cookies[this.countCookies()] = Object.assign({}, cookie_data);
this.storeSessionData();
return true;
}
getCookie(domain, path) {
if (!this.checkCookies()) this.resetCookies();
var self = this;
var result = false;
Object.keys(this.session_store['cookies']).forEach(function (k) {
if (result != false) return;
if (self.session_store['cookies'][k].domain == domain &&
self.session_store['cookies'][k].path == path) {
var current_epoch_utc = Math.floor(Date.toUTCString().getTime() / 1000);
var cookie_expires_epoch_utc = Math.floor(Date.Parse(self.session_store['cookies'][k].expires).toUTCString().getTime());
if (cookie_expires_epoch_utc <= current_epoch_utc) self.deleteCookie(self.session_store['cookies'][k]);
else result = self.session_store['cookies'][k];
}
});
return result;
}
getCookieString(domain, path) {
var cookie_data = this.getCookie(domain, path);
var outstring = "";
Object.keys(cookie_data).forEach(function (k) {
outstring += k + "=" + escape(cookie_data[k]) + "&";
});
return outstring.substring(0, outstring.length - 1);
}
deleteCookie(domain, path = null) {
var result = false;
if (!this.checkCookies()) {
this.resetCookies();
return true;
}
if (!domain) return false;
else if (typeof (domain) == 'object') {
// accept array as first argument
if (domain.domain && domain.path) {
path = domain.path;
domain = domain.domain;
}
} else if (!path) {
return false;
}
var self = this;
Object.keys(this.session_store['cookies']).forEach(function (k) {
if (self.session_store['cookies'][k].domain == domain && self.session_store['cookies'][k].path == path) {
delete self.session_store['cookies'][k];
self.storeSessionData();
result = true;
}
});
return result;
}
checkCookies() {
if (!this.session_store.cookies) return false;
else if (this.session_store.cookies == []) return false;
return true;
}
listCookies() {
if (!this.checkCookies()) this.resetCookies();
var outstring = "";
var self = this;
Object.keys(this.session_store.cookies).forEach(function (k) {
outstring += self.session_store.cookies[k].domain + "\0" + self.session_store.cookies[k].path + "\0";
});
return outstring;
}
loadSessionData() {
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);
this.session_store = session_data;
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 loading session data for", this.filterSSID(this.ssid), e);
return false;
}
}
saveSessionData() {
if (!this.session_store.registered) {
var temp_store = this.session_store;
this.loadSessionData();
this.session_store = Object.assign(this.session_store, temp_store);
}
try {
var store_data = JSON.stringify(this.session_store);
this.fs.writeFileSync(this.session_storage + this.path.sep + this.ssid + ".json", store_data, "Utf8");
return true;
} catch (e) {
console.error(" # Error saving session data for", this.filterSSID(this.ssid), e);
return false;
}
}
retrieveSessionData() {
// alias
this.loadSessionData();
}
storeSessionData() {
// alias
return this.saveSessionData();
}
hasCap(cap) {
if (this.capabilities) {
@@ -43,6 +225,7 @@ class WTVClientSessionData {
// returns headers to send to client, while storing the new data in our session data.
this.data_store['wtv-user-name'] = nick;
this.data_store['wtv-irc-nick'] = nick;
this.session_store.subscriber_irc_nick = nick;
return "wtv-irc-nick: " + nick + "\nwtv-user-nick: " + nick;
}
@@ -51,6 +234,34 @@ class WTVClientSessionData {
return false;
}
currentConnections() {
if (this.data_store) {
if (this.data_store.sockets) {
return this.data_store.sockets.size;
}
}
return 0;
}
getSessionData(key = null) {
if (typeof (this.data_store) === 'session_store') return null;
else if (key === null) return this.data_store;
else if (this.session_store[key]) return this.session_store[key];
else return null;
}
setSessionData(key, value) {
if (key === null) throw ("ClientSessionData.set(): invalid key provided");
if (typeof (this.session_store) === 'undefined') this.session_store = new Array();
this.session_store[key] = value;
}
deleteSessionData(key) {
if (key === null) throw ("ClientSessionData.delete(): invalid key provided");
delete this.session_store[key];
}
get(key = null) {
if (typeof (this.data_store) === 'undefined') return null;
else if (key === null) return this.data_store;

View File

@@ -51,7 +51,7 @@ class WTVFlashrom {
}
getFlashromData(data, path) {
getFlashromInfo(data, path) {
var flashrom_info = new Array();
var flashrom_magic = "96031889";
var part_header = new Buffer.alloc(32);
@@ -109,15 +109,21 @@ class WTVFlashrom {
async sendToClient(data, request_path, callback) {
var headers = "200 OK\n";
if (this.bf0app_update) headers += "minisrv-use-carriage-return: false\n";
var flashrom_info = this.getFlashromData(data, request_path)
var flashrom_info = this.getFlashromInfo(data, request_path)
if (flashrom_info.is_bootrom) headers += "Content-Type: binary/x-wtv-bootrom"; // maybe?
else headers += "Content-Type: binary/x-wtv-flashblock";
if (flashrom_info.next_rompath != null) headers += "\nwtv-visit: " + flashrom_info.next_rompath;
callback(data, headers);
}
async getFlashromMeta(request_path, callback) {
// read 512 bytes of rom, and send result of getFlashromInfo
// to callback (in data), without headers
this.getFlashRom(request_path, callback, 512);
}
async getFlashRom(request_path, callback, length = 0) {
var flashrom_file_path = null;
var headers, flashrom_file_path = null;
var self = this;
Object.keys(self.service_vaults).forEach(function (g) {
if (flashrom_file_path != null) return;
@@ -151,21 +157,20 @@ class WTVFlashrom {
if (res.statusCode == 200) {
var data = Buffer.from(data_hex, 'hex');
} else if (res.statusCode == 206) {
headers = "";
var data = self.getFlashromData(Buffer.from(data_hex, 'hex'), request_path);
var data = self.getFlashromInfo(Buffer.from(data_hex, 'hex'), request_path);
} else if (res.statusCode == 404) {
var errpage = doErrorPage(404, "The service could not find the requested ROM on zefie's server.")
var headers = errpage[0];
headers = errpage[0];
var data = errpage[1];
} else {
var errpage = doErrorPage(400)
var headers = errpage[0];
headers = errpage[0];
var data = errpage[1];
}
if (res.statusCode == "206") {
if (res.statusCode != 206) {
self.sendToClient(data, request_path, callback);
} else {
callback(data);
callback(data, headers);
}
});
});

View File

@@ -0,0 +1,413 @@
/**
* Pure-JS implementation of WebTV's LZPF compression
*
* This is a port of my Lzpf compression code from my ROMFS Python tool
* Originally reverse engineered from the box
*
* By: Eric MacDonald (eMac)
*/
class WTVLzpf {
// Note: currentlty doesn't offer streaming support but this is good enough to meet perf demands at the scale we're at.
current_length = 0
current_literal = 0
flag_table = new Uint16Array(0x1000)
compressed_data = []
nomatchEncode = [
[0x0000, 0x10], [0x0001, 0x10], [0x0002, 0x10],
[0x0003, 0x10], [0x0004, 0x10], [0x009A, 0x0F],
[0x0005, 0x10], [0x009C, 0x0F], [0x009E, 0x0F],
[0x3400, 0x06], [0x7000, 0x05], [0x00A0, 0x0F],
[0x0006, 0x10], [0x0380, 0x09], [0x0007, 0x10],
[0x0008, 0x10], [0x0009, 0x10], [0x000A, 0x10],
[0x000B, 0x10], [0x000C, 0x10], [0x000D, 0x10],
[0x000E, 0x10], [0x000F, 0x10], [0x00A2, 0x0F],
[0x0010, 0x10], [0x0011, 0x10], [0x0012, 0x10],
[0x0013, 0x10], [0x0014, 0x10], [0x0015, 0x10],
[0x0016, 0x10], [0x0017, 0x10], [0xE000, 0x04],
[0x0200, 0x0A], [0x7800, 0x05], [0x0400, 0x09],
[0x00B0, 0x0E], [0x0018, 0x10], [0x0120, 0x0B],
[0x0480, 0x09], [0x0140, 0x0B], [0x0160, 0x0B],
[0x0240, 0x0A], [0x00B8, 0x0D], [0x1400, 0x07],
[0x1600, 0x07], [0x3800, 0x06], [0x8000, 0x05],
[0x0A00, 0x08], [0x1800, 0x07], [0x0B00, 0x08],
[0x0500, 0x09], [0x0C00, 0x08], [0x0580, 0x09],
[0x0600, 0x09], [0x0680, 0x09], [0x0700, 0x09],
[0x0780, 0x09], [0x0D00, 0x08], [0x0180, 0x0B],
[0x8800, 0x05], [0x3C00, 0x06], [0x9000, 0x05],
[0x0280, 0x0A], [0x00B4, 0x0E], [0x4000, 0x06],
[0x1A00, 0x07], [0x1C00, 0x07], [0x1E00, 0x07],
[0x4400, 0x06], [0x2000, 0x07], [0x2200, 0x07],
[0x2400, 0x07], [0x4800, 0x06], [0x01A0, 0x0B],
[0x02C0, 0x0A], [0x2600, 0x07], [0x0E00, 0x08],
[0x4C00, 0x06], [0x5000, 0x06], [0x2800, 0x07],
[0x00C0, 0x0C], [0x5400, 0x06], [0x2A00, 0x07],
[0x9800, 0x05], [0x0800, 0x09], [0x0880, 0x09],
[0x0F00, 0x08], [0x00D0, 0x0C], [0x0300, 0x0A],
[0x0900, 0x09], [0x0019, 0x10], [0x001A, 0x10],
[0x001B, 0x10], [0x001C, 0x10], [0x1000, 0x08],
[0x001D, 0x10], [0xA000, 0x05], [0x2C00, 0x07],
[0x5800, 0x06], [0x5C00, 0x06], [0xF000, 0x04],
[0x2E00, 0x07], [0x3000, 0x07], [0x6000, 0x06],
[0xA800, 0x05], [0x01C0, 0x0B], [0x1100, 0x08],
[0x6400, 0x06], [0x6800, 0x06], [0xB000, 0x05],
[0xB800, 0x05], [0xC000, 0x05], [0x01E0, 0x0B],
[0xC800, 0x05], [0xD000, 0x05], [0xD800, 0x05],
[0x3200, 0x07], [0x1200, 0x08], [0x6C00, 0x06],
[0x0980, 0x09], [0x1300, 0x08], [0x0340, 0x0A],
[0x00E0, 0x0C], [0x00F0, 0x0C], [0x0100, 0x0C],
[0x0110, 0x0C], [0x001E, 0x10], [0x001F, 0x10],
[0x0020, 0x10], [0x0021, 0x10], [0x0022, 0x10],
[0x0023, 0x10], [0x0024, 0x10], [0x0025, 0x10],
[0x0026, 0x10], [0x0027, 0x10], [0x0028, 0x10],
[0x0029, 0x10], [0x002A, 0x10], [0x002B, 0x10],
[0x002C, 0x10], [0x002D, 0x10], [0x002E, 0x10],
[0x002F, 0x10], [0x00A4, 0x0F], [0x00A6, 0x0F],
[0x00A8, 0x0F], [0x0030, 0x10], [0x0031, 0x10],
[0x0032, 0x10], [0x0033, 0x10], [0x0034, 0x10],
[0x0035, 0x10], [0x0036, 0x10], [0x0037, 0x10],
[0x0038, 0x10], [0x0039, 0x10], [0x003A, 0x10],
[0x003B, 0x10], [0x003C, 0x10], [0x003D, 0x10],
[0x003E, 0x10], [0x003F, 0x10], [0x0040, 0x10],
[0x0041, 0x10], [0x0042, 0x10], [0x0043, 0x10],
[0x0044, 0x10], [0x0045, 0x10], [0x0046, 0x10],
[0x0047, 0x10], [0x0048, 0x10], [0x0049, 0x10],
[0x004A, 0x10], [0x004B, 0x10], [0x004C, 0x10],
[0x004D, 0x10], [0x004E, 0x10], [0x004F, 0x10],
[0x0050, 0x10], [0x0051, 0x10], [0x0052, 0x10],
[0x0053, 0x10], [0x0054, 0x10], [0x0055, 0x10],
[0x0056, 0x10], [0x0057, 0x10], [0x0058, 0x10],
[0x0059, 0x10], [0x005A, 0x10], [0x005B, 0x10],
[0x005C, 0x10], [0x005D, 0x10], [0x005E, 0x10],
[0x005F, 0x10], [0x0060, 0x10], [0x0061, 0x10],
[0x0062, 0x10], [0x00AA, 0x0F], [0x0063, 0x10],
[0x0064, 0x10], [0x0065, 0x10], [0x0066, 0x10],
[0x0067, 0x10], [0x0068, 0x10], [0x0069, 0x10],
[0x006A, 0x10], [0x006B, 0x10], [0x006C, 0x10],
[0x006D, 0x10], [0x006E, 0x10], [0x006F, 0x10],
[0x0070, 0x10], [0x0071, 0x10], [0x0072, 0x10],
[0x0073, 0x10], [0x0074, 0x10], [0x0075, 0x10],
[0x0076, 0x10], [0x0077, 0x10], [0x0078, 0x10],
[0x0079, 0x10], [0x007A, 0x10], [0x007B, 0x10],
[0x007C, 0x10], [0x007D, 0x10], [0x007E, 0x10],
[0x007F, 0x10], [0x0080, 0x10], [0x0081, 0x10],
[0x0082, 0x10], [0x0083, 0x10], [0x0084, 0x10],
[0x0085, 0x10], [0x0086, 0x10], [0x0087, 0x10],
[0x0088, 0x10], [0x0089, 0x10], [0x008A, 0x10],
[0x008B, 0x10], [0x008C, 0x10], [0x008D, 0x10],
[0x00AC, 0x0F], [0x008E, 0x10], [0x008F, 0x10],
[0x0090, 0x10], [0x0091, 0x10], [0x0092, 0x10],
[0x0093, 0x10], [0x00AE, 0x0F], [0x0094, 0x10],
[0x0095, 0x10], [0x0096, 0x10], [0x0097, 0x10],
[0x0098, 0x10], [0x0099, 0x10]
];
matchEncode = [
[0x80000000, 0x01], [0x80000000, 0x03],
[0xA0000000, 0x03], [0xC0000000, 0x03],
[0xE0000000, 0x06], [0xE4000000, 0x06],
[0xE8000000, 0x06], [0xEC000000, 0x06],
[0xF0000000, 0x06], [0xF4000000, 0x06],
[0xF8000000, 0x06], [0xFC000000, 0x0B],
[0xFC200000, 0x0B], [0xFC400000, 0x0B],
[0xFC600000, 0x0B], [0xFC800000, 0x0B],
[0xFCA00000, 0x0B], [0xFCC00000, 0x0B],
[0xFCE00000, 0x0B], [0xFD000000, 0x0B],
[0xFD200000, 0x0B], [0xFD400000, 0x0B],
[0xFD600000, 0x0B], [0xFD800000, 0x0B],
[0xFDA00000, 0x0B], [0xFDC00000, 0x0B],
[0xFDE00000, 0x0B], [0xFE000000, 0x0B],
[0xFE200000, 0x0B], [0xFE400000, 0x0B],
[0xFE600000, 0x0B], [0xFE800000, 0x0B],
[0xFEA00000, 0x0B], [0xFEC00000, 0x0B],
[0xFEE00000, 0x0B], [0xFF000000, 0x0B],
[0xFF200000, 0x0B], [0xFF400000, 0x0B],
[0xFF600000, 0x0B], [0xFF800000, 0x0B],
[0xFFA00000, 0x0B], [0xFFC00000, 0x0B],
[0xFFE00000, 0x13], [0xFFE02000, 0x13],
[0xFFE04000, 0x13], [0xFFE06000, 0x13],
[0xFFE08000, 0x13], [0xFFE0A000, 0x13],
[0xFFE0C000, 0x13], [0xFFE0E000, 0x13],
[0xFFE10000, 0x13], [0xFFE12000, 0x13],
[0xFFE14000, 0x13], [0xFFE16000, 0x13],
[0xFFE18000, 0x13], [0xFFE1A000, 0x13],
[0xFFE1C000, 0x13], [0xFFE1E000, 0x13],
[0xFFE20000, 0x13], [0xFFE22000, 0x13],
[0xFFE24000, 0x13], [0xFFE26000, 0x13],
[0xFFE28000, 0x13], [0xFFE2A000, 0x13],
[0xFFE2C000, 0x13], [0xFFE2E000, 0x13],
[0xFFE30000, 0x13], [0xFFE32000, 0x13],
[0xFFE34000, 0x13], [0xFFE36000, 0x13],
[0xFFE38000, 0x13], [0xFFE3A000, 0x13],
[0xFFE3C000, 0x13], [0xFFE3E000, 0x13],
[0xFFE40000, 0x13], [0xFFE42000, 0x13],
[0xFFE44000, 0x13], [0xFFE46000, 0x13],
[0xFFE48000, 0x13], [0xFFE4A000, 0x13],
[0xFFE4C000, 0x13], [0xFFE4E000, 0x13],
[0xFFE50000, 0x13], [0xFFE52000, 0x13],
[0xFFE54000, 0x13], [0xFFE56000, 0x13],
[0xFFE58000, 0x13], [0xFFE5A000, 0x13],
[0xFFE5C000, 0x13], [0xFFE5E000, 0x13],
[0xFFE60000, 0x13], [0xFFE62000, 0x13],
[0xFFE64000, 0x13], [0xFFE66000, 0x13],
[0xFFE68000, 0x13], [0xFFE6A000, 0x13],
[0xFFE6C000, 0x13], [0xFFE6E000, 0x13],
[0xFFE70000, 0x13], [0xFFE72000, 0x13],
[0xFFE74000, 0x13], [0xFFE76000, 0x13],
[0xFFE78000, 0x13], [0xFFE7A000, 0x13],
[0xFFE7C000, 0x13], [0xFFE7E000, 0x13],
[0xFFE80000, 0x13], [0xFFE82000, 0x13],
[0xFFE84000, 0x13], [0xFFE86000, 0x13],
[0xFFE88000, 0x13], [0xFFE8A000, 0x13],
[0xFFE8C000, 0x13], [0xFFE8E000, 0x13],
[0xFFE90000, 0x13], [0xFFE92000, 0x13],
[0xFFE94000, 0x13], [0xFFE96000, 0x13],
[0xFFE98000, 0x13], [0xFFE9A000, 0x13],
[0xFFE9C000, 0x13], [0xFFE9E000, 0x13],
[0xFFEA0000, 0x13], [0xFFEA2000, 0x13],
[0xFFEA4000, 0x13], [0xFFEA6000, 0x13],
[0xFFEA8000, 0x13], [0xFFEAA000, 0x13],
[0xFFEAC000, 0x13], [0xFFEAE000, 0x13],
[0xFFEB0000, 0x13], [0xFFEB2000, 0x13],
[0xFFEB4000, 0x13], [0xFFEB6000, 0x13],
[0xFFEB8000, 0x13], [0xFFEBA000, 0x13],
[0xFFEBC000, 0x13], [0xFFEBE000, 0x13],
[0xFFEC0000, 0x13], [0xFFEC2000, 0x13],
[0xFFEC4000, 0x13], [0xFFEC6000, 0x13],
[0xFFEC8000, 0x13], [0xFFECA000, 0x13],
[0xFFECC000, 0x13], [0xFFECE000, 0x13],
[0xFFED0000, 0x13], [0xFFED2000, 0x13],
[0xFFED4000, 0x13], [0xFFED6000, 0x13],
[0xFFED8000, 0x13], [0xFFEDA000, 0x13],
[0xFFEDC000, 0x13], [0xFFEDE000, 0x13],
[0xFFEE0000, 0x13], [0xFFEE2000, 0x13],
[0xFFEE4000, 0x13], [0xFFEE6000, 0x13],
[0xFFEE8000, 0x13], [0xFFEEA000, 0x13],
[0xFFEEC000, 0x13], [0xFFEEE000, 0x13],
[0xFFEF0000, 0x13], [0xFFEF2000, 0x13],
[0xFFEF4000, 0x13], [0xFFEF6000, 0x13],
[0xFFEF8000, 0x13], [0xFFEFA000, 0x13],
[0xFFEFC000, 0x13], [0xFFEFE000, 0x13],
[0xFFF00000, 0x13], [0xFFF02000, 0x13],
[0xFFF04000, 0x13], [0xFFF06000, 0x13],
[0xFFF08000, 0x13], [0xFFF0A000, 0x13],
[0xFFF0C000, 0x13], [0xFFF0E000, 0x13],
[0xFFF10000, 0x13], [0xFFF12000, 0x13],
[0xFFF14000, 0x13], [0xFFF16000, 0x13],
[0xFFF18000, 0x13], [0xFFF1A000, 0x13],
[0xFFF1C000, 0x13], [0xFFF1E000, 0x13],
[0xFFF20000, 0x13], [0xFFF22000, 0x13],
[0xFFF24000, 0x13], [0xFFF26000, 0x13],
[0xFFF28000, 0x13], [0xFFF2A000, 0x13],
[0xFFF2C000, 0x13], [0xFFF2E000, 0x13],
[0xFFF30000, 0x13], [0xFFF32000, 0x13],
[0xFFF34000, 0x13], [0xFFF36000, 0x13],
[0xFFF38000, 0x13], [0xFFF3A000, 0x13],
[0xFFF3C000, 0x13], [0xFFF3E000, 0x13],
[0xFFF40000, 0x13], [0xFFF42000, 0x13],
[0xFFF44000, 0x13], [0xFFF46000, 0x13],
[0xFFF48000, 0x13], [0xFFF4A000, 0x13],
[0xFFF4C000, 0x13], [0xFFF4E000, 0x13],
[0xFFF50000, 0x13], [0xFFF52000, 0x13],
[0xFFF54000, 0x13], [0xFFF56000, 0x13],
[0xFFF58000, 0x13], [0xFFF5A000, 0x13],
[0xFFF5C000, 0x13], [0xFFF5E000, 0x13],
[0xFFF60000, 0x13], [0xFFF62000, 0x13],
[0xFFF64000, 0x13], [0xFFF66000, 0x13],
[0xFFF68000, 0x13], [0xFFF6A000, 0x13],
[0xFFF6C000, 0x13], [0xFFF6E000, 0x13],
[0xFFF70000, 0x13], [0xFFF72000, 0x13],
[0xFFF74000, 0x13], [0xFFF76000, 0x13],
[0xFFF78000, 0x13], [0xFFF7A000, 0x13],
[0xFFF7C000, 0x13], [0xFFF7E000, 0x13],
[0xFFF80000, 0x13], [0xFFF82000, 0x13],
[0xFFF84000, 0x13], [0xFFF86000, 0x13],
[0xFFF88000, 0x13], [0xFFF8A000, 0x13],
[0xFFF8C000, 0x13], [0xFFF8E000, 0x13],
[0xFFF90000, 0x13], [0xFFF92000, 0x13],
[0xFFF94000, 0x13], [0xFFF96000, 0x13],
[0xFFF98000, 0x13], [0xFFF9A000, 0x13],
[0xFFF9C000, 0x13], [0xFFF9E000, 0x13],
[0xFFFA0000, 0x13], [0xFFFA2000, 0x13],
[0xFFFA4000, 0x13], [0xFFFA6000, 0x13],
[0xFFFA8000, 0x13], [0xFFFAA000, 0x13],
[0xFFFAC000, 0x13], [0xFFFAE000, 0x13],
[0xFFFB0000, 0x13], [0xFFFB2000, 0x13],
[0xFFFB4000, 0x13], [0xFFFB6000, 0x13],
[0xFFFB8000, 0x13], [0xFFFBA000, 0x13],
[0xFFFBC000, 0x13], [0xFFFBE000, 0x13],
[0xFFFC0000, 0x13], [0xFFFC2000, 0x13],
[0xFFFC4000, 0x13], [0xFFFC6000, 0x13],
[0xFFFC8000, 0x13], [0xFFFCA000, 0x13],
[0xFFFCC000, 0x13], [0xFFFCE000, 0x13],
[0xFFFD0000, 0x13], [0xFFFD2000, 0x13],
[0xFFFD4000, 0x13], [0xFFFD6000, 0x13],
[0xFFFD8000, 0x13], [0xFFFDA000, 0x13],
[0xFFFDC000, 0x13], [0xFFFDE000, 0x13],
[0xFFFE0000, 0x13], [0xFFFE2000, 0x13],
[0xFFFE4000, 0x13], [0xFFFE6000, 0x13],
[0xFFFE8000, 0x13], [0xFFFEA000, 0x13],
[0xFFFEC000, 0x13], [0xFFFEE000, 0x13],
[0xFFFF0000, 0x13], [0xFFFF2000, 0x13],
[0xFFFF4000, 0x13], [0xFFFF6000, 0x13],
[0xFFFF8000, 0x13], [0xFFFFA000, 0x13],
[0xFFFFC000, 0x13], [0xFFFFE000, 0x13],
[0x00000000, 0x00], [0x00000000, 0x00]
];
/**
* Initialize the Lzpf class.
*
* @returns {undefined}
*/
constructor() {
this.clear();
}
/**
* Sets starting values for the compression algorithm.
*
* @returns {undefined}
*/
clear() {
this.current_length = 0;
this.current_literal = 0;
this.flag_table.fill(0xFFFF, 0, 0x1000);
this.compressed_data = [];
}
/**
* Encodes a literal onto the compressed byte array.
*
* @param code_length {Number} bit length of the code
* @param code {Number} code to be encoded
*
* @returns {undefined}
*/
EncodeLiteral(code_length, code) {
// Using >>> to stick with unsigned integers without making a mess with casting.
this.current_literal |= code >>> (this.current_length & 0x1F);
this.current_length += code_length;
while (this.current_length > 7) {
//console.log("add", this.current_literal >>> 0, code >>> 0, byte, type)
this.compressed_data.push((this.current_literal >>> 0x18) & 0xFF);
this.current_length -= 8;
this.current_literal = (this.current_literal << 8) & 0xFFFFFFFF;
}
}
/**
* Compress data using WebTV's Lzpf compression algorithm and adds the footer to the end.
*
* @param uncompressed_data {String} data to compress
*
* @returns {Buffer} Lzpf compression data
*/
Compress(uncompressed_data) {
this.clear();
if (uncompressed_data.words) {
uncompressed_data = new Buffer.from(this.wordArrayToUint8Array(uncompressed_data));
} else {
uncompressed_data = new Buffer.from(uncompressed_data);
}
var uncompressed_len = uncompressed_data.length;
var i = 0;
var sum = 0;
var working_data = 0;
var flag = 0xFFFF;
var flags_index = 0;
var match_index = 0;
var type_index = 0;
while(i < uncompressed_len) {
var code_length = -1;
var code = -1;
var byte = uncompressed_data.readUInt8(i);
if(match_index > 0) {
if (byte != uncompressed_data.readUInt8(flag) || match_index > 0x0127) {
code_length = this.matchEncode[match_index][1];
code = this.matchEncode[match_index][0];
match_index = 0;
type_index = 3;
} else {
match_index++;
flag++;
sum = (sum + byte) & 0xFFFF;
working_data = ((working_data * 0x0100) + byte) & 0xFFFFFFFF;
i++;
}
} else {
flag = 0xFFFF;
if (i >= 3) {
flags_index = (working_data >>> 0x0B ^ working_data) & 0x0FFF;
flag = this.flag_table[flags_index];
this.flag_table[flags_index] = i;
} else {
type_index++;
}
if (flag == 0xFFFF) {
code_length = this.nomatchEncode[byte][1];
code = this.nomatchEncode[byte][0] << 0x10;
} else if (byte == uncompressed_data.readUInt8(flag)) {
match_index = 1;
flag++;
type_index = 4;
} else {
code_length = this.nomatchEncode[byte][1] + 1;
code = this.nomatchEncode[byte][0] << 0x0F;
}
sum = (sum + byte) & 0xFFFF;
working_data = ((working_data * 0x0100) + byte) & 0xFFFFFFFF;
i++;
}
if (code_length > 0) {
this.EncodeLiteral(code_length, code);
}
}
// Finish up. This would normally be in an Lzpf_Finish method.
if(type_index == 2) {
this.EncodeLiteral(0x10, 0x00990000);
} else if(type_index >= 3) {
if(type_index == 4) {
code_length = this.matchEncode[match_index][1];
code = this.matchEncode[match_index][0];
this.EncodeLiteral(code_length, code);
}
flags_index = (working_data >>> 0x0B ^ working_data) & 0x0FFF;
if (flags_index == 0xFFFF) {
this.EncodeLiteral(0x10, 0x00990000);
} else {
this.EncodeLiteral(0x11, 0x004c8000);
}
}
// Below is just metadata. The compressed block is complete.
// Encode checksum
this.EncodeLiteral(0x08, (sum << 0x10) & 0xFFFFFFFF);
this.EncodeLiteral(0x08, (sum << 0x18) & 0xFFFFFFFF);
// End
this.compressed_data.push(this.current_literal >>> 0x18);
this.compressed_data.push(0x20);
return new Buffer.from(this.compressed_data);
}
}
module.exports = WTVLzpf;

View File

@@ -0,0 +1,47 @@
class WTVRegister {
fs = require('fs');
path = require('path');
service_owner = "a minisrv user";
session_store_dir = null;
constructor(service_owner, session_store_dir = null) {
this.service_owner = service_owner;
if (session_store_dir) this.session_store_dir = session_store_dir
}
getServiceOperator(first_letter_lower = false) {
if (this.service_owner == "a minisrv user") {
if (first_letter_lower) return "the operator of this service";
else return "The operator of this service";
} else {
return this.service_owner;
}
}
checkUsernameSanity(username) {
var check1 = /^([A-Za-z0-9\-\_]{5,16})$/.test(username);
var check2 = /^[A-Za-z]/.test(username);
return (check1 && check2);
}
checkUsernameAvailable(username, ssid_sessions) {
var username_match = false;
this.fs.readdirSync(this.session_store_dir).forEach(file => {
if (username_match) return;
try {
var temp_session_data_file = this.fs.readFileSync(this.session_store_dir + this.path.sep + file, 'Utf8');
var temp_session_data = JSON.parse(temp_session_data_file);
if (temp_session_data.subscriber_username == username) username_match = true;
} catch (e) {
console.error(" # Error parsing Session Data JSON", file, e);
username_match = true;
}
});
return !username_match;
}
}
module.exports = WTVRegister;

View File

@@ -11,6 +11,7 @@ const mime = require('mime-types');
const { crc16 } = require('easy-crc');
const process = require('process');
var WTVSec = require('./WTVSec.js');
var WTVLzpf = require('./WTVLzpf.js');
var WTVClientCapabilities = require('./WTVClientCapabilities.js');
var WTVClientSessionData = require('./WTVClientSessionData.js');
@@ -45,12 +46,18 @@ if (!String.prototype.reverse) {
}
}
function getServiceString(service, overrides = null) {
function getServiceString(service, overrides = {}) {
// used externally by service scripts
if (service === "all") {
var out = "";
Object.keys(minisrv_config.services).forEach(function (k) {
if (overrides.exceptions) {
Object.keys(overrides.exceptions).forEach(function (j) {
if (k != overrides.exceptions[j]) out += minisrv_config.services[k].toString(overrides) + "\n";
});
} else {
out += minisrv_config.services[k].toString(overrides) + "\n";
}
});
return out;
} else {
@@ -263,6 +270,30 @@ async function processURL(socket, request_headers) {
shortURL = unescape(request_headers.request_url);
}
if (request_headers.post_data) {
if (headersAreStandard(request_headers.post_data.toString(CryptoJS.enc.Utf8))) {
if (request_headers.post_data.toString(CryptoJS.enc.Utf8).indexOf('=')) {
if (request_headers.post_data.toString(CryptoJS.enc.Utf8).indexOf('&')) {
var qraw = request_headers.post_data.toString(CryptoJS.enc.Utf8).split('&');
if (qraw.length > 0) {
for (let i = 0; i < qraw.length; i++) {
var k = qraw[i].split("=")[0];
if (k) {
request_headers.query[k] = qraw[i].split("=")[1];
}
}
}
} else {
var qraw = request_headers.post_data.toString(CryptoJS.enc.Utf8);
var k = qraw[i].split("=")[0];
if (k) {
request_headers.query[k] = qraw[i].split("=")[1];
}
}
}
}
}
if (shortURL.indexOf(':/') >= 0 && shortURL.indexOf('://') < 0) {
var ssid = socket.ssid;
if (ssid == null) {
@@ -368,16 +399,21 @@ async function doHTTPProxy(socket, request_headers) {
var data_hex = Buffer.concat(data).toString('hex');
console.log(` * Proxy Request ${request_type.toUpperCase()} ${res.statusCode} for ${request_headers.request}`)
var headers = new Array();
headers.http_response = res.statusCode + " " + res.statusMessage;
headers["wtv-connection-close"] = false;
if (res.headers.server) headers.Server = res.headers.server;
if (res.headers.connection) headers.Connection = res.headers.connection == "close" ? "Keep-Alive" : "Close";
if (res.headers.date) headers.Date = res.headers.date;
if (res.headers["content-type"]) headers["Content-type"] = res.headers["content-type"];
if (res.headers.cookie) headers.Cookie = res.headers.cookie;
if (res.headers.vary) headers.Vary = res.headers.vary;
if (res.headers.location) headers.Location = res.headers.location;
res.headers.http_response = res.statusCode + " " + res.statusMessage;
res.headers["wtv-connection-close"] = false;
// header pass-through whitelist, case insensitive comparsion to server, however, you should
// specify the header case as you intend for the client
var headers = stripHeaders(res.headers, [
'Server',
'Connection',
'Date',
'Content-Type',
'Content-length',
'Cookie',
'Location',
'Accept-Ranges',
'Last-Modified'
]);
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);
sendToClient(socket, headers, Buffer.from(data_hex,'hex'));
@@ -404,6 +440,30 @@ async function doHTTPProxy(socket, request_headers) {
}
}
function stripHeaders(headers_obj, whitelist) {
var whitelisted_headers = new Array();
var out_headers = new Array();
out_headers.http_response = headers_obj.http_response;
out_headers['wtv-connection-close'] = headers_obj['wtv-connection-close'];
// compare regardless of case
Object.keys(whitelist).forEach(function (k) {
Object.keys(headers_obj).forEach(function (j) {
if (whitelist[k].toLowerCase() == j.toLowerCase()) whitelisted_headers[j.toLowerCase()] = [whitelist[k], j, headers_obj[j]];
});
});
// restore original header order
Object.keys(headers_obj).forEach(function (k) {
if (whitelisted_headers[k.toLowerCase()]) {
if (whitelisted_headers[k.toLowerCase()][1] == k) out_headers[whitelisted_headers[k.toLowerCase()][0]] = whitelisted_headers[k.toLowerCase()][2];
}
});
// return
return out_headers;
}
function headerStringToObj(headers, response = false) {
var inc_headers = 0;
var headers_obj = new Array();
@@ -435,8 +495,10 @@ function headerStringToObj(headers, response = false) {
return headers_obj;
}
async function sendToClient(socket, headers_obj, data) {
async function sendToClient(socket, headers_obj, data, compress_data = false) {
var headers = "";
var wni_style_content_length = false;
var compress_data = false;
if (typeof (data) === 'undefined') data = '';
if (typeof (headers_obj) === 'string') {
// string to header object
@@ -447,7 +509,7 @@ async function sendToClient(socket, headers_obj, data) {
return;
}
var wtv_connection_close = headers_obj["wtv-connection-close"];
if (typeof(headers_obj["wtv-connection-close"]) != 'undefined') delete headers_obj["wtv-connection-close"];
if (typeof (headers_obj["wtv-connection-close"]) != 'undefined') delete headers_obj["wtv-connection-close"];
// add Connection header if missing, default to Keep-Alive
if (!headers_obj.Connection) {
@@ -455,39 +517,86 @@ async function sendToClient(socket, headers_obj, data) {
headers_obj = moveObjectElement('Connection', 'http_response', headers_obj);
}
if (headers_obj['minisrv-already-compressed'] && wni_style_content_length) {
content_length = headers_obj["Content-length"];
} else {
var content_length = 0;
if (typeof data.length !== 'undefined') {
content_length = data.length;
} else if (typeof data.byteLength !== 'undefined') {
content_length = data.byteLength;
}
}
// fix captialization of Content-Type header. May be unnecessary.
if (headers_obj["Content-type"]) {
headers_obj["Content-Type"] = headers_obj["Content-type"];
delete headers_obj["Content-type"];
}
/*
// check if client reports it supports compressed data
if (ssid_sessions[socket.ssid].capabilities) {
if (ssid_sessions[socket.ssid].capabilities['client-can-receive-compressed-data']) {
// if the client reports it supports compression, check the Content-Type
// of the file we are sending to see if its worth compressing
compress_data = shouldWeCompress(headers_obj["Content-Type"]);
}
}
*/
// compress if needed, and if not already compressed
if (compress_data && content_length > 0 && !headers_obj['minisrv-already-compressed']) {
if (zdebug) console.log(" # Uncompressed data length:", content_length);
headers_obj["wtv-lzpf"] = 0;
var wtvcomp = new WTVLzpf();
// we expect the compressed data to be smaller or at most equal to the source size
// so we set our initial buffer size to the source size
var compressed_data = new Buffer.alloc(content_length);
wtvcomp.on('data', (data, length, offset, complete) => {
// put data received into buffer
data.copy(compressed_data, offset, 0, length);
if (complete !== false) {
if (zdebug) console.log(" # Compressed data length:", complete);
// now that we have all of the compressed data, copy it to a new buffer
// of the correct length, and clean up the original buffer.
data = new Buffer.alloc(complete);
compressed_data.copy(data, 0, 0, compressed_data.byteLength);
compressed_data, wtvcomp = null;
// internal header to tell ourselves to not compress again
headers_obj['minisrv-already-compressed'] = true;
if (wni_style_content_length) headers_obj["Content-length"] = content_length;
sendToClient(socket, headers_obj, data);
}
});
wtvcomp.Compress(data);
return;
}
// clean up internal header for compression
if (headers_obj['minisrv-already-compressed']) delete headers_obj['minisrv-already-compressed'];
// encrypt if needed
if (socket_sessions[socket.id].secure == true) {
var clen = null;
if (typeof data.length !== 'undefined') {
clen = data.length;
} else if (typeof data.byteLength !== 'undefined') {
clen = data.byteLength;
}
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;
}
}
// fix captialization
if (headers_obj["Content-length"]) {
delete headers_obj["Content-length"];
}
if (headers_obj["Content-type"]) {
headers_obj["Content-Type"] = headers_obj["Content-type"];
delete headers_obj["Content-type"];
}
// calculate content length
if (typeof data.length !== 'undefined') {
headers_obj["Content-length"] = data.length;
} else if (typeof data.byteLength !== 'undefined') {
headers_obj["Content-length"] = data.byteLength;
}
// make sure we are using our Content-length and not one set in a script.
if (headers_obj["Content-Length"]) delete headers_obj["Content-Length"];
if (headers_obj["Content-length"]) delete headers_obj["Content-length"];
// On the WNI server this is the length before compression but we're using the length after compression.
// It matches the HTTP spec anyway so leaving.
headers_obj["Content-length"] = content_length;
if (ssid_sessions[socket.ssid]) {
if (ssid_sessions[socket.ssid].data_store.wtvsec_login) {
@@ -501,13 +610,15 @@ async function sendToClient(socket, headers_obj, data) {
}
}
// internal header to determine EOL type. bf0app upgrader does not like \r, while the rest of the WebTV world does.
// set header 'minisrv-use-carriage-return' to true to disable \r for this specific transfer.
var end_of_line = "\n";
if (!headers_obj['minisrv-use-carriage-return'] || headers_obj['minisrv-use-carriage-return'] != "false") end_of_line = "\r\n";
if (headers_obj['minisrv-use-carriage-return']) delete headers_obj['minisrv-use-carriage-return'];
if (end_of_line == "\n" && zdebug) console.log(" * Script requested to send headers without carriage return (bf0app hack)");
// header object to string
// convert header object back to string
if (zshowheaders) console.log(" * Outgoing headers on socket ID", socket.id, (await filterSSID(headers_obj)));
Object.keys(headers_obj).forEach(function (k) {
if (k == "http_response") {
@@ -552,12 +663,25 @@ 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);
@@ -594,7 +718,12 @@ function headersAreStandard(string, verbose = false) {
// in unencrypted headers, and returns true only if every character in the string matches
// the regex. Once we know the string is binary, we can better process it with the
// raw base64 or hex data in processRequest() below.
return /^([A-Za-z0-9\+\/\=\-\.\,\ \"\;\:\?\&\r\n\(\)\%\<\>\_\~]{8,})$/.test(string);
return /^([A-Za-z0-9\+\/\=\-\.\,\ \"\;\:\?\&\r\n\(\)\%\<\>\_\~\*\@\#\\]{8,})$/.test(string);
}
function filterSSID(ssid) {
var WTVCSD = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs);
return WTVCSD.filterSSID(ssid);
}
async function processRequest(socket, data_hex, skipSecure = false, encryptedRequest = false) {
@@ -666,9 +795,10 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
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();
ssid_sessions[socket.ssid] = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs);
}
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);
}
@@ -755,7 +885,7 @@ 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();
ssid_sessions[socket.ssid] = new WTVClientSessionData(minisrv_config.config.hide_ssid_in_logs);
}
if (!ssid_sessions[socket.ssid].capabilities) ssid_sessions[socket.ssid].capabilities = new WTVClientCapabilities(headers["wtv-capability-flags"]);
}
@@ -1074,14 +1204,22 @@ async function cleanupSocket(socket) {
if (socket.ssid) {
ssid_sessions[socket.ssid].data_store.sockets.delete(socket);
if (ssid_sessions[socket.ssid].data_store.sockets.size === 0 && ssid_sessions[socket.ssid].data_store.wtvsec_login) {
// if last socket for SSID disconnected, destroy login session
if (!zquiet) console.log(" * Last socket from WebTV SSID", filterSSID(socket.ssid),"disconnected, cleaning up primary WTVSec instance for this SSID");
ssid_sessions[socket.ssid].delete("wtvsec_login");
if (ssid_sessions[socket.ssid].currentConnections() === 0) {
// clean up possible minibrowser session data
if (ssid_sessions[socket.ssid].get("wtv-needs-upgrade")) ssid_sessions[socket.ssid].delete("wtv-needs-upgrade");
if (ssid_sessions[socket.ssid].get("wtv-used-8675309")) ssid_sessions[socket.ssid].delete("wtv-used-8675309");
// 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);
}
}
}
socket.end();
@@ -1182,7 +1320,7 @@ if (git_commit) {
console.log("**** Welcome to " + z_title + " ****");
console.log(" *** Reading global configuration...");
try {
var minisrv_config = JSON.parse(fs.readFileSync(__dirname + "/config.json"));
var minisrv_config = JSON.parse(fs.readFileSync(__dirname + path.sep + "config.json"));
if (git_commit) {
minisrv_config.config.git_commit = git_commit;
delete this.git_commit;
@@ -1190,13 +1328,12 @@ try {
} catch (e) {
throw ("ERROR: Could not read config.json", e);
}
var service_vaults = new Array();
try {
if (fs.lstatSync(__dirname + "/user_config.json")) {
console.log(" *** Reading user configuration...");
try {
var minisrv_user_config = JSON.parse(fs.readFileSync(__dirname + "/user_config.json"));
var minisrv_user_config = JSON.parse(fs.readFileSync(__dirname + path.sep + "user_config.json"));
} catch (e) {
console.error("ERROR: Could not read user_config.json", e);
var throw_me = true;
@@ -1217,6 +1354,7 @@ if (throw_me) {
throw ("An error has occured while reading the configuration files.");
}
var service_vaults = new Array();
if (minisrv_config.config.ServiceVaults) {
Object.keys(minisrv_config.config.ServiceVaults).forEach(function (k) {
var service_vault = returnAbsolutePath(minisrv_config.config.ServiceVaults[k]);
@@ -1227,6 +1365,13 @@ if (minisrv_config.config.ServiceVaults) {
throw ("ERROR: No Service Vaults defined!");
}
if (minisrv_config.config.SessionStore) {
var SessionStore = returnAbsolutePath(minisrv_config.config.SessionStore);
console.log(" * Configured Session Storage at", SessionStore);
} else {
throw ("ERROR: No Session Storage Directory (SessionStore) defined!");
}
var service_ip = minisrv_config.config.service_ip;
Object.keys(minisrv_config.services).forEach(function (k) {
if (minisrv_config.services[k].disabled) return;
@@ -1244,7 +1389,7 @@ Object.keys(minisrv_config.services).forEach(function (k) {
if (overrides != null) {
if (typeof (overrides) == 'object') {
Object.keys(overrides).forEach(function (k) {
self[k] = overrides[k];
if (k != "exceptions") self[k] = overrides[k];
});
}
}

View File

@@ -5,6 +5,8 @@
"UserServiceVault",
"ServiceVault"
],
"SessionStore": "SessionStore",
"service_owner": "a minisrv user",
"service_name": "WebTV",
"service_logo": "WebTVLogoJewel.gif",
"service_splash_logo": "file://ROM/images/SplashLogo1.gif",
@@ -14,23 +16,20 @@
"error_log_file": "errors.log"
},
"services": {
"wtv-1800": {
"port": 1615,
"connections": 1,
"flags": "0x00000004",
"send_tellyscripts": false
"wtv-head-waiter": {
"port": 1601,
"connections": 1
},
"wtv-tricks": {
"port": 1602,
"flags": "0x00000004"
},
"wtv-star": {
"port": 1603,
"flags": "0x00000007"
},
"wtv-head-waiter": {
"port": 1601,
"connections": 1
},
"wtv-update": {
"port": 1635,
"connections": 3
"wtv-register": {
"port": 1607
},
"wtv-log": {
"port": 1609,
@@ -40,9 +39,11 @@
"wtv-home": {
"port": 1612
},
"wtv-tricks": {
"port": 1602,
"flags": "0x00000004"
"wtv-1800": {
"port": 1615,
"connections": 1,
"flags": "0x00000004",
"send_tellyscripts": false
},
"wtv-flashrom": {
"port": 1618,
@@ -50,22 +51,22 @@
"use_zefie_server": true,
"bf0app_default_rom": "content/artemis-webtv-000/build7181/daily-nondebug/bf0app-part000.rom"
},
"wtv-music": {
"port": 1656,
"connections": 3
},
"wtv-setup": {
"port": 1613,
"flags": "0x00000010",
"connections": 3
},
"wtv-cookie": {
"port": 1619,
"connections": 1
},
"wtv-chat": {
"port": 1630,
"connections": 3
},
"wtv-cookie": {
"port": 1619,
"connections": 1
"wtv-update": {
"port": 1635,
"connections": 3
},
"http": {
"port": 1650,
@@ -84,6 +85,10 @@
"external_proxy_host": "127.0.0.1",
"external_proxy_port": 1080,
"flags": "0x00000001"
},
"wtv-music": {
"port": 1656,
"connections": 3
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "zefie_wtvp_minisrv",
"version": "0.9.4",
"version": "0.9.11",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "zefie_wtvp_minisrv",
"version": "0.9.11",
"version": "0.9.12",
"description": "WebTV Service (WTVP) Emulation Server",
"main": "app.js",
"homepage": "https://github.com/zefie/zefie_wtvp_minisrv",

View File

@@ -40,6 +40,13 @@
<Content Include="ServiceVault\wtv-chat\images\top_corner_dark.jpg" />
<Content Include="ServiceVault\wtv-chat\images\widget.gif" />
<Content Include="ServiceVault\wtv-chat\MakeChatPage.js" />
<Content Include="ServiceVault\wtv-cookie\add.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-cookie\get.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-cookie\list.js" />
<Content Include="ServiceVault\wtv-flashrom\current-noflash.js">
<SubType>Code</SubType>
</Content>
@@ -186,17 +193,47 @@
<Content Include="ServiceVault\wtv-music\demo\midi\Wind1.mid" />
<Content Include="ServiceVault\wtv-music\demo\midi\Xess.mid" />
<Content Include="ServiceVault\wtv-music\demo\music.jpg" />
<Content Include="ServiceVault\wtv-music\get-playlist.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-register\FinishRegistration.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-register\register.js" />
<Content Include="ServiceVault\wtv-register\ServeAgreementDeclinePage.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-register\ServeLegal.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-register\ValidateAccountInfo.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-register\ValidateAgreement.js" />
<Content Include="ServiceVault\wtv-register\ShowTOS.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-register\ValidateReviewAccountInfo.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-register\ValidateWelcome.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-register\splash.js" />
<Content Include="ServiceVault\wtv-setup\get.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-star\ROMCache\HackTVLogoJewel.gif" />
<Content Include="ServiceVault\wtv-star\ROMCache\WebTVLogoJewel.gif" />
<Content Include="ServiceVault\wtv-tricks\access.js" />
<Content Include="ServiceVault\wtv-tricks\blastcache.js" />
<Content Include="ServiceVault\wtv-tricks\blastbacklist.js" />
<Content Include="ServiceVault\wtv-tricks\go-offline.js" />
<Content Include="ServiceVault\wtv-tricks\info.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-tricks\tricks.js">
<SubType>Code</SubType>
</Content>
<Content Include="ServiceVault\wtv-update\content\diskmaps\DealerDemo.json">
<SubType>Code</SubType>
</Content>
@@ -224,6 +261,12 @@
<Content Include="WTVFlashrom.js">
<SubType>Code</SubType>
</Content>
<Content Include="WTVLzpf.js">
<SubType>Code</SubType>
</Content>
<Content Include="WTVRegister.js">
<SubType>Code</SubType>
</Content>
<Content Include="WTVSec.js">
<SubType>Code</SubType>
</Content>
@@ -233,11 +276,13 @@
<Folder Include="ServiceVault\" />
<Folder Include="ServiceVault\wtv-chat\" />
<Folder Include="ServiceVault\wtv-chat\images\" />
<Folder Include="ServiceVault\wtv-cookie\" />
<Folder Include="ServiceVault\wtv-flashrom\" />
<Folder Include="ServiceVault\wtv-flashrom\ROMCache\" />
<Folder Include="ServiceVault\wtv-music\" />
<Folder Include="ServiceVault\wtv-music\demo\" />
<Folder Include="ServiceVault\wtv-music\demo\midi\" />
<Folder Include="ServiceVault\wtv-register\" />
<Folder Include="ServiceVault\wtv-setup\" />
<Folder Include="ServiceVault\wtv-star\" />
<Folder Include="ServiceVault\wtv-star\ROMCache\" />