v0.9.54 combined merge from dev

* initial (very incomplete) work on PC Services Admin (eg csops)
  * primitive account listing
  * add ban/unban/delete functionality
* fix wtv-tricks theme
* fix wtv-tricks theme (cSetup)
* better tricks code
* fix session_data.getTicketData()
* speedtest and other tricks stuff
* better protection against direct access to finished url
* dependancies update (run `npm update`)
* Bump path-to-regexp and express in /zefie_wtvp_minisrv (#29)

Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 0.1.12 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.

Updates `path-to-regexp` from 0.1.10 to 0.1.12
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.10...v0.1.12)

Updates `express` from 4.21.1 to 4.21.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.1...4.21.2)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix up path functions

* force version 1.2.1 of newsie due to breaking change

* remove debug log print for usenet

* fix account directory was broken due to previous changes

* fix wtv-home:/home was hiding options bar

* bump to 0.9.54

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
zefie
2024-12-18 19:30:33 -05:00
committed by GitHub
parent 8315347e95
commit 9314705def
25 changed files with 713 additions and 324 deletions

View File

@@ -1,9 +1,8 @@
'use strict';
const path = require('path');
var classPath = __dirname + path.sep + "includes" + path.sep + "classes" + path.sep;
var classPath = path.resolve(__dirname + path.sep + "includes" + path.sep + "classes" + path.sep) + path.sep;
const { WTVShared, clientShowAlert } = require(classPath + "WTVShared.js");
const wtvshared = new WTVShared(); // creates minisrv_config
classPath = wtvshared.getAbsolutePath(classPath, __dirname);
const fs = require('fs');
const tls = require('tls');
@@ -337,7 +336,7 @@ var runScriptInVM = function (script_data, user_contextObj = {}, privileged = fa
"breakOnSigint": true
});
} catch (e) {
console.error(e);
throw e;
}
// unload any loaded modules for this vm
@@ -382,7 +381,7 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
}
var privileged = false;
if (minisrv_config.services[service_name]) privileged = (minisrv_config.services[service_name].privileged) ? true : false;
else if (pc_services) privileged = (minisrv_config.services['pc_services'].privileged) ? true : false;
else if (pc_services) privileged = (minisrv_config.services[pc_service_name].privileged) ? true : false;
if (privileged) {
updateFromVM.push(["ssid_sessions", "ssid_sessions"]); // global ssid_sessions object for privileged service scripts, such as wtv-setup, wtv-head-waiter, etc
@@ -440,6 +439,7 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
contextObj.cwd = service_vault_file_path.substr(0, service_vault_file_path.lastIndexOf(path.sep));
}
if (file_exists && !is_dir) {
// file exists, read it and return it
service_vault_found = true;
@@ -616,7 +616,7 @@ async function processPath(socket, service_vault_file_path, request_headers = ne
headers = errpage[0];
data = errpage[1];
if (pc_services) {
if (minisrv_config.services[real_service_name].show_verbose_errors)
if (minisrv_config.services[pc_service_name].show_verbose_errors)
data += "<br><br>The interpreter said:<br><pre>" + e.stack + "</pre>";
}
console.error(" * Scripting error:", e);
@@ -2043,7 +2043,7 @@ if (!minisrv_config) {
var service_vaults = new Array();
if (minisrv_config.config.ServiceVaults) {
Object.keys(minisrv_config.config.ServiceVaults).forEach(function (k) {
var service_vault = wtvshared.returnAbsolutePath(minisrv_config.config.ServiceVaults[k]);
var service_vault = wtvshared.getAbsolutePath(minisrv_config.config.ServiceVaults[k]);
service_vaults.push(service_vault);
console.log(" * Configured Service Vault at", service_vault, "with priority", (parseInt(k) + 1));
})
@@ -2054,7 +2054,7 @@ if (minisrv_config.config.ServiceVaults) {
var service_deps = new Array();
if (minisrv_config.config.ServiceDeps) {
Object.keys(minisrv_config.config.ServiceDeps).forEach(function (k) {
var service_dep = wtvshared.returnAbsolutePath(minisrv_config.config.ServiceDeps[k]);
var service_dep = wtvshared.getAbsolutePath(minisrv_config.config.ServiceDeps[k]);
service_deps.push(service_dep);
console.log(" * Configured Service Dependencies at", service_dep, "with priority", (parseInt(k) + 1));
})
@@ -2063,7 +2063,7 @@ if (minisrv_config.config.ServiceDeps) {
}
if (minisrv_config.config.SessionStore) {
var SessionStore = wtvshared.returnAbsolutePath(minisrv_config.config.SessionStore);
var SessionStore = wtvshared.getAbsolutePath(minisrv_config.config.SessionStore);
console.log(" * Configured Session Storage at", SessionStore);
} else {
throw ("ERROR: No Session Storage Directory (SessionStore) defined!");

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

View File

@@ -9,7 +9,7 @@ cch=rom+'Cache/'
rch='/ROMCache/'
thm=rch+'Themes/'
thi=thm+'Images/'
thb=thm+'Borders/'
thb=rom+'Borders/'
th=0
@@ -32,13 +32,13 @@ function gTC(type,itm){
case 1://dark
bgclr='191919'
tclr='42bd52'
bbif = rom + 'ButtonBorder2'
bbif = thb+'ButtonBorder2'
break
case 2://red
bgclr='6e0005'
tclr='f0f0f0'
bclr='f0f0f0'
bbif = rom + 'ButtonBorder2'
bbif = thb+'ButtonBorder2'
break
case 3://basic
bgclr='cccccc'
@@ -59,7 +59,7 @@ function gTC(type,itm){
case 5://green
bgclr='004422'
tclr='f0f0f0'
bbif = rom + 'ButtonBorder2'
bbif = thb+'ButtonBorder2'
break
case 6://blue
bgclr='002244'
@@ -68,7 +68,7 @@ function gTC(type,itm){
vclr='0080ff'
shimg=''
gclr='004488'
bbif = rom + 'ButtonBorder2'
bbif = thb+'ButtonBorder2'
break
case 7://teal
bgclr='008080'
@@ -80,12 +80,12 @@ function gTC(type,itm){
bgclr='4a2766'
lclr='aaaaaa'
shimg='ShadowLogo8.gif'
bbif=rom+'ButtonBorder2'
bbif = thb+'ButtonBorder2'
break
case 9://brown
bgclr='442200'
tclr='e7ce4a'
bbif = rom + 'ButtonBorder2'
bbif = thb+'ButtonBorder2'
break
case 10://white
bgclr='c9c9c9'
@@ -98,7 +98,7 @@ function gTC(type,itm){
case 11://halloween
bgclr='080808'
tclr='c06000'
bbif = rom + 'ButtonBorder2'
bbif = thb+'ButtonBorder2'
break
}switch(type){
case 'bg':return bgclr
@@ -187,6 +187,7 @@ function ta(r,s,n,b,c,x,u){
d.write('<textarea rows='+r+' size='+s+' id='+n+' name='+n+' border='+b+' text='+tclr+' bgcolor='+bgclr+' '+x+'>'+c+'</textarea>');
if(u){d.write('</font>')}
}
function as(bg,h,w,g,b,lc,rc,lo,ro,s){
if(s){
if(!lc){lc=gTC('t')}

View File

@@ -2,7 +2,7 @@ z_nv=null;
z_th=new Array()
z_th[0]='HackTV Light'
z_th[1]='WebTV Dark'
z_th[2]='Avegee Red'
z_th[2]='Amy<br>Red'
z_th[3]='Basic Web'
z_th[4]='WinXP Tan'
z_th[5]='Ryder Green'

View File

@@ -0,0 +1,181 @@
var minisrv_service_file = true;
WTVPCAdmin = require(classPath + "/WTVPCAdmin.js")
var wtva = new WTVPCAdmin(minisrv_config, socket, service_name);
var auth = wtva.isAuthorized();
if (auth === true) {
var password = null;
if (request_headers.authorization) {
var authheader = request_headers.authorization.split(' ');
console.log(request_headers)
if (authheader[0] == "Basic") {
password = Buffer.from(authheader[1], 'base64').toString();
password = password.split(':')[1];
}
}
if (wtva.checkPassword(password)) {
headers = `200 OK
Content-Type: text/html`
htmlhead = `<html>
<head>
<title>zefie minisrv v${minisrv_config.version} account administration</title>
</head>
<body bgcolor="#000000" text="#449944" link="gold" alink="gold" vlink="gold">
<p>
Welcome to the zefie minisrv v${minisrv_config.version} Account Administration
</p>
`;
data = htmlhead;
if (!request_headers.query.cmd) {
data += `Please select an option to get started:
<hr>
<a href="?cmd=list">List all SSIDs and their Primary User</a><br>
</p>
</body>
</html >`;
}
else if (request_headers.query.cmd == "list") {
data += `<hr>`;
if (request_headers.query.msg) {
data += decodeURI(request_headers.query.msg) + "<hr>";
}
data += `<table border=1>`;
accounts = wtva.listRegisteredSSIDs();
Object.keys(accounts).forEach(function (k) {
data += `<tr><td><a href="?cmd=ssid&ssid=${accounts[k][0]}">${accounts[k][0]}</a></td><td>${(accounts[k][1]['username'] === undefined) ? "Unregistered SSID" : accounts[k][1]['username'] }</td></tr>`;
});
data += `</table>`;
} else if (request_headers.query.cmd == "ssid") {
var ssid = request_headers.query.ssid;
if (!ssid) {
redirectmsg = `An SSID is required for the ${request_headers.query.cmd} command.`;
} else {
data += "<hr>";
if (request_headers.query.msg) {
data += decodeURI(request_headers.query.msg) + "<hr>";
}
data += `<script>
function validateSelection(cmd, ssid, friendlymsg) {
conf = confirm("Are you sure you wish to "+friendlymsg+"?\\n\\n"+ssid);
if (conf) {
location.href = "/admin/?cmd="+cmd+"&ssid="+ssid;
}
}
</script>
`
data += `<p>Management for SSID: ${ssid}</p>`;
data += `<form action="/admin/" method="GET">`
data += `<input type="button" value="Delete Account" onclick="validateSelection('delete', '${ssid}', 'delete all accounts associated with this SSID')">`
if (wtva.isBanned(ssid)) {
data += `<input type="button" value="Ban Account" onclick="validateSelection('ban', '${ssid}', 'ban this SSID')" disabled=disabled>`
data += `<input type="button" value="Unban Account" onclick="validateSelection('unban', '${ssid}', 'unban this SSID')">`
} else {
data += `<input type="button" value="Ban Account" onclick="validateSelection('ban', '${ssid}', 'ban this SSID')">`
data += `<input type="button" value="Unban Account" onclick="validateSelection('unban', '${ssid}', 'unban this SSID')" disabled=disabled>`
}
data += "<p><table border=1>";
user_info = wtva.getAccountInfoBySSID(ssid.toLowerCase());
if (user_info.account_users) {
if (user_info.account_users['subscriber']) {
data += `<tr><td>Primary User:</td><td>${user_info.account_users['subscriber'].subscriber_username}</td></tr>`;
if (Object.keys(user_info.account_users).length > 1) {
data += `<tr><td style="vertical-align: top">Additional Users:</td><td>`;
Object.keys(user_info.account_users).forEach(function (k) {
if (k == "subscriber") return;
data += user_info.account_users[k].subscriber_username + "<br>";
})
data += `</td></tr>`
}
data += "</table></p>";
} else {
data += "The user aborted registration, so this account has no users."
}
} else {
data += "The SSID does not exist in the SessionStore."
}
}
} else if (request_headers.query.cmd == "delete") {
redirectmsg = "";
var ssid = request_headers.query.ssid;
if (ssid) {
var userAccount = wtva.getAccountBySSID(ssid);
userAccount.unregisterBox();
redirectmsg = `All data for SSID ${ssid} has been deleted. Please note that this does not include Usenet posts made by this account.`;
} else {
redirectmsg = `An SSID is required for the ${request_headers.query.cmd} command.`;
}
headers = "302 OK\nLocation: /admin/?cmd=list&msg=" + encodeURI(redirectmsg);
} else if (request_headers.query.cmd == "ban") {
redirectmsg = "";
var ssid = request_headers.query.ssid;
if (ssid) {
var fake_config = wtvshared.getUserConfig();
if (!fake_config.config) fake_config.config = {};
if (!fake_config.config.ssid_block_list) fake_config.config.ssid_block_list = [];
var entry_exists = false;
Object.keys(fake_config.config.ssid_block_list).forEach(function (k) {
if (fake_config.config.ssid_block_list[k] == ssid) {
redirectmsg = "The SSID was already banned.";
}
});
if (!entry_exists) {
fake_config.config.ssid_block_list.push(ssid);
wtvshared.writeToUserConfig(fake_config);
reloadConfig();
redirectmsg = "The SSID is now banned.";
}
} else {
redirectmsg = `An SSID is required for the ${request_headers.query.cmd} command.`;
}
headers = "302 OK\nLocation: /admin/?cmd=ssid&ssid=" + encodeURI(ssid) + "&msg=" + encodeURI(redirectmsg);
} else if (request_headers.query.cmd == "unban") {
redirectmsg = "The SSID was not banned, so it could not be unbanned.";
var ssid = request_headers.query.ssid;
if (ssid) {
var config_changed = false;
var fake_config = wtvshared.getUserConfig();
if (!fake_config.config) fake_config.config = {};
if (!fake_config.config.ssid_block_list) fake_config.config.ssid_block_list = [];
if (typeof request_headers.query.ssid === 'string') {
Object.keys(fake_config.config.ssid_block_list).forEach(function (k) {
if (fake_config.config.ssid_block_list[k] == request_headers.query.ssid) {
fake_config.config.ssid_block_list.splice(k, 1);
config_changed = true
}
});
} else {
Object.keys(fake_config.config.ssid_block_list).forEach(function (k) {
Object.keys(request_headers.query.ssid).forEach(function (j) {
if (fake_config.config.ssid_block_list[k] == request_headers.query.ssid[j]) {
fake_config.config.ssid_block_list.splice(k, 1);
config_changed = true
}
});
});
}
if (config_changed) {
wtvshared.writeToUserConfig(fake_config);
minisrv_config = reloadConfig();
redirectmsg = "The SSID is now unbanned.";
}
else {
redirectmsg = `An SSID is required for the ${request_headers.query.cmd} command.`;
}
}
headers = "302 OK\nLocation: /admin/?cmd=ssid&ssid=" + encodeURI(ssid) + "&msg=" + encodeURI(redirectmsg);
}
} else {
var errpage = wtvshared.doErrorPage(401, "Please enter the administration password, you can leave the username blank.");
headers = errpage[0];
headers += "\nWWW-Authenticate: Basic";
data = errpage[1];
}
} else {
var errpage = wtvshared.doErrorPage(403, auth);
headers = errpage[0];
data = errpage[1];
}

View File

@@ -103,7 +103,7 @@ if (ssid_sessions[socket.ssid].get("wtv-used-8675309") || ssid_sessions[socket.s
<spacer height=32 type=block><b><shadow><blackface><font color=cbcbcb>${title} &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </font></blackface></shadow></b>
</td></tr></table>`;
}
data += `<display nooptions>
data += `
<hr>
<center>
@@ -123,8 +123,7 @@ if (ssid_sessions[socket.ssid].get("wtv-used-8675309") || ssid_sessions[socket.s
} else {
data += `<input type="text" name="url" width=440 bgcolor=191919 text=42bd52 cursor=42bd52 autoexecute value="wtv-tricks:/tricks">`;
}
data += `
<input type="submit" value="Go">
data += `<script>butt("Go","submit",30,"submit")</script>
</form>
<hr>
<table>
@@ -234,8 +233,6 @@ This server is operated by ${minisrv_config.config.service_owner}.<br>
<td valign="top" colspan=4>
&#149;&nbsp; Redesigned home page, uses custom rom theme system.<br>
&#149;&nbsp; Added Protoweb Support (<a href="proto://www.webtv.net/">Try it!</a>)<br>
&#149;&nbsp; Added a <a href="wtv-tricks:/charmap">WebTV Character Map</a><br>
&#149;&nbsp; Redesigned homepage based on MattMan69's HackTV<br>
&#149;&nbsp; Added a new minisrv logo<br>
</td></tr>
</table>

View File

@@ -0,0 +1,79 @@
var minisrv_service_file = true;
headers = `200 OK
Connection: Keep-Alive
wtv-expire-all: wtv-tricks:/benchmark
Content-type: text/html`
data = `<html>
<display nosave nosend skipback>
<script src=/ROMCache/h.js></script><script src=/ROMCache/n.js></script><script>
head('Speed Test Result')</script>`;
var start_time = parseInt(session_data.getTicketData("benchmark_starttime"));
if (isNaN(start_time)) {
data += "Invalid data, please try your benchmark again";
} else {
var end_time = Math.floor(new Date().getTime());
if (!session_data.getTicketData("benchmark_endtime")) {
session_data.setTicketData("benchmark_endtime", end_time);
} else {
end_time = session_data.getTicketData("benchmark_endtime");
}
var download_time = end_time - start_time;
var image_filename = wtvshared.getServiceDep("/wtv-tricks/benchmark.jpg", true);
var image_size = fs.statSync(image_filename).size
var image_size_kb = parseFloat(image_size / 1024).toFixed(3);
var throughput = parseFloat((image_size / download_time) * 1024).toFixed(0);
data += `
<table>
<tr>
<td height=20>
<tr>
<td valign=top align=right width=200><shadow>POP Number:</shadow>
<td width=10>
<td valign=top>&phone;
<tr>
<td valign=top align=right><shadow>Connected at:</shadow>
<td width=10>
<td valign=top>&rate;
<tr>
<td valign=top align=right><shadow>Modem f/w:</shadow>
<td width=10>
<td valign=top>&modem;
<tr>
<td height=40>
<tr>
<td valign=top align=right width=200><shadow>Image Size:</shadow>
<td width=10>
<td valign=top>${image_size_kb} KBytes
<tr>
<td valign=top align=right><shadow>Start Time:</shadow>
<td width=10>
<td valign=top>${new Date(start_time).toISOString().replace('T', ' ').substr(0, 19)}
<tr>
<td valign=top align=right><shadow>End Time:</shadow>
<td width=10>
<td valign=top>${new Date(end_time).toISOString().replace('T', ' ').substr(0, 19)}
<tr>
<td valign=top align=right><shadow>Total Time:</shadow>
<td width=10>
<td valign=top>${parseFloat(download_time / 1000).toFixed(1)} seconds
<tr>
<td valign=top align=right><shadow>Throughput:</shadow>
<td width=10>
<td valign=top>${throughput} bytes/sec
</table>
`;
}
data += `
<p>
<p>
<a selected href="wtv-tricks:/benchmark">Re-Test</a>
<td width=30>
<a href="wtv-tricks:/tricks">Back to Tricks</a>
</CENTER>
</BODY>
</HTML>
`;

View File

@@ -0,0 +1,35 @@
var minisrv_service_file = true;
headers = `200 OK
Connection: Keep-Alive
`;
if (!request_headers.query.getimage) {
if (session_data.getTicketData("benchmark_starttime")) {
session_data.deleteTicketData("benchmark_endtime")
}
headers += `wtv-expire-all: wtv-tricks:/benchmark
Content-type: text/html`
data = `<HTML>
<HEAD>
<TITLE>Speedtest in progress...</TITLE>
<display nosend noback>
</HEAD>
<BODY BGCOLOR=191919 TEXT=44cc55 LINK=189cd6 VLINK=189cd6>
<CENTER>
<h1>Benchmark Image</h1>
<br>
<IMG SRC="wtv-tricks:/benchmark?getimage=true" ALIGN=CENTER onload="location.href='wtv-tricks:/benchmark-finished'">
</CENTER>
</BODY>
</HTML>`;
} else {
var start_time = Math.floor(new Date().getTime());
session_data.setTicketData("benchmark_starttime", start_time);
headers += "wtv-expire-all: wtv-tricks:/benchmark\nContent-type: image/jpg"
data = wtvshared.getServiceDep("/wtv-tricks/benchmark.jpg", false);
}

View File

@@ -37,174 +37,42 @@ function load() {
headers = `200 OK
Content-Type: text/html`
data = `<html>
<head>
<title>Connect Setup v2.2-minisrv</title>
<DISPLAY noscroll notvaudio switchtowebmode>
</head>
<body bgcolor="#3C2F47" text="#cbcbcb" link="#aaaaaa"
hspace="0" vspace="0" fontsize="large" noscroll>
<table cellspacing="0" cellpadding="0" cellborder="0">
<tr>
<td width="104" height="80" valign="top" align="left"><spacer type="block" WIDTH="11" HEIGHT="11"><br>
<spacer type="block" WIDTH="10" HEIGHT="1"> <a href="wtv-home:/home"><img src="${minisrv_config.config.service_logo}" width="87"
height="67"></a>
</td>
<td width="456" height="80" valign="middle" align="center">
<br><h2>
&nbsp;Connection Setup v2.2-minisrv
</h2>
</td>
</tr>
<tr><td colspan=4><hr>
<tr><td absheight=6>
data = `<html><head><display nooptions noscroll allowoffline notvaudio switchtowebmode nosend>
<script src=/ROMCache/h.js></script><script src=/ROMCache/n.js></script>
<script src=htv-cSetup.js></script>
</head><form name=t><input type=hidden name=h value=&pname;></form>
<script>head('Connect Setup v2.6');
window.onload=uS;
</script><form name=c action=client:ConfirmConnectSetup>
<table width=100% cellspacing=1 cellpadding=0>
<tr><td height=18>
<tr><td colspan=3>&nbsp;Server:</td>
<td><select width=420 name=p onchange=uS() selected>
<option value=htv>MattMan's (HTV) MiniSrv</option>
<option value=htvb>MattMan's (HTV) MiniSrv Backup</option>
<option value=mm69>MattMan's Revival Srv.</option>
<option value=zef>zefie's MiniSrv</option>
<option value=jar>WebTV Redialed</option>
<option value=zlan>zefie LAN (.8)</option>
<option value=zlan2>zefie LAN (.95)</option>
<option value=other>Other</option>
</select></table>
<table width=100% cellspacing=1 cellpadding=0>
<tr><td height=18>
<tr><td><input name=serviceType type=hidden value=custom>
&nbsp;Address:&nbsp;&nbsp;&nbsp;<input size=21 asciionly name=machine value="" bgcolor=191919 text=c6c6c6 cursor=cc9933>
&nbsp;&nbsp;&nbsp;Port:<input size=5 asciionly numbers name=port value="" bgcolor=191919 text=c6c6c6 cursor=cc9933>
</table>
<script>
function doConnect() {
if (document.connect.machine.value == "${minisrv_config.services['wtv-1800'].host}" && document.connect.port.value == "${minisrv_config.services['wtv-1800'].port}") {
alert("You are already here!");
} else {
document.connect.submit();
}
}
function setOther() {
count = document.connect.preset.length;
document.connect.preset.selectedIndex = count - 1;
setTimeout(updateService,10);
}
function updateService() {
srv = document.connect.preset[document.connect.preset.selectedIndex].value;
switch (srv) {
case "mattman69":
document.connect.machine.value="71.244.121.234"
document.connect.port.value="1615"
document.message.msg.value="This is MattMan69's Public HackTV minisrv, all are welcome to connect and enjoy the wonders of WebTV. Offers a custom experience."
break;
case "mm69bak":
document.connect.machine.value="71.244.121.234"
document.connect.port.value="1415"
document.message.msg.value="This is the public HackTV minisrv backup, only available when the main HackTV server is down."
break;
case "mm69pri":
document.connect.machine.value="71.244.121.234"
document.connect.port.value="1515"
document.message.msg.value="This is MattMan's normally private WebTV server. It's the real deal, not minisrv! May be up from time to time."
break;
case "redialed":
document.connect.machine.value="217.160.150.209"
document.connect.port.value="1615"
document.message.msg.value="WebTV Redialed, a server designed to replicate the original WebTV service."
break
case "zefie":
document.connect.machine.value="38.175.202.142"
document.connect.port.value="1615"
document.message.msg.value="This is zefie's public minisrv, for those who want the vanilla minisrv experience."
break
case "local":
document.connect.machine.value="127.0.0.1"
document.connect.port.value="1615"
document.message.msg.value="Connect to your server via localhost. Localhost refers to the computer that you are on that is running your server."
break;
case "other":
document.message.msg.value="Your custom service."
}
}
</script>
<form name="connect" action="wtv-tricks:/cSetup">
<table width=100% cellspacing=1 cellpadding=0>
<tr>
<td colspan=3>
&nbsp;<font color=#4489a8>Presets:</font>
</td>
<td><spacer W=24 type=block>
<select width="440" name="preset" onchange="updateService()" selected>
<option value="mattman69" selected>MattMan's (HTV) MiniSrv - Public</option>
<option value="mm69bak">MattMan's (HTV) MiniSrv - Bakup</option>
<option value="mm69pri">MattMan's Revival Server</option>
<option value="redialed">WebTV Redialed</option>
<option value="zefie">Zefie's MiniSrv - Public</option>
<option value="local">Localhost - Your Server</option>
<option value="other">Other</option>
</select>
<tr><td absheight=6>
</table>
<hr>
<table width=100% cellspacing=1 cellpadding=0>
<tr>
<td height=6>
<tr>
<td colspan=3>
&nbsp;<font color=#4489a8>Service:</font>
<tr>
<td width=15></td>
<td height=2>
<tr>
<td height=2>
<tr>
<td>
<td>
<input name=serviceType type=radio bgcolor=#444444 value=custom checked>
<td>
&nbsp;Custom:&nbsp;&nbsp;&nbsp;
<td>
Address:
<input size=16 ASCIIONLY name=machine bgcolor=#444444 text=#cbcbcb cursor=#cc9933 value="71.244.121.234" onkeypress="setOther()">
&nbsp;&nbsp;&nbsp;Port:
<input size=5 ASCIIONLY NUMBERS name=port bgcolor=#444444 text=#cbcbcb cursor=#cc9933 value="1615" onkeypress="setOther()">
</table>
<spacer type=block height="8">
<hr>
<table cellspacing=1 cellpadding=0>
<tr>
<td height=8>
<tr>
<td colspan=3>
&nbsp;<font color=#4489a8>Description:</font><br><br>
<tr>
<td width=20>
<td width=390 align=left valign=top>
<form name=message>
<textarea rows=4 size=46 text=#cbcbcb id=msg name=msg border="0" bgcolor=#3C2F47 value='This is the public HackTV minisrv, all are welcome to connect and enjoy the wonders of WebTV. Custom experience!' nohighlight noselect>
</textarea>
</form>
<td>
<td width=100% align=right valign=top>
<form action="client:GoToPhoneSetup">
<font color="#E7CE4A" size=-2><shadow>&nbsp;
<input
type=submit
borderimage="file://ROM/tvimages/TVButtonBorder.bif"
value="Phone Settings"
name="Phone Settings"
usestyle
width=170> &nbsp;
</shadow></font>
</form>
<spacer type=block height="60">
<font color="#E7CE4A" size=-2><shadow>&nbsp;
<input type=hidden name=useEncryption value=true checked>
<input
type=button
borderimage="file://ROM/tvimages/TVButtonBorder.bif"
value="Connect"
name="Connect"
onclick="doConnect()"
usestyle
width=170> &nbsp;
</shadow></font>
</table>
</form>
</body>
</html>`;
<spacer type=block height=42><hr><br>
<table cellspacing=1 cellpadding=0>
<tr><td height=1>
<tr><td colspan=2>&nbsp;Info:<br><br><td>
<tr><td width=20><td width=300 align=left valign=top>
<form name=i><font size=-1><script>ta(6,46,'msg',0,'','nohighlight noselect',1)</script></font></form>
<td><td width=100% align=right valign=top>
<font size=-2><input type=hidden name=useEncryption value=true><script>butt('Connect','Connect',170);</script></font>
</form>
<form action=client:gotophonesetup><font size=-2><script>butt( 'Dialing Options', '', 170);</script></font></form>
</table>
`;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 B

View File

@@ -6,7 +6,7 @@ var legend_every = 6;
function getLegend() {
d = "<tr>\n";
for (var i = 0; i < num_per_line; i++) {
d += "<td><b><font color=44cc55>Code</font></b>\n<td><b><font color=44cc55>Char</font></b>\n";
d += "<td><b>Code</b>\n<td><b>Char</b>\n";
}
d += "<tr>\n";
return d;
@@ -16,18 +16,12 @@ function getLegend() {
headers = `200 OK
Content-Type: text/html`;
data = `<html>
<body>
<display nosave nosend>
<title>WebTV Character Map</title>
<sidebar width=20%>
<img src="wtv-tricks:/images/Favorites_bg2.jpg">
</sidebar>
<body bgcolor="#191919" text="#33bb44" link="36d5ff" vlink="36d5ff" vspace=0>
<br>
<br>
<font color=44cc55><h1>WebTV Character Map</h1></font>
<br>
data = `<html><head><display allowoffline switchtowebmode>
<script src=/ROMCache/h.js></script><script src=/ROMCache/n.js></script>
<script src=htv-cSetup.js></script>
</head ><form name=t><input type=hidden name=h value=&pname;></form>
<script>head('WebTV Character Map');</script>
<br><br>
<table border=1>`;

View File

@@ -0,0 +1,27 @@
function uI(ip,prt,dsc,ro){
if(!ro){ro=false}
d.c.machine.value=ip
d.c.port.value=prt
d.i.msg.value=dsc
d.c.machine.readonly=ro
d.c.port.readonly=ro
}
function uS(){switch(d.c.p[d.c.p.selectedIndex].value){
case "htv":uI("71.244.121.234","1615","This is the public HackTV minisrv, all are welcome to connect and enjoy the wonders of WebTV. Custom experience, including updates to HackTV builds!",true)
break
case "htvb":uI("71.244.121.234","1415","This is the public HackTV minisrv backup, only available when the main HackTV server is down.",true)
break
case "zef": uI("38.175.202.142","1615","zefie's public minisrv, for those who want an experience close to the vanilla minisrv.",true)
break
case "mm69":uI("71.244.121.234","1515","MattMan's megasrv. It's the real deal, not minisrv! May be up from time to time.",true)
break
case "jar":uI("217.160.150.209","1615","WebTV Redialed aims to replicate the look and feel of the original production WebTV service.",true)
break
case "zlan":uI("192.168.11.8","1615","zefie's Desktop via LAN.",false)
break
case "zlan2":uI("192.168.11.95","1615","zefie's public minisrv via LAN.",false)
break
case "other":uI("","1615","Your custom service.",false)
break
}}

View File

@@ -31,7 +31,7 @@ Content-Type: text/html`
data = `<html>
<!--- *=* Copyright 1996, 1997 WebTV Networks, Inc. All rights reserved. --->
<display nosave nosend skipback>
<script src=file://rom/Cache/h.js></script><script src=file://rom/Cache/n.js></script><script>
<script src=/ROMCache/h.js></script><script src=/ROMCache/n.js></script><script>
head('${minisrv_config.config.service_name} Info')</script>
<table cellspacing=0 cellpadding=0><tr><td abswidth=10>&nbsp;<td colspan=3>

View File

@@ -12,69 +12,51 @@ var notAdminAlert = new clientShowAlert({
headers = `200 OK
Content-Type: text/html`
tricks = [
["wtv-tricks:/info", minisrv_config.config.service_name + " info"],
["wtv-tricks:/themes", "Theme Switcher"],
["wtv-cookie:list", "List Cookies"],
["wtv-cookie:reset", "Clear Cookies"],
["wtv-tricks:/bastblacklist?return_to=wtv-tricks%3A%2Ftricks", "Blast Blacklist"],
["client:ResetNVAndPowerOff", "Blast NVRAM"],
["wtv-tricks:/charmap", "Character Map"],
["wtv-tricks:/cSetup", "Connect Setup"],
["wtv-tricks:/benchmark", "Speed Test"],
["", ""],
["", ""],
["", ""],
["", ""],
["", ""],
["", ""],
["", ""],
]
// add these at the bottom
tricks.push((session_data.getSessionData("registered")) ? ["wtv-tricks:/unregister", "Unregister This Box"] : ["wtv-tricks:/register", "Register This Box"]); // reg/unreg
tricks.push((wtvshared.isAdmin(session_data)) ? ["wtv-admin:/admin", minisrv_config.config.service_name + " Admin"] : [notAdminAlert, minisrv_config.config.service_name + " Admin"]); // wtv-admin
data = `<html>
<display nosave nosend>
<script src=file://rom/Cache/h.js></script><script src=file://rom/Cache/n.js></script><script>
<script src=/ROMCache/h.js></script><script src=/ROMCache/n.js></script><script>
head('${minisrv_config.config.service_name} Tricks')</script>
<table cellspacing=0 cellpadding=0><tr><td abswidth=10>&nbsp;<td colspan=3>
<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>
`;
if (session_data.getSessionData("registered")) data += `<td><a href="wtv-tricks:/unregister">Unregister This Box</a>`;
else data += `<td><a href="wtv-tricks:/register">Register This Box</a>`
<table>`;
data += `
<tr>
for (i = 0; i < tricks.length; i += 2) {
data += `<tr>
<td colspan=3 height=6>
<tr>
<td><a href="${(wtvshared.isAdmin(session_data)) ? "wtv-admin:/admin" : notAdminAlert}">${minisrv_config.config.service_name} Admin</a>
<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>
<td>${(tricks[i][0] != "") ? `<a href="${tricks[i][0]}">${tricks[i][1]}</a>` : `<!-- TODO --> &nbsp;`}
<td width=25>
<td>`
if (i + 1 < tricks.length) {
data += (tricks[i + 1][0] != "") ? `<a href="${tricks[i + 1][0]}">${tricks[i + 1][1]}</a>` : `<!-- TODO --> &nbsp;`
} else {
// require even number of tricks
data += "<!-- TODO --> &nbsp;"
}
}
data += `</table>
</body>
</html>
`;

View File

@@ -193,7 +193,7 @@ class WTVClientSessionData {
}
getAccountStoreDirectory() {
return this.minisrv_config.config.SessionStore + this.path.sep + "accounts";
return this.path.resolve(this.wtvshared.getAbsolutePath() + this.path.sep + this.minisrv_config.config.SessionStore + this.path.sep + "accounts");
}
/**

View File

@@ -356,7 +356,6 @@ class WTVNews {
var promises = [];
for (var article in NGArticles) {
if (article == "getCaseInsensitiveKey" || isNaN(article)) continue;
console.log(article);
promises.push(new Promise((resolve, reject) => {
this.getHeader(NGArticles[article]).then((data) => {
if (data.article) messages.push(data.article)

View File

@@ -14,7 +14,7 @@ class WTVNewsServer {
constructor(minisrv_config, local_server_port, using_auth = false, username = null, password = null, run_server = true) {
this.minisrv_config = minisrv_config;
const { WTVShared } = require("./WTVShared.js");
this.wtvshared = new WTVShared(minisrv_config);
this.wtvshared = new WTVShared(this.minisrv_config);
this.featuredGroups = minisrv_config.services['wtv-news'].featuredGroups;
const nntp_server = require('nntp-server-zefie');
var nntp_statuses = require('nntp-server-zefie/lib/status');
@@ -23,7 +23,7 @@ class WTVNewsServer {
this.password = password || null;
this.using_auth = using_auth;
this.scan_interval = minisrv_config.services['wtv-news'].groupMetaRefreshInterval || 86400;
this.data_path = this.wtvshared.getAbsolutePath(this.minisrv_config.config.SessionStore + '/minisrv_internal_nntp');
this.data_path = this.wtvshared.getAbsolutePath(this.minisrv_config.config.SessionStore + this.path.sep + 'minisrv_internal_nntp');
this.createDataStore();
if (using_auth && (!username && !password)) {
@@ -140,9 +140,9 @@ class WTVNewsServer {
}
var tls_options = {
ca: this.wtvshared.getServiceDep('wtv-news/localserver_ca.pem'),
key: this.wtvshared.getServiceDep('wtv-news/localserver_key.pem'),
cert: this.wtvshared.getServiceDep('wtv-news/localserver_cert.pem'),
ca: this.wtvshared.getServiceDep('wtv-news' + this.path.sep + 'localserver_ca.pem'),
key: this.wtvshared.getServiceDep('wtv-news' + this.path.sep + 'localserver_key.pem'),
cert: this.wtvshared.getServiceDep('wtv-news' + this.path.sep + 'localserver_cert.pem'),
}
this.local_server = new nntp_server({ requireAuth: using_auth, tls: tls_options, secure: true, allow_posting: true });
this.local_server.listen('nntps://127.0.0.1:' + local_server_port);

View File

@@ -0,0 +1,177 @@
class WTVPCAdmin {
fs = require('fs');
path = require('path');
minisrv_config = [];
wtvr = null;
wtvshared = null;
socket = null;
WTVClientSessionData = require("./WTVClientSessionData.js");
service_name = "wtv-admin";
constructor(minisrv_config, socket, service_name) {
this.minisrv_config = minisrv_config;
var { WTVShared } = require("./WTVShared.js");
var WTVRegister = require("./WTVRegister.js");
this.socket = socket;
this.wtvr = new WTVRegister(minisrv_config);
this.clientAddress = socket.remoteAddress;
this.service_name = service_name;
}
ip2long(ip) {
var components;
if (components = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)) {
var iplong = 0;
var power = 1;
for (var i = 4; i >= 1; i -= 1) {
iplong += power * parseInt(components[i]);
power *= 256;
}
return iplong;
}
else return -1;
}
isInSubnet(ip, subnet) {
if (subnet.indexOf('/') == -1) {
var mask, base_ip, long_ip = this.ip2long(ip);
var mask2, base_ip2, long_ip2 = this.ip2long(ip);
return (long_ip == long_ip2);
} else {
var mask, base_ip, long_ip = this.ip2long(ip);
if ((mask = subnet.match(/^(.*?)\/(\d{1,2})$/)) && ((base_ip = this.ip2long(mask[1])) >= 0)) {
var freedom = Math.pow(2, 32 - parseInt(mask[2]));
return (long_ip > base_ip) && (long_ip < base_ip + freedom - 1);
}
}
return false;
}
rejectConnection() {
var rejectReason;
rejectReason = this.clientAddress + " is not in the whitelist.";
console.log(" * Request from IP", this.clientAddress, "for PC Services Admin, but that IP is not authorized.");
return rejectReason;
}
checkPassword(password) {
if (this.minisrv_config.config.pc_admin.password) {
return (password == this.minisrv_config.config.pc_admin.password);
} else {
// no password set
return true;
}
}
isAuthorized(justchecking = false) {
var allowed_ip = false;
if (this.minisrv_config.config.pc_admin.ip_whitelist) {
var self = this;
Object.keys(this.minisrv_config.config.pc_admin.ip_whitelist).forEach(function (k) {
allowed_ip = self.isInSubnet(self.clientAddress, self.minisrv_config.config.pc_admin.ip_whitelist[k]);
});
}
if (justchecking) {
return allowed_ip;
} else {
return allowed_ip ? true : this.rejectConnection();
}
}
listRegisteredSSIDs() {
var search_dir = this.minisrv_config.config.SessionStore + this.path.sep + "accounts";
var self = this;
var out = [];
this.fs.readdirSync(search_dir).forEach(file => {
if (self.fs.lstatSync(search_dir + self.path.sep + file).isDirectory()) {
var user = self.getAccountInfoBySSID(file);
out.push([file,user]);
}
});
return out;
}
getAccountInfo(username, directory = null) {
var search_dir = this.minisrv_config.config.SessionStore + this.path.sep + "accounts";
var account_data = null;
var self = this;
if (directory) search_dir = directory;
this.fs.readdirSync(search_dir).forEach(file => {
if (self.fs.lstatSync(search_dir + self.path.sep + file).isDirectory() && account_data === null) {
account_data = self.getAccountInfo(username, search_dir + self.path.sep + file);
}
if (account_data !== null) return;
if (!file.match(/.*\.json/ig)) return;
try {
var temp_session_data_file = self.fs.readFileSync(search_dir + self.path.sep + file, 'Utf8');
var temp_session_data = JSON.parse(temp_session_data_file);
if (temp_session_data.subscriber_username.toLowerCase() == username.toLowerCase()) {
account_data = [temp_session_data, (search_dir + self.path.sep + file).replace(this.minisrv_config.config.SessionStore + this.path.sep + "accounts", "").split(this.path.sep)[1]];
}
} catch (e) {
console.error(" # Error parsing Session Data JSON", search_dir + self.path.sep + file, e);
}
});
if (account_data !== null) {
if (account_data.ssid) return account_data;
var account_info = {};
account_info.ssid = account_data[1];
account_info.username = account_data[0].subscriber_username;
account_info.user_id = account_data[0].subscriber_userid;
var userSession = new this.WTVClientSessionData(this.minisrv_config, account_info.ssid);
userSession.user_id = 0;
account_info.account_users = userSession.listPrimaryAccountUsers();
return account_info;
}
return null;
}
getAccountInfoBySSID(ssid) {
var account_info = {};
var userSession = new this.WTVClientSessionData(this.minisrv_config, ssid);
userSession.user_id = 0;
if (userSession.isRegistered(false)) {
account_info.ssid = ssid;
account_info.account_users = userSession.listPrimaryAccountUsers();
if (account_info.account_users) {
if (account_info.account_users['subscriber']) {
account_info.username = account_info.account_users['subscriber'].subscriber_username;
} else {
account_info.username = account_info.account_users[0];
}
} else {
account_info.username = account_info.account_users[0];
}
account_info.user_id = 0;
return account_info;
}
else return false;
}
getAccountBySSID(ssid) {
var userSession = new this.WTVClientSessionData(this.minisrv_config, ssid);
userSession.user_id = 0;
return userSession;
}
isBanned(ssid) {
var self = this;
var isBanned = false;
if (this.minisrv_config.config.ssid_block_list) {
Object.keys(this.minisrv_config.config.ssid_block_list).forEach(function (k) {
if (self.minisrv_config.config.ssid_block_list[k] == ssid) {
isBanned = true;
}
});
}
return isBanned;
}
}
module.exports = WTVPCAdmin;

View File

@@ -158,6 +158,7 @@ class WTVSec {
getTicketData(key = null) {
if (typeof (this.ticket_store) === 'session_store') return null;
else if (key === null) return this.ticket_store;
else if (typeof this.ticket_store[key] !== 'undefined') return this.ticket_store[key];
else return null;
}

View File

@@ -19,12 +19,14 @@ class WTVShared {
debug = require('debug')('WTVShared')
process = require('process');
shenanigans = null;
appdir = this.path.resolve(__dirname + this.path.sep + ".." + this.path.sep + "..");
minisrv_config = [];
constructor(minisrv_config, quiet = false) {
if (minisrv_config == null) this.minisrv_config = this.readMiniSrvConfig(true, !quiet);
else this.minisrv_config = minisrv_config;
this.shenanigans = new WTVShenanigans(this.minisrv_config);
if (!String.prototype.reverse) {
@@ -370,7 +372,7 @@ class WTVShared {
// Assuming this.path.sep is a slash (/ or \) and this.parentDirectory is set correctly
if (!/^(?:[a-zA-Z]:)?[\\/]/.test(check_path)) {
// It's a relative path
check_path = this.parentDirectory + this.path.sep + check_path;
check_path = this.path.resolve(this.parentDirectory + this.path.sep + check_path);
}
// Use the fixPathSlashes method to normalize the slashes
return this.fixPathSlashes(check_path);
@@ -398,8 +400,7 @@ class WTVShared {
getUserConfig() {
try {
var user_config_filename = this.getAbsolutePath("user_config.json", this.parentDirectory);
var user_config_filename = this.getAbsolutePath("user_config.json", this.appdir);
if (this.fs.lstatSync(user_config_filename)) {
try {
var minisrv_user_config = this.parseJSON(this.fs.readFileSync(user_config_filename));
@@ -885,26 +886,34 @@ class WTVShared {
* @param {string} path
* @param {string} directory Root directory
*/
getAbsolutePath(path, directory = '') {
const pathModule = require('path');
getAbsolutePath(path = '', directory = '.') {
if (directory[0] == "/") {
return this.path.resolve(directory + this.path.sep + path);
}
try {
// start with our absolute path (of app.js)
const appdir = this.path.resolve(__dirname + this.path.sep + '..' + this.path.sep + '..')
if (path == '' && directory == '.') {
return appdir;
}
// If the directory is a valid directory, prepend it to the path
directory = this.path.resolve(appdir + this.path.sep + directory);
if (!path) {
return directory;
}
if (directory && !path.startsWith(directory)) {
const fs = require('fs');
if (fs.lstatSync(directory).isDirectory()) {
// Ensure directory has trailing separator
if (!directory.endsWith(pathModule.sep)) {
directory += pathModule.sep;
}
path = directory + path;
if (!directory.endsWith(this.path.sep)) {
directory += this.path.sep;
}
path = directory + path;
}
} catch (e) {
// If there's an error accessing the directory, log it or handle as needed
console.error('Error resolving directory:', e);
}
// The path.resolve method will take care of normalizing slashes
return pathModule.resolve(path);
return this.path.resolve(path);
}
@@ -925,9 +934,9 @@ class WTVShared {
* @return {string} path without gz, or unmodified path if it isnt a gz
*/
getFilePath(path) {
var path_split = path.split('/');
var path_split = path.split(this.path.sep);
path_split.pop();
return path_split.join('/');
return path_split.join(this.path.sep);
}
/**
@@ -1198,4 +1207,4 @@ class clientShowAlert {
}
module.exports.WTVShared = WTVShared;
module.exports.clientShowAlert = clientShowAlert;
module.exports.clientShowAlert = clientShowAlert;

View File

@@ -62,6 +62,14 @@
"null"
]
},
"pc_admin": {
"enabled": true,
"ip_whitelist": [
"192.168.1.0/24",
"127.0.0.1"
],
"password": "MySeqRetKey1" // change this in user_config.json
},
"keys": {
"initial_shared_key": "CC5rWmRUE0o=", // Used for the initial RC4 rolling key. Changing this is untested and unsupported.
"user_data_key": "PNa$WN7gz}!T=t6X7^=|Ii##CEB~p\\EP" // Currently used to cipher user passwords in configs. Changing this while there are registered accounts will make it impossible to decrypt existing account passwords

View File

@@ -1,12 +1,12 @@
{
"name": "zefie_wtvp_minisrv",
"version": "0.9.53",
"version": "0.9.54",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "zefie_wtvp_minisrv",
"version": "0.9.53",
"version": "0.9.54",
"license": "GPL3",
"dependencies": {
"@mafintosh/vm2": "^3.9.2",
@@ -14,12 +14,12 @@
"crypto-js": "^4.2.0",
"easy-crc": "0.0.2",
"endianness": "^8.0.2",
"express": "^4.21.1",
"express": "^4.21.2",
"follow-redirects": "^1.15.6",
"html-entities": "^2.5.2",
"iconv-lite": "^0.6.3",
"mime-types": "^2.1.35",
"newsie": "^1.2.1",
"newsie": "1.2.1",
"nntp-server-zefie": "^3.1.0",
"proxy-agent": "^6.4.0",
"rc4-crypto": "^1.5.0",
@@ -413,16 +413,15 @@
}
},
"node_modules/call-bind": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.0",
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.1"
"set-function-length": "^1.2.2"
},
"engines": {
"node": ">= 0.4"
@@ -431,6 +430,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.0.tgz",
"integrity": "sha512-CCKAP2tkPau7D3GE8+V8R6sQubA9R5foIzGp+85EXCVSCivuxBNAWqcpn72PKYiIcqoViv/kcUDpaEIMBVi1lQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -552,9 +564,9 @@
}
},
"node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -711,6 +723,20 @@
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/dunder-proto": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz",
"integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/easy-crc": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/easy-crc/-/easy-crc-0.0.2.tgz",
@@ -754,13 +780,10 @@
}
},
"node_modules/es-define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.4"
},
"engines": {
"node": ">= 0.4"
}
@@ -985,9 +1008,9 @@
}
},
"node_modules/express": {
"version": "4.21.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
"version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
@@ -1009,7 +1032,7 @@
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.10",
"path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7",
"qs": "6.13.0",
"range-parser": "~1.2.1",
@@ -1024,6 +1047,10 @@
},
"engines": {
"node": ">= 0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/express/node_modules/debug": {
@@ -1296,13 +1323,10 @@
}
},
"node_modules/gopd": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.1.0.tgz",
"integrity": "sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.4"
},
"engines": {
"node": ">= 0.4"
},
@@ -1340,12 +1364,12 @@
}
},
"node_modules/has-proto": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.1.0.tgz",
"integrity": "sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
"integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7"
"dunder-proto": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
@@ -1812,9 +1836,9 @@
}
},
"node_modules/newsie": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/newsie/-/newsie-1.2.2.tgz",
"integrity": "sha512-GghUsQLF/vndovSJf2w1QarRNEeCrIIIxgTK1cJJ0mIYYuiwzzAAG05RB7XXsGndEebqYQwscGpPUEKnYn7gHw==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/newsie/-/newsie-1.2.1.tgz",
"integrity": "sha512-41jhtKmlpSc27oIBkp681fm4aLURPT/AgeBvSRicxNPWDVeHLaq7tSvG/OsEXz7g41thgv9JMV1ZjYSABMiYVA==",
"license": "AGPL-1.0",
"engines": {
"node": ">=8.9.0"
@@ -2007,9 +2031,9 @@
}
},
"node_modules/path-to-regexp": {
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"license": "MIT"
},
"node_modules/picocolors": {

View File

@@ -1,6 +1,6 @@
{
"name": "zefie_wtvp_minisrv",
"version": "0.9.53",
"version": "0.9.54",
"description": "WebTV Service (WTVP) Emulation Server",
"main": "app.js",
"homepage": "https://github.com/zefie/zefie_wtvp_minisrv",
@@ -31,12 +31,12 @@
"crypto-js": "^4.2.0",
"easy-crc": "0.0.2",
"endianness": "^8.0.2",
"express": "^4.21.1",
"express": "^4.21.2",
"follow-redirects": "^1.15.6",
"html-entities": "^2.5.2",
"iconv-lite": "^0.6.3",
"mime-types": "^2.1.35",
"newsie": "^1.2.1",
"newsie": "1.2.1",
"nntp-server-zefie": "^3.1.0",
"proxy-agent": "^6.4.0",
"rc4-crypto": "^1.5.0",

View File

@@ -30,6 +30,13 @@
]
},
"hide_ssid_in_logs": true,
"pc_admin": {
"ip_whitelist": [
"192.168.20.0/24", // your subnet
"127.0.0.1"
],
"password": "MyEvEnMoReSeqRetKey1!11!" // change this
},
"verbosity": 2,
"errorMessages": {
"999": "My Custom Error Code Message",