diff --git a/.gitignore b/.gitignore index c9a5d6db..e1b59f99 100644 --- a/.gitignore +++ b/.gitignore @@ -369,3 +369,4 @@ FodyWeavers.xsd /zefie_wtvp_minisrv/SessionStore/*.json /zefie_wtvp_minisrv/SessionStore/*/ /zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/viewers/HackTV.zip +/zefie_wtvp_minisrv/postest.js diff --git a/zefie_wtvp_minisrv/.gitignore b/zefie_wtvp_minisrv/.gitignore index 85333cc9..6803f7b4 100644 --- a/zefie_wtvp_minisrv/.gitignore +++ b/zefie_wtvp_minisrv/.gitignore @@ -8,7 +8,7 @@ ServiceLogPost/*_* # Large files not pertaining to the service code UserServiceVault/*-* -UserServiceVault/*_* +UserTemplates/*_* package-lock.json diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/glossary.json b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/glossary.json similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/glossary.json rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/glossary.json diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Alerts/Forbidden.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Alerts/Forbidden.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Alerts/Forbidden.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Alerts/Forbidden.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Alerts/HostMissing.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Alerts/HostMissing.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Alerts/HostMissing.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Alerts/HostMissing.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Alerts/InternalServerError.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Alerts/InternalServerError.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Alerts/InternalServerError.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Alerts/InternalServerError.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Alerts/NotFound.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Alerts/NotFound.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Alerts/NotFound.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Alerts/NotFound.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Alerts/ServiceUnavailable.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Alerts/ServiceUnavailable.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Alerts/ServiceUnavailable.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Alerts/ServiceUnavailable.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/Index.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/Index.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/Index.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/Index.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISP.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISP.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISP.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISP.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ1.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ1.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ1.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ1.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ3.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ3.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ3.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ3.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ3B.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ3B.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ3B.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ3B.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ4.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ4.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ4.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ4.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ4B.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ4B.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ4B.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ4B.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ4C.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ4C.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ4C.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ4C.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ5.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ5.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ5.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ5.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ5B.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ5B.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/OISPQ5B.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/OISPQ5B.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/PayMethods/Ach.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/PayMethods/Ach.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/PayMethods/Ach.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/PayMethods/Ach.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/PayMethods/Credit.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/PayMethods/Credit.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/PayMethods/Credit.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/PayMethods/Credit.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/PayMethods/Debit.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/PayMethods/Debit.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/PayMethods/Debit.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/PayMethods/Debit.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/PayMethods/PayMethods.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/PayMethods/PayMethods.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Billing/PayMethods/PayMethods.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Billing/PayMethods/PayMethods.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Chat/ChatDiploma.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Chat/ChatDiploma.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Chat/ChatDiploma.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Chat/ChatDiploma.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Index/Main/1.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Index/Main/1.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Index/Main/1.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Index/Main/1.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Keyboard/Cmd/Cmd.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Keyboard/Cmd/Cmd.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Keyboard/Cmd/Cmd.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Keyboard/Cmd/Cmd.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Keyboard/Cmd/Cmd2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Keyboard/Cmd/Cmd2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Keyboard/Cmd/Cmd2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Keyboard/Cmd/Cmd2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Keyboard/Cmd/Cmd3.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Keyboard/Cmd/Cmd3.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Keyboard/Cmd/Cmd3.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Keyboard/Cmd/Cmd3.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Keyboard/Cmd/Cmd4.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Keyboard/Cmd/Cmd4.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Keyboard/Cmd/Cmd4.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Keyboard/Cmd/Cmd4.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Keyboard/Cmd/Cmd5.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Keyboard/Cmd/Cmd5.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Keyboard/Cmd/Cmd5.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Keyboard/Cmd/Cmd5.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Attach/Attach.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Attach/Attach.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Attach/Attach.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Attach/Attach.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Attach/More.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Attach/More.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Attach/More.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Attach/More.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Attach/Show.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Attach/Show.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Attach/Show.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Attach/Show.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/CarbCops/CarbCops.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/CarbCops/CarbCops.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/CarbCops/CarbCops.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/CarbCops/CarbCops.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/CarbCops/More.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/CarbCops/More.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/CarbCops/More.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/CarbCops/More.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/CarbCops/Show.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/CarbCops/Show.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/CarbCops/Show.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/CarbCops/Show.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Compose.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Compose.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Compose.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Compose.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/GetStarted/Privacy.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/GetStarted/Privacy.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/GetStarted/Privacy.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/GetStarted/Privacy.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/GetStarted/Reading.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/GetStarted/Reading.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/GetStarted/Reading.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/GetStarted/Reading.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/GetStarted/WriteMail.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/GetStarted/WriteMail.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/GetStarted/WriteMail.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/GetStarted/WriteMail.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/GettingStarted.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/GettingStarted.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/GettingStarted.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/GettingStarted.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Main.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Main.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Main.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Main.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Picture/Picture.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Picture/Picture.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Picture/Picture.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Picture/Picture.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Picture/Picture2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Picture/Picture2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Picture/Picture2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Picture/Picture2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Picture/Picture3.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Picture/Picture3.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Picture/Picture3.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Picture/Picture3.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Picture/Picture4.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Picture/Picture4.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Picture/Picture4.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Picture/Picture4.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Picture/Picture5.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Picture/Picture5.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Picture/Picture5.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Picture/Picture5.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Reply/Reply.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Reply/Reply.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Reply/Reply.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Reply/Reply.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Reply/Reply2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Reply/Reply2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Reply/Reply2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Reply/Reply2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Signature/Signature.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Signature/Signature.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Signature/Signature.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Signature/Signature.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Signature/Signature2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Signature/Signature2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Signature/Signature2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Signature/Signature2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Signature/Signature3.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Signature/Signature3.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Signature/Signature3.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Signature/Signature3.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Storage/Storage.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Storage/Storage.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Storage/Storage.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Storage/Storage.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Storage/Storage2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Storage/Storage2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Storage/Storage2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Storage/Storage2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/WhatIs.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/WhatIs.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/WhatIs.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/WhatIs.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing3.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing3.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing3.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing3.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing4.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing4.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing4.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing4.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing5.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing5.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing5.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing5.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing6.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing6.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/Write/Writing6.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/Write/Writing6.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/mail.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/mail.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Mail/mail.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Mail/mail.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/MailPOP/WhatIs/WhatIs.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/MailPOP/WhatIs/WhatIs.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/MailPOP/WhatIs/WhatIs.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/MailPOP/WhatIs/WhatIs.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/MailPOP/WhatIs/WhatIs2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/MailPOP/WhatIs/WhatIs2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/MailPOP/WhatIs/WhatIs2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/MailPOP/WhatIs/WhatIs2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail3.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail3.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail3.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Scrapbook/AddFromMail/AddFromMail3.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Spelling/Overview/Overview.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Spelling/Overview/Overview.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Spelling/Overview/Overview.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Spelling/Overview/Overview.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Spelling/Overview/Overview2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Spelling/Overview/Overview2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Spelling/Overview/Overview2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Spelling/Overview/Overview2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Spelling/Overview/Overview3.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Spelling/Overview/Overview3.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Spelling/Overview/Overview3.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Spelling/Overview/Overview3.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Spelling/Overview/Overview4.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Spelling/Overview/Overview4.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Spelling/Overview/Overview4.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Spelling/Overview/Overview4.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Spelling/Overview/Overview5.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Spelling/Overview/Overview5.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Spelling/Overview/Overview5.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Spelling/Overview/Overview5.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/Find.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/Find.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/Find.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/Find.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/Paste.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/Paste.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/Paste.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/Paste.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/PasteWord.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/PasteWord.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/PasteWord.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/PasteWord.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/Review.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/Review.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/Review.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/Review.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/Select.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/Select.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/Select.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/Select.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/SelectWord.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/SelectWord.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/SelectWord.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/SelectWord.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/Start.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/Start.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/CutPaste/Start.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/CutPaste/Start.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/Capitals.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/Capitals.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/Capitals.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/Capitals.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/Erasing.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/Erasing.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/Erasing.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/Erasing.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/GettingRidOf.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/GettingRidOf.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/GettingRidOf.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/GettingRidOf.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/InsertingSpace.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/InsertingSpace.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/InsertingSpace.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/InsertingSpace.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/NextLine.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/NextLine.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/NextLine.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/NextLine.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/NextTextBox.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/NextTextBox.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/NextTextBox.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/NextTextBox.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/OnScreenKeyboard.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/OnScreenKeyboard.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/OnScreenKeyboard.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/OnScreenKeyboard.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/PreviousTextBox.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/PreviousTextBox.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/OnScreenKeyboard/PreviousTextBox.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/OnScreenKeyboard/PreviousTextBox.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/Send.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/Send.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/Send.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/Send.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Find.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Find.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Find.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Find.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Goto.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Goto.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Goto.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Goto.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=HangUp.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=HangUp.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=HangUp.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=HangUp.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Info.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Info.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Info.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Info.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Messenger.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Messenger.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Messenger.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Messenger.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Print.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Print.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Print.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Print.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Reload.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Reload.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Reload.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Reload.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Save.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Save.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Save.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=Save.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=TVvsWeb.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=TVvsWeb.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=TVvsWeb.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=TVvsWeb.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=TvWindow.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=TvWindow.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=TvWindow.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=TvWindow.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=logo.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=logo.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=logo.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options&page=logo.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options.htm b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options.htm similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options.htm rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Tips/Options/topic=Tips&subtopic=Options.htm diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/1.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/1.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/1.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/1.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/3.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/3.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/3.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/3.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/4.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/4.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/4.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/4.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/5.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/5.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/5.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/5.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/6.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/6.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/6.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/6.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/7.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/7.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/AddUser/7.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/AddUser/7.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/Addresses/Addresses.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/Addresses/Addresses.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/Addresses/Addresses.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/Addresses/Addresses.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/Addresses/Addresses2.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/Addresses/Addresses2.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/prerendered/Users/Addresses/Addresses2.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/prerendered/Users/Addresses/Addresses2.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/templates/glossary.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/templates/glossary.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/templates/glossary.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/templates/glossary.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/templates/glossary_index.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/templates/glossary_index.js similarity index 100% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/templates/glossary_index.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/templates/glossary_index.js diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/templates/glossary_word_index.js b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/templates/glossary_word_index.js similarity index 98% rename from zefie_wtvp_minisrv/ServiceDeps/wtv-guide/templates/glossary_word_index.js rename to zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/templates/glossary_word_index.js index 7ffa6267..0c36c61b 100644 --- a/zefie_wtvp_minisrv/ServiceDeps/wtv-guide/templates/glossary_word_index.js +++ b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-guide/templates/glossary_word_index.js @@ -59,7 +59,6 @@ Choose a word to see what it means. var table_split = Math.floor(this.page_args.words.length / 2); var words_rendered = 0; var self = this; - console.log(this.page_args.words); Object.keys(this.page_args.words).forEach(function (k) { // test data += `${self.page_args.words[k].word}
\n` diff --git a/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-mail/welcomeMail.txt b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-mail/welcomeMail.txt new file mode 100644 index 00000000..5b0acbd2 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-mail/welcomeMail.txt @@ -0,0 +1,14 @@ +From: zefie +Subject: Welcome to minisrv! + +Thank you for test driving minisrv! + +minisrv aims to provide a simular experience as the production WebTV Services. +You can enjoy fun features as they are released, such as WebTV Mail, WebTV Chat, Usenet, customing your signature settings which also support custom HTML abilities. + +You can use Mail to send internal email to others by emailing theirusername@${service_name}, replacing "theirusername" with the user's actual username. +Others within the same minisrv network can also email you by sending a message to ${user_address} + +You can also save webpages to your Favorites, as well as join discussion groups on usenet! + +To report trouble of any kind please contact ${service_owner_contact} via ${service_owner_contact_method}. \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-news/post-unavailable.html b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-news/post-unavailable.html new file mode 100644 index 00000000..a38edb7f --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceDeps/templates/wtv-news/post-unavailable.html @@ -0,0 +1,231 @@ + + +Posting unavailable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + +
+ + + +
+
+
+ +
+ +
+ +
+ + + +
+ + + + +
+
Group +
+
+
+
+ +
+ +
+ +
+ + + +
+ +
Previous
+
+
+
+ +
+ +
+ +
+ + + +
+ +
Next
+
+
+
+ +
+ +
+ +
+ + + +
+ + + + +
+
Next New +
+
+
+
+ +
+ +
+ +
+ + + +
+ + + + +
+
Mail to +
+
+
+
+ +
+ +
+ +
+ + + +
+ + + + +
+
Respond +
+
+
+
+ +
+ +
+ +
+ + + +
+ + + + +
+
Help +
+
+
+
+ +
+ +
+ +
+
+
+
+ + + + + + + + + +
+ + + +
+ + + + Posting + + + + +
+



+ +This posting is no longer available. + + \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-news/localserver_ca.pem b/zefie_wtvp_minisrv/ServiceDeps/wtv-news/localserver_ca.pem new file mode 100644 index 00000000..6a5fbe67 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceDeps/wtv-news/localserver_ca.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID1TCCAr2gAwIBAgIUQzfMpYgezM0u/aOpBIYzCTSNuSgwDQYJKoZIhvcNAQEL +BQAwejELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMRcwFQYDVQQKDA5aZWZpZSBO +ZXR3b3JrczEQMA4GA1UECwwHbWluaXNydjETMBEGA1UEAwwKbWluaXNydl9jYTEe +MBwGCSqGSIb3DQEJARYPemVmaWVAemVmaWUubmV0MB4XDTIyMTAxMjAzMzQzOVoX +DTIyMTExMTAzMzQzOVowejELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMRcwFQYD +VQQKDA5aZWZpZSBOZXR3b3JrczEQMA4GA1UECwwHbWluaXNydjETMBEGA1UEAwwK +bWluaXNydl9jYTEeMBwGCSqGSIb3DQEJARYPemVmaWVAemVmaWUubmV0MIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzo8+u/9kJcQY+mOKLxYNOtNSWqlu +fwSKpo/kCMbCkM4TCJiaKHWwtXeT5tgrYPqg6s3nHpG2arwI/sxX6fy86s9i8bu5 +NEaO6/Czii0gQLXznURPaCPKp2dJEpcrFvqsB/Ej7Bm2cZH4BaOW9CeaMdrSXK1e +Tlwem1XHPeFnIPGQr3sYp2CNcB3TWzNkGGDPB2CBcR+qB2Fnjb7aEcd5t4imJqT6 +BPTiDB234v3glcEaDBIr3bT/YGZuRn7Ou8qAVKlfT4iDsgHkpW+V7RYRocfAynPF +mSxQf2i4hIfvK2mGhdpcQGH5WTOp6K9xIv/lGIZcb29xoAeICplq3/u24wIDAQAB +o1MwUTAdBgNVHQ4EFgQUG8IOPoOiwIA1GI/3pANtftkD7BwwHwYDVR0jBBgwFoAU +G8IOPoOiwIA1GI/3pANtftkD7BwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B +AQsFAAOCAQEAaG63vM/KbOfx/wzg8dZE6j/h8Ai0wJ1iXXvBLa23+fpZwfHIMH/A +uvkap+OzX3oI8fdalReY11+WONfzA4pyuNPtluwkngSLjT8YSfHfM3MUM6LKt5x4 +rRNBNN74H8A7q5UDA/SD2M1HjcOkFNlH4XrE6Uy/ColCVV9cYGPdx1rKwiQiKK7Q +Nr+6awAYHzQ2kdrZ4kneBZqAWAuIzjjWMxcgVwCHpb4rV0u3j/uhIos/8Q6NtLA7 +EqW0qMWmpJ9DlqfhLXqVCgfPyxGNpvTom0lw6J8OL8U6d+oaeVTZW44/3A8wNjJ+ +Gd2qQMxupodfV3LVyREvDpM+cowW6q+qHA== +-----END CERTIFICATE----- diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-news/localserver_cert.pem b/zefie_wtvp_minisrv/ServiceDeps/wtv-news/localserver_cert.pem new file mode 100644 index 00000000..83c6dd06 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceDeps/wtv-news/localserver_cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDnDCCAoSgAwIBAgIULCdoiUdXwTXF3qsxau5hOdxSiKQwDQYJKoZIhvcNAQEL +BQAwejELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMRcwFQYDVQQKDA5aZWZpZSBO +ZXR3b3JrczEQMA4GA1UECwwHbWluaXNydjETMBEGA1UEAwwKbWluaXNydl9jYTEe +MBwGCSqGSIb3DQEJARYPemVmaWVAemVmaWUubmV0MCAXDTIyMTAxMzAwNTIwMFoY +DzIxMjIwOTE5MDA1MjAwWjB/MQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlv +cmsxFzAVBgNVBAoMDlplZmllIE5ldHdvcmtzMRAwDgYDVQQLDAdtaW5pc3J2MRIw +EAYDVQQDDAlsb2NhbGhvc3QxHjAcBgkqhkiG9w0BCQEWD3plZmllQHplZmllLm5l +dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN5R/V1oF69ZvKyz0toA +1f2+b1BUkYivtiVYlSavAqS2EiqhKCNZdreFIuIMHo8v0npir3VxXxwwVBM2+DPQ +sp08wUCu9nLidYYBMl4qlRRANmd5i6uQ0ErLceSPv/KfkDeVfd63rrKvQCxBqhFi +OI/ZI+bxkK+P7fAntKJ35abKDQyJ4NblAb+AUXvxo+HsCaX8Gyox8cbLFGrkNICY +Pe9YcuY899OhuY/vBLTkkLXKyynG7nLaGYc39uNGg/SI0ZWcAEC1q0uRVB5ed3X7 +BfpIlP60wxLi8eX7DANDyoRJ/vOSF5RIilmrPM6bXnAMYRmsUb+Z3Wjc8NRBZCC/ +5a0CAwEAAaMTMBEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEA +nFPOU9HRjf/i5r8qS8VodNbZRVD0+aemdJobdvmlBbNn+Uh2k4sYcBse9dI2ZGbB +5Z0sxAAJXdynVqzrhIQzZUDsZFi1mBI8rpo6hGdL7QU2aepiDDb4dBpt3Xc8XcmT +SeXV5sPTZC4wT8t/IJh6wAynPKmBl1BveTtml4BHiNS2YKYK3LrTkpxRhoAiBatf +km4+UiL/6nskBhLuKkLLYTgA1VwrbnzSMjGWkJ8F9E9xsXrcK29eyCYhKJXETO5T +Npdk7Hl8qbbe8/a99XRxZzi/rcf5VjnQ3CmxE/+jV99efhrCyc1l0EwS04qfjUhA +mRVCPS3bpgPbKkCHe7TGXw== +-----END CERTIFICATE----- diff --git a/zefie_wtvp_minisrv/ServiceDeps/wtv-news/localserver_key.pem b/zefie_wtvp_minisrv/ServiceDeps/wtv-news/localserver_key.pem new file mode 100644 index 00000000..f16d54f5 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceDeps/wtv-news/localserver_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA3lH9XWgXr1m8rLPS2gDV/b5vUFSRiK+2JViVJq8CpLYSKqEo +I1l2t4Ui4gwejy/SemKvdXFfHDBUEzb4M9CynTzBQK72cuJ1hgEyXiqVFEA2Z3mL +q5DQSstx5I+/8p+QN5V93reusq9ALEGqEWI4j9kj5vGQr4/t8Ce0onflpsoNDIng +1uUBv4BRe/Gj4ewJpfwbKjHxxssUauQ0gJg971hy5jz306G5j+8EtOSQtcrLKcbu +ctoZhzf240aD9IjRlZwAQLWrS5FUHl53dfsF+kiU/rTDEuLx5fsMA0PKhEn+85IX +lEiKWas8zptecAxhGaxRv5ndaNzw1EFkIL/lrQIDAQABAoIBAH8A+aulrnom2okS +hW6ysYyugKq0VRtvva9iBnq92dW8iW4++E4Raqd2cDIQWFjWKfhubeu6o2nYFf+Q +FISNQaxfq8rG6NVCl37BKkPvMZELCclc/zQ4mzVPObYnhLEXBG0sgmZ8Klm7kf52 +WLBrmwJaOo9RCqWwpG3gUOnLcq8vhvqKEXRzqaHqPtWJEuU09FgXt55/8eydykvE +JqP9W1iLpwYgknSkC65QKxpWrKx1h9JbkKUzOx4H51WzR2qVDT3VVK+5J7LvonSI +p1eEDGH8g3kWp6T0qwaUTkVINS4hhg/l5XPEqKkTNayKIJeSrEkfgs0sL/D9cxTI +gswml6ECgYEA/E7RJa8xXDqthtw/Uxss5wfANquufBxl9c0Spp2M1SfMSXGTQ+SQ +6mUGsWdiFhv98vPVv4JDfjvOSonppG9+cd2+kSignCeEt33hMb6cgp9QpG0PC22C +B2JqWtN4YuS8D+Hms5ZwC1XSavXCD8gPspXlo6jM6Q/3fPZxZr+xvzkCgYEA4ZLV +rOwODiPRB3DL+Y01KJZQvHGbU9QRAjAfqpdJ6UagueKQB6I/GxCKwtZbG1l2RreM +vjhvDf8oWW4Oe+Ff9PXp/A4C42RbPKTKIUNLiDd+qVsn9yT2dypibb3W6pzLQru7 +gT72ERCwb/yAoIbwLSUpudarRxASOBiCxgJO5hUCgYAdQE4DHnKMjMj9b59v1SC5 +kC56qCDMhsZTXvkgk/d15u1KPn6iSmd6pUfHXYMDqS8h8Z8AWuvUQL7D6YVK6Rox +vVGQprMoJ3S9iTyIdd7TTgEdbv9lhcajcIeADDBS1s3u0XPbsj8/MS359JARIFKh +k7tR5AoNoypANJolHWhQEQKBgQC8iPV+6m109AqppWVW1ucvXTNtzaZ9kioFIiPV +eU2VZCrCMtMfDkSgYlsYLgFIAqYQxSkldBWeJT2cQZhpgh2pqEBBI5TWafK35SPs +WUqwN3HuKvpkXsiBITPTdXBD93kL9czqYa1Y5hISB4Gaqi3kDcOqR/owEwanTBVB +WnyHYQKBgQChNn7uvIIUzQKoxYyvXk5NVIb1xey64deOVnayg66s6oHF9UHtynay +equq5maSgyF3Ft597koiG7ylMkcXkdsmUPos26ZSDlgqYC9v+VopqQB3T06ltyGA +lOjjVjzofTSzMvQ1UFbDoogelpnZNn8koKrgrUuZL+A0VLEYQTFITg== +-----END RSA PRIVATE KEY----- diff --git a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/index.js b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/index.js index 5d5d2cc7..f31c7f7a 100644 --- a/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/index.js +++ b/zefie_wtvp_minisrv/ServiceVault/http_pc/viewergen/index.js @@ -49,8 +49,8 @@ function getPatchDataType(type, invert = false) { patch_data += "wtv-system-version: %s\r\n"; patch_data += "wtv-capability-flags: %s\r\n"; patch_data += "wtv-client-bootrom-version: %s\r\n"; - patch_data += "wtv-need-upgrade: %s\n"; - patch_data += "wtv-used-8675309: %s\n"; + patch_data += "wtv-need-upgrade: %s\r\n"; + patch_data += "wtv-used-8675309: %s\r\n"; patch_data += "wtv-client-rom-type: %s\r\n"; patch_data += "wtv-system-chipversion: %s\r\n"; patch_data += "User-Agent: %s\r\n"; @@ -192,7 +192,6 @@ function getPatchData(fname, client_data_obj, start_url = "client:GoToConn", def var customized_patch_data = patch_data[fname]; Object.keys(customized_patch_data).forEach(function (idx) { var val = customized_patch_data[idx]; - if (typeof val === 'string') { // start url override if (start_url != patch_defaults.start_url && start_url.length <= patch_limits.start_url) { @@ -209,7 +208,7 @@ function getPatchData(fname, client_data_obj, start_url = "client:GoToConn", def if (!val.byteLength) { // not a buffer object var block_length = val['length']; - var patch_data = getPatchDataType(val['type'], (fname.substr(12,3) != "1.1")); + var patch_data = getPatchDataType(val['type'], (fname.substr(12, 3) != "1.1")); if (patch_data) { var patch_data_array = patch_data.split("\r\n"); var patch_data_string = ""; @@ -365,6 +364,7 @@ if (request_headers.query.viewer && data: viewer_data, patch_data: getPatchData(viewer_file, client_data_obj) } + if (!patchDataObject.patch_data) { errpage = wtvshared.doErrorPage("500", null, socket.minisrv_pc_mode) headers = errpage[0]; diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js index 54eca96a..78341d1f 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-1800/preregister.js @@ -40,13 +40,16 @@ if (socket.ssid) { data = errpage[1]; } -if (request_headers.query.relogin && session_data.getSessionData("registered")) gourl += "relogin=true"; +if (request_headers.query.relogin && session_data.getSessionData("registered")) { + gourl += "relogin=true"; + session_data.setUserLoggedIn(false); +} if (request_headers.query.reconnect && session_data.getSessionData("registered")) gourl += "reconnect=true"; if (session_data.data_store.wtvsec_login) { var prereg_contype = "text/html"; - if (request_headers.query.relogin) { // relogin + if (request_headers.query.relogin || request_headers.query.guest_login) { // relogin session_data.data_store.wtvsec_login.ticket_b64 = null; // clear old ticket } @@ -55,7 +58,7 @@ if (session_data.data_store.wtvsec_login) { var file_path = null; var bf0app_update = false; var romtype = session_data.get("wtv-client-rom-type"); - var send_tellyscript = (minisrv_config.services[service_name].send_tellyscripts && !request_headers.query.relogin); + var send_tellyscript = (minisrv_config.services[service_name].send_tellyscripts && !request_headers.query.relogin && !request_headers.query.guest_login); var wtv_script_id = parseInt(session_data.get("wtv-script-id")); var bootrom = session_data.get("wtv-client-bootrom-version"); if ((request_headers.query.reconnect || request_headers.query.relogin) && wtv_script_id != 0) send_tellyscript = false; @@ -68,7 +71,6 @@ if (session_data.data_store.wtvsec_login) { } else { romtype = session_data.get("wtv-client-rom-type"); } - var file_path = null; switch (romtype) { case "US-LC2-disk-0MB-8MB": case "US-LC2-disk-0MB-8MB-softmodem-CPU5230": @@ -77,9 +79,8 @@ if (session_data.data_store.wtvsec_login) { case "US-WEBSTAR-disk-0MB-16MB-softmodem-CPU5230": prereg_contype = "text/tellyscript"; // if wtv-open-access: true then client expects OpenISP - if (session_data.get("wtv-open-access")) file_path = __dirname + "/" + - + "/wtv-1800/tellyscripts/LC2/LC2_OpenISP_56k.tok"; - else var file_path = ServiceDeps + "/wtv-1800/tellyscripts/LC2/LC2_WTV_18006138199.tok"; + if (session_data.get("wtv-open-access")) file_path = ServiceDeps + "/wtv-1800/tellyscripts/LC2/LC2_OpenISP_56k.tok"; + else file_path = ServiceDeps + "/wtv-1800/tellyscripts/LC2/LC2_WTV_18006138199.tok"; break; case "US-DTV-disk-0MB-32MB-softmodem-CPU5230": @@ -164,7 +165,7 @@ if (session_data.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 && !session_data.getSessionData("registered") && !session_data.lockdown) headers += getServiceString('wtv-register') + "\n"; + if (request_headers.query.reconnect && !session_data.isRegistered() && !session_data.lockdown) headers += getServiceString('wtv-register') + "\n"; if (!session_data.lockdown) headers += getServiceString('wtv-flashrom') + "\n"; if (bf0app_update) headers += "wtv-boot-url: " + gourl + "\n"; else { diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/admin.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/admin.js index 19dfde37..8dcdabb0 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/admin.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/admin.js @@ -21,7 +21,7 @@ if (auth === true) { - +

@@ -57,19 +57,19 @@ if (auth === true) { Grant Admin to SSID -Modify Admin for SSID +Polyzoot a User -Polyzoot a User +Modify Admin for SSID -Reload Config +Edit Config Restore Favs for User - +Reload Config diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/ban.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/ban.js index 00cf5837..43616e52 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/ban.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/ban.js @@ -47,7 +47,7 @@ wtv-expire-all: wtv-admin:/ban`; - +

${minisrv_config.config.service_name} Admin Tricks

diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/deleteaccount.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/deleteaccount.js index 2a8b5682..94177dfd 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/deleteaccount.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/deleteaccount.js @@ -39,7 +39,7 @@ wtv-noback-all: wtv-admin:/deleteaccount`; - +

${minisrv_config.config.service_name} Admin Tricks

diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/deleteuser.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/deleteuser.js index 5d96215f..d10326ba 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/deleteuser.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/deleteuser.js @@ -48,7 +48,7 @@ wtv-noback-all: wtv-admin:/deleteuser`; - +

${minisrv_config.config.service_name} Admin Tricks

diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/findaccount.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/findaccount.js index 96d63cac..6aed0b8b 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/findaccount.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/findaccount.js @@ -28,7 +28,7 @@ wtv-noback-all: wtv-admin:/findaccount`; - +

${minisrv_config.config.service_name} Admin Tricks

diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/operatortweaks.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/operatortweaks.js new file mode 100644 index 00000000..3e9e8117 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/operatortweaks.js @@ -0,0 +1,273 @@ +var minisrv_service_file = true; + +var WTVAdmin = require(classPath + "/WTVAdmin.js"); +var wtva = new WTVAdmin(minisrv_config, session_data, service_name); +var auth = wtva.isAuthorized(); + +function generateFormField(type, confvar, options = null) { + if (confvar.indexOf('.') > 0) { + var confvar_split = confvar.split('.'); + console.log(confvar_split) + // not operater error resistant, be mindful if you modify this page + if (user_config.config[confvar_split[0]]) + var confvar_value = user_config.config[confvar_split[0]][confvar_split[1]] || minisrv_config.config[confvar_split[0]][confvar_split[1]] + else + var confvar_value = minisrv_config.config[confvar_split[0]][confvar_split[1]]; + + confvar = confvar.replace(".", "-"); + } else + var confvar_value = user_config.config[confvar] || minisrv_config.config[confvar]; + + if (type == "input") + return `` + if (type == "checkbox") + return `\n` + if (type == "select") { + var out = `"; + } +} + +if (auth === true) { + var password = null; + if (request_headers.Authorization) { + var authheader = request_headers.Authorization.split(' '); + if (authheader[0] == "Basic") { + password = Buffer.from(authheader[1], 'base64').toString(); + if (password) password = password.split(':')[1]; + } + } + if (wtva.checkPassword(password)) { + var user_config = wtvshared.getUserConfig(); + headers = "200 OK\r\nContent-Type: text/html"; + data = ` + + +${minisrv_config.config.service_name} Operator Tweaks + + + + + + +
+
+

${minisrv_config.config.service_name} Operator Tweaks

+ +These settings can be updated without restarting minisrv +
+ + + + + + +
+
+
+ +
+service_owner
The name of the server +operator +
+service_owner_account
The minisrv account name of the server +operator +
+service_owner_contact
The email address or username of the +server operator where users can contact them +
+service_owner_
contact_method

The method by which the user can +contact the server operator (eg. email, Discord, Twitter, etc...) +
+service_name
The name of the service (eg. WebTV) +
+service_logo
The logo for the service. Filename only. Must exist in the SharedROMCache service vault. +
+service_splash_logo
The splash page logo for the service. Absolute path. Can be file:// or wtv url. +
+show_detailed_splash
Show service information and client connection speed on the splash page. +
+hide_ssid_in_logs
Filter SSIDs in console logs and log files. +
+filter_
passwords_in_logs

Filter passwords (if the form field contains 'pass') in console logs and log files. +
+verbosity
Console log debug level. +
+show_diskmap
Useful for debugging wtv-disk downloads. +
+allow_guests
Allows users to use the service without having to register. +Guest session data is destroyed upon logout, and some features are not available to guests. +
+enable_
lzpf_compression

Toggles whether LZPF compression will be considered or not +
+enable_
gzip_compression

Toggles whether GZIP compression will be considered or not +
+Max Users Per Account +
+Min Username Length +
+Max Username Length +
+Enable Passwords
+When disabled, accounts will not be able to use passwords, if they had a password set prior, the account will be accessible without it. +
+Min Password Length +
+Max Password Length +
+Password Field Size +The size of the field on the login password page +
+
+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+${generateFormField('input', 'service_owner')} +
+${generateFormField('input', 'service_owner_account')} +
+${generateFormField('input', 'service_owner_contact')} +
+${generateFormField('input', 'service_owner_contact_method')} +
+${generateFormField('input', 'service_name')} +
+${generateFormField('input', 'service_logo')} +
+${generateFormField('input', 'service_splash_logo')} +
+${generateFormField('checkbox', 'show_detailed_splash')} +
+${generateFormField('checkbox', 'hide_ssid_in_logs')} +
+${generateFormField('checkbox', 'filter_passwords_in_logs')} +
+${generateFormField('select', 'verbosity', [ + { "name": "Quiet (0)", value: 0 }, + { "name": "Show Headers (1)", value: 1 }, + { "name": "Verbose, without Headers (2)", value: 2 }, + { "name": "Verbose, with headers (3)", value: 3 }, + { "name": "Debug (4)", value: 4 }, +])} +
+${generateFormField('checkbox', 'show_diskmap')} +
+${generateFormField('checkbox', 'allow_guests')} +
+${generateFormField('checkbox', 'enable_lzpf_compression')} +
+${generateFormField('checkbox', 'enable_gzip_compression')} +
+${generateFormField('input', 'user_accounts.max_users_per_account', "size=2 onkeypress='return forceNumeric(event)' onchange='validateNumber(this,1,50,6)' maxlength=2")} +
+${generateFormField('input', 'user_accounts.min_username_length', "size=2 onkeypress='return forceNumeric(event)' onchange='validateNumber(this,3,50,5)' maxlength=2")} +
+${generateFormField('input', 'user_accounts.max_username_length', "size=2 onkeypress='return forceNumeric(event)' onchange='validateNumber(this,3,50,18)' maxlength=2")} +
+${generateFormField('checkbox', 'passwords.enabled', "onchange='passwordFieldToggle(this)'")} +
+${generateFormField('input', 'passwords.min_length', "size=2 onkeypress='return forceNumeric(event)' onchange='validateNumber(this,3,32,5)' maxlength=2")} +
+${generateFormField('input', 'passwords.max_length', "size=2 onkeypress='return forceNumeric(event)' onchange='validateNumber(this,3,256,32)' maxlength=2")} +
+${generateFormField('input', 'passwords.form_size', "size=2 onkeypress='return forceNumeric(event)' onchange='validateNumber(this,5,99,16)' maxlength=2")} +
+
+
+

+ +
+ + +
+ + +
+
+
+
+ + +`; + } else { + var errpage = wtvshared.doErrorPage(401, "Please enter the administration password, you can leave the username blank."); + headers = errpage[0]; + data = errpage[1]; + } +} else { + var errpage = wtvshared.doErrorPage(403, auth); + headers = errpage[0]; + data = errpage[1]; +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/polyzoot.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/polyzoot.js index 5ce97658..2c0c4d15 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/polyzoot.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/polyzoot.js @@ -58,7 +58,7 @@ wtv-noback-all: wtv-admin:/polyzoot`; - +

${minisrv_config.config.service_name} Admin Tricks

diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/regenfavs.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/regenfavs.js index 50446a1b..ee7d4f47 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/regenfavs.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/regenfavs.js @@ -39,7 +39,7 @@ wtv-noback-all: wtv-admin:/regenfavs`; - +

${minisrv_config.config.service_name} Admin Tricks

diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/reloadconfig.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/reloadconfig.js index f9b02c6f..163ac9ed 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/reloadconfig.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/reloadconfig.js @@ -25,7 +25,7 @@ wtv-noback-all: wtv-admin:/reloadconfig`; - +

${minisrv_config.config.service_name} Admin Tricks

diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/removeuserpasswd.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/removeuserpasswd.js index 81db23e9..1dadeb37 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/removeuserpasswd.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/removeuserpasswd.js @@ -44,7 +44,7 @@ wtv-noback-all: wtv-admin:/removeuserpasswd`; - +

${minisrv_config.config.service_name} Admin Tricks

diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/unban.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/unban.js index e9e7442b..2950864e 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/unban.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/unban.js @@ -56,7 +56,7 @@ wtv-expire-all: wtv-admin:/unban`; - +

${minisrv_config.config.service_name} Admin Tricks

diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-admin/validate-operator-tweaks.js b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/validate-operator-tweaks.js new file mode 100644 index 00000000..ec25ce06 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-admin/validate-operator-tweaks.js @@ -0,0 +1,48 @@ +var minisrv_service_file = true; + +var WTVAdmin = require(classPath + "/WTVAdmin.js"); +var wtva = new WTVAdmin(minisrv_config, session_data, service_name); +var auth = wtva.isAuthorized(); + +if (auth === true) { + var password = null; + if (request_headers.Authorization) { + var authheader = request_headers.Authorization.split(' '); + if (authheader[0] == "Basic") { + password = Buffer.from(authheader[1], 'base64').toString(); + if (password) password = password.split(':')[1]; + } + } + if (wtva.checkPassword(password)) { + var user_config = wtvshared.getUserConfig(); + Object.keys(request_headers.query).forEach((k) => { + if (k === "autosubmit") return; + var v = request_headers.query[k]; + if (!isNaN(parseInt(v))) v = parseInt(v); + if (v === "on" || v === "true" || v === "false") v = wtvshared.parseBool(v); + if (k.indexOf("-") > 0) { + var s = k.split("-"); + if (!user_config.config[s[0]]) user_config.config[s[0]] = {} + user_config.config[s[0]][s[1]] = v; + } else { + user_config.config[k] = v; + } + }); + var res = wtvshared.writeToUserConfig(user_config); + if (res) { + console.log(" * Configuration updated from wtv-admin, reloading") + reloadConfig(); + headers = "200 OK\nwtv-expire-all: wtv-admin:/operatortweaks\nContent-Type: text/html"; + } else { + err = wtvshared.doErrorPage(400, "Error writing userconfig"); + headers = err[0]; + data = err[1]; + } + } +} + +if (!headers) { + err = wtvshared.doErrorPage(); + headers = err[0]; + data = err[1]; +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/ValidateLogin.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/ValidateLogin.js index 7a321b17..323ad9f2 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/ValidateLogin.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/ValidateLogin.js @@ -9,13 +9,12 @@ if (request_headers.query.hangup) { Location: client:gototvhome wtv-visit: client:hangupphone` } else { - var user_id = (request_headers.query.user_id) ? request_headers.query.user_id : session_data.user_id; if (socket.ssid !== null && user_id !== null) session_data.switchUserID(user_id); if (socket.ssid !== null && !session_data.get("wtvsec_login")) { - wtvsec_login = new WTVSec(minisrv_config); + wtvsec_login = session_data.createWTVSecSession(); wtvsec_login.IssueChallenge(); wtvsec_login.set_incarnation(request_headers["wtv-incarnation"]); session_data.set("wtvsec_login", wtvsec_login); @@ -52,7 +51,7 @@ wtv-visit: client:hangupphone` if (request_headers.query.skip_splash) gourl += "&skip_splash=true"; } - if (user_id != null && !request_headers.query.initial_login && !request_headers.query.user_login) { + if (user_id != null && !request_headers.query.initial_login && !request_headers.query.user_login && !request_headers.query.relogin) { if (request_headers.query.password == "") { headers = `403 Please enter your password and try again minisrv-no-mail-count: true @@ -73,9 +72,10 @@ minisrv-no-mail-count: true if (session_data.baddisk === true) { gourl = "wtv-head-waiter:/bad-disk?" } - else if (session_data.getNumberOfUserAccounts() > 1 && user_id === 0 && request_headers.query.initial_login) { + else if (session_data.getNumberOfUserAccounts() > 1 && user_id === 0 && (request_headers.query.initial_login || request_headers.query.relogin)) { gourl = "wtv-head-waiter:/choose-user?" } else { + if (!session_data.getUserPasswordEnabled() && request_headers.query.user_login) session_data.setUserLoggedIn(true); var limitedLogin = (!session_data.lockdown && (!session_data.get('password_valid') && session_data.getUserPasswordEnabled())); var limitedLoginRegistered = (limitedLogin && session_data.isRegistered()); } @@ -89,7 +89,7 @@ Content-Type: text/html`; wtv-encrypted: true`; if (wtvsec_login) session_data.data_store.wtvsec_login.update_ticket = true; } - if (limitedLoginRegistered) gourl = "wtv-head-waiter:/password?"; + if (limitedLoginRegistered && session_data.getUserPasswordEnabled()) gourl = "wtv-head-waiter:/password?"; headers += ` wtv-visit: ${gourl}`; diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/choose-user.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/choose-user.js index f6bd3f3d..7668ec4e 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/choose-user.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/choose-user.js @@ -1,6 +1,9 @@ var minisrv_service_file = true; -if (socket.ssid !== null) session_data.switchUserID(0); +if (socket.ssid !== null) { + session_data.switchUserID(0); + session_data.setUserLoggedIn(false); +} headers = `200 OK minisrv-no-mail-count: true diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js index e74c4768..4618e857 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login-stage-two.js @@ -9,6 +9,8 @@ if (gourl) { wtv-open-isp-disabled: false `; if (!session_data.isRegistered() && (!request_headers.query.guest_login || !minisrv_config.config.allow_guests)) { + // fake logged in for reg + session_data.setUserLoggedIn(true); headers += `wtv-encrypted: true ${getServiceString('wtv-register')} ${getServiceString('wtv-head-waiter')} @@ -47,12 +49,13 @@ else { var gourl = "wtv-home:/splash?"; } var limitedLogin = session_data.lockdown; - var limitedLoginRegistered = (limitedLogin || (session_data.isRegistered() && !session_data.isUserLoggedIn())); + var limitedLoginRegistered = (limitedLogin || (session_data.isRegistered() && !session_data.isUserLoggedIn()) && session_data.getUserPasswordEnabled()); + if (!session_data.getUserPasswordEnabled()) session_data.setUserLoggedIn(true); var offline_user_list = null; if (session_data.isRegistered()) { // check for SMTP Password if (session_data.getSessionData("subscriber_smtp_password") === null) { - session_data.setUserSMTPPassword(session_data.generatePassword(16)); + session_data.setUserSMTPPassword(wtvshared.generatePassword(16)); } if (session_data.user_id == 0) { var accounts = session_data.listPrimaryAccountUsers(); diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js index 4351a0a4..4a971720 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/login.js @@ -4,47 +4,47 @@ session_data.setUserLoggedIn(false); var challenge_response, challenge_header = ""; if (socket.ssid !== null) session_data.switchUserID(0); -var gourl = "wtv-head-waiter:/ValidateLogin?initial_login=true&"; +var gourl = "wtv-head-waiter:/ValidateLogin?"; if (request_headers.query.relogin) gourl += "relogin=true"; else if (request_headers.query.reconnect) gourl += "reconnect=true"; +else gourl += "initial_login=true" if (request_headers.query.guest_login) { - if (request_headers.query.relogin || request_headers.query.reconnect) gourl += "&"; + if (gourl.substr(-1) != "?") gourl += "&"; gourl += "guest_login=true"; if (request_headers.query.skip_splash) gourl += "&skip_splash=true"; } var send_to_relogin = true; -if (socket.ssid) { - if (session_data) { - if (request_headers["wtv-ticket"]) { - if (session_data.data_store.wtvsec_login.ticket_b64 == null) { - if (request_headers["wtv-ticket"].length > 8) { - session_data.data_store.wtvsec_login.DecodeTicket(request_headers["wtv-ticket"]); - session_data.data_store.wtvsec_login.ticket_b64 = request_headers["wtv-ticket"]; - send_to_relogin = false; - } +if (session_data) { + if (request_headers["wtv-ticket"]) { + if (session_data.data_store.wtvsec_login.ticket_b64 == null) { + if (request_headers["wtv-ticket"].length > 8) { + session_data.data_store.wtvsec_login.DecodeTicket(request_headers["wtv-ticket"]); + session_data.data_store.wtvsec_login.ticket_b64 = request_headers["wtv-ticket"]; + send_to_relogin = false; } - } else { - if (session_data.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); - session_data.data_store.wtvsec_login.PrepareTicket(); - send_to_relogin = false; - } else { - challenge_header = "wtv-challenge: " + session_data.data_store.wtvsec_login.IssueChallenge(); - send_to_relogin = false; - } + } + } else { + if (session_data.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); + session_data.data_store.wtvsec_login.PrepareTicket(); + send_to_relogin = false; } else { challenge_header = "wtv-challenge: " + session_data.data_store.wtvsec_login.IssueChallenge(); send_to_relogin = false; } + } else { + challenge_header = "wtv-challenge: " + session_data.data_store.wtvsec_login.IssueChallenge(); + send_to_relogin = false; } } } + session_data.setUserLoggedIn(send_to_relogin); } if (!send_to_relogin) { @@ -66,7 +66,6 @@ Content-type: text/html`; data = ''; } else { - headers = `200 OK Connection: Keep-Alive Expires: Wed, 09 Oct 1991 22:00:00 GMT diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js index aa2f54e4..cd040a39 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-head-waiter/relogin.js @@ -1,4 +1,5 @@ var minisrv_service_file = true; + session_data.setUserLoggedIn(false); var gourl = "wtv-1800:/preregister?"; diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js b/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js index 56cf5f78..93b41609 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-home/home.js @@ -38,10 +38,10 @@ Content-type: text/html` - + - +
@@ -57,12 +57,12 @@ Content-type: text/html` - -
+
+
@@ -93,12 +93,12 @@ Content-type: text/html`
- -
+
+
@@ -131,12 +131,12 @@ Content-type: text/html`
- -
+
+
@@ -152,13 +152,13 @@ Content-type: text/html`
- +
- Tricks + Discuss
@@ -173,12 +173,12 @@ Content-type: text/html`
- -
+
+
@@ -214,12 +214,12 @@ Content-type: text/html` - -
+
+
@@ -230,7 +230,7 @@ Content-type: text/html`
- +
@@ -241,7 +241,7 @@ Content-type: text/html` -
+
@@ -264,7 +264,7 @@ Content-type: text/html`
- Mail + Mail
@@ -284,7 +284,7 @@ Content-type: text/html`
- Favorites + Favorites
@@ -304,7 +304,7 @@ Content-type: text/html`
- Flashroms + Flashroms
@@ -324,7 +324,7 @@ Content-type: text/html`
- Search + Search
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-home/images/BackgroundGradientEdge_dark.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-home/images/BackgroundGradientEdge_dark.gif new file mode 100644 index 00000000..05f19f4a Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-home/images/BackgroundGradientEdge_dark.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-home/images/BackgroundGradient_dark.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-home/images/BackgroundGradient_dark.gif new file mode 100644 index 00000000..56eb2bce Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-home/images/BackgroundGradient_dark.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-home/images/HomeBanner_dark.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-home/images/HomeBanner_dark.gif new file mode 100644 index 00000000..5adb8078 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-home/images/HomeBanner_dark.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-home/splash.js b/zefie_wtvp_minisrv/ServiceVault/wtv-home/splash.js index 179e0a34..b5e1d8e7 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-home/splash.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-home/splash.js @@ -10,7 +10,7 @@ data = ` Engaging zefie... - + diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-mail/DiplomaMail.js b/zefie_wtvp_minisrv/ServiceVault/wtv-mail/DiplomaMail.js index a7050a83..c96ee0fa 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-mail/DiplomaMail.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-mail/DiplomaMail.js @@ -78,7 +78,7 @@ choose this link: -
+ ") >= 0) { + data = wtvshared.sanitizeSignature(data).replace("", ``); + } else { + data = `\n${data}`; + } + if (request_headers.query.demotext) data += "
" + request_headers.query.demotext; } if (!errpage) { headers = `200 OK diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-mail/readmail.js b/zefie_wtvp_minisrv/ServiceVault/wtv-mail/readmail.js index afcd6b1f..863b1114 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-mail/readmail.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-mail/readmail.js @@ -274,8 +274,8 @@ ${(message.subject) ? wtvshared.htmlEntitize(message.subject) : '(No subject)'} if (typeof message.body === "object" && message.body) { message.body = wtvshared.decodeBufferText(message.body); } - data += ` -${wtvshared.htmlEntitize(message.body, true)} + message.body = message.body.replace(/\n/g, "

"); + data += `${(message.allow_html) ? message.body : wtvshared.htmlEntitize(message.body, true)}

`; if (message.signature) { @@ -283,7 +283,8 @@ ${wtvshared.htmlEntitize(message.body, true)} } data += `

`; - if (message.attachments) { + console.log(message.allow_html) + if (Array.isArray(message.attachments)) { message.attachments.forEach((v, k) => { if (v) { console.log("*****************", v['Content-Type']); diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-mail/sendmail.js b/zefie_wtvp_minisrv/ServiceVault/wtv-mail/sendmail.js index a0937710..b0509cd3 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-mail/sendmail.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-mail/sendmail.js @@ -1,11 +1,33 @@ var minisrv_service_file = true; + var message_snapshot_data = null; var message_voicemail_data = null; - var intro_seen = session_data.mailstore.checkMailIntroSeen(); if (!intro_seen && !request_headers.query.intro_seen) { // user is trying to bypass the intro screen - headers = "300 OK\nLocation: wtv-mail:/DiplomaMail"; + headers = "300 OK\nLocation: wtv-mail:/DiplomaMail?came-from=" + encodeURIComponent(request_headers.request_url); +} else if (request_headers.query.clear == "true") { + if (request_headers.Referer) + gourl = request_headers.Referer.replace(/[\?\&]clear\=true/, ''); + else + gourl = "wtv-mail:/sendmail" + if (request_headers.query.saveoff) delete request_headers.query.saveoff; + session_data.deleteSessionData("usenet_draft"); + session_data.deleteSessionData("usenet_draft_attachments"); + session_data.deleteSessionData("mail_draft"); + session_data.deleteSessionData("mail_draft_attachments"); + if (request_headers.query.message_to) delete request_headers.query.message_to; + if (request_headers.query.message_subject) delete request_headers.query.message_subject; + if (request_headers.query.message_body) delete request_headers.query.message_body; + if (request_headers.query.message_url) delete request_headers.query.message_url; + if (request_headers.query.message_title) delete request_headers.query.message_title; + if (request_headers.query.message_reply_all_cc) delete request_headers.query.message_reply_all_cc; + if (request_headers.query['wtv-saved-message-id']) delete request_headers.query['wtv-saved-message-id']; + + headers = `300 OK +wtv-expire-all: wtv-mail:/listmail +wtv-expire-all: wtv-mail:/sendmail +Location: ${gourl}`; } else { var doClientError = function (msg) { var clientErrorMsg = new clientShowAlert({ @@ -19,46 +41,66 @@ if (!intro_seen && !request_headers.query.intro_seen) { return "200 OK\nwtv-visit: " + clientErrorMsg; } - if (request_headers.query.clear == "true") { - session_data.deleteSessionData("mail_draft"); - session_data.deleteSessionData("mail_draft_attachments"); - headers = `300 OK -wtv-expire: wtv-mail:/listmail -wtv-expire: wtv-mail:/sendmail -Location: wtv-mail:/sendmail`; - } - var newsgroup = null; if (wtvshared.parseBool(request_headers.query.discuss)) { newsgroup = request_headers.query.group || request_headers.query.message_to || null; } + var gourl = "wtv-mail:/sendmail"; + var msg_subject, to_addr, to_name; + if (newsgroup !== null) { var to_addr = newsgroup; var pageTitle = "Post to " + newsgroup; + var article = request_headers.query.article || null; + var gourl = gourl + "?group=" + newsgroup; + } else { var to_addr = request_headers.query.message_to || null; - var pageTitle = "Write an e-mail message" + var pageTitle = "Write an e-mail message"; + if (request_headers.query.message_reply_id) { + reply_message = session_data.mailstore.getMessageByID(request_headers.query.message_reply_id); + if (reply_message) { + msg_subject = "Re: " + reply_message.subject; + to_addr = reply_message.to_addr; + to_name = reply_message.to_name; + } + } } - var msg_subject = request_headers.query.message_subject || null; + var msg_subject = msg_subject || request_headers.query.message_subject || null; var msg_body = request_headers.query.message_body || null; - var to_name = request_headers.query.whatever_webtv_sends_this_as || null; + var to_name = to_name || request_headers.query.whatever_webtv_sends_this_as || null; var msg_url = request_headers.query.message_url || null; var msg_url_title = request_headers.query.message_title || null; var no_signature = false; - var mail_draft_data = session_data.getSessionData("mail_draft"); - var mail_draft_attachments = session_data.getSessionData("mail_draft_attachments") || {}; - if (mail_draft_data) { - session_data.deleteSessionData("mail_draft"); - if (mail_draft_data.to_addr) to_addr = mail_draft_data.to_addr; - if (mail_draft_data.msg_subject) msg_subject = mail_draft_data.msg_subject; - if (mail_draft_data.msg_body) msg_body = mail_draft_data.msg_body; - if (mail_draft_data.no_signature) no_signature = mail_draft_data.no_signature; - if (mail_draft_data.msg_url) msg_url = mail_draft_data.msg_url; - if (mail_draft_data.msg_url_title) msg_url_title = mail_draft_data.msg_url_title; - if (mail_draft.data.newsgroup) newsgroup = mail_draft_data.newsgroup; + + mail_draft_data = {}; + mail_draft_attachments = {}; + if (!wtvshared.parseBool(request_headers.query.discuss)) { + mail_draft_data = session_data.getSessionData("mail_draft"); + mail_draft_attachments = session_data.getSessionData("mail_draft_attachments") || {}; + if (mail_draft_data && !wtvshared.parseBool(request_headers.query.discuss)) { + session_data.deleteSessionData("mail_draft"); + if (mail_draft_data.to_addr) to_addr = request_headers.query.message_to || mail_draft_data.to_addr; + if (mail_draft_data.msg_subject) msg_subject = request_headers.query.message_subject || mail_draft_data.msg_subject; + if (mail_draft_data.msg_body) msg_body = request_headers.query.message_body || mail_draft_data.msg_body; + if (mail_draft_data.no_signature) no_signature = mail_draft_data.no_signature; + if (mail_draft_data.msg_url) msg_url = request_headers.query.message_url || mail_draft_data.msg_url; + if (mail_draft_data.msg_url_title) msg_url_title = request_headers.query.message_title || mail_draft_data.msg_url_title; + } + } else { + mail_draft_data = session_data.getSessionData("usenet_draft"); + mail_draft_attachments = session_data.getSessionData("usenet_draft_attachments") || {}; + if (mail_draft_data && !wtvshared.parseBool(request_headers.query.discuss)) { + session_data.deleteSessionData("usenet_draft"); + if (mail_draft_data.to_addr) to_addr = request_headers.query.message_to || mail_draft_data.to_addr; + if (mail_draft_data.msg_subject) msg_subject = request_headers.query.message_subject || mail_draft_data.msg_subject; + if (mail_draft_data.msg_body) msg_body = request_headers.query.message_body || mail_draft_data.msg_body; + if (mail_draft_data.no_signature) no_signature = mail_draft_data.no_signature; + if (mail_draft_data.article) article = article || mail_draft_data.article; + } } if (request_headers.query.togglesign == "true") no_signature = false; @@ -100,80 +142,114 @@ Content-Type: audio/wav`; if (message_snapshot_data) { - if (typeof message_snapshot_data == "object") { - attachments.push({ 'Content-Type': 'image/jpeg', data: new Buffer.from(message_snapshot_data).toString('base64') }); - } else { - attachments.push({ 'Content-Type': 'image/jpeg', data: message_snapshot_data }); + var attachment = { + 'Content-Type': 'image/jpeg', + 'filename': 'snapshot.jpg' } + if (typeof message_snapshot_data == "object") { + attachment.data = new Buffer.from(message_snapshot_data).toString('base64'); + attachment.is_base64 = true; + } else + attachment.data = message_snapshot_data; + + attachments.push(attachment); } if (message_voicemail_data) { - if (typeof message_voicemail_data == "object") { - attachments.push({ 'Content-Type': 'audio/wav', data: new Buffer.from(message_voicemail_data).toString('base64') }); - } else { - attachments.push({ 'Content-Type': 'audio/wav', data: new message_voicemail_data }); + var attachment = { + 'Content-Type': 'audio/wav', + 'filename': 'voicemail.wav' } - } - if (newsgroup !== null) { - var request_is_async = true; - if (msg_body === null) { - headers = doClientError("Please type a message to send to the group."); - sendToClient(socket, headers, ''); - } else { - const Client = require('newsie').default - const client = new Client({ - host: minisrv_config.services[request_headers.query['discuss-prefix'] || "wtv-news"].upstream_address, - port: minisrv_config.services[request_headers.query['discuss-prefix'] || "wtv-news"].upstream_port - }) - client.connect() - .then(response => { - return client.post() - }) - .then(response => { - if (response.code == 340) { - var articleData = {}; - articleData.headers = { - 'Relay-Version': "version zefie_wtvp_minisrv " + minisrv_config.version + "; site " + minisrv_config.config.domain_name, - 'Posting-Version': "version zefie_wtvp_minisrv " + minisrv_config.version + "; site " + minisrv_config.config.domain_name, - 'Path': "@" + minisrv_config.config.domain_name, - 'From': from_addr, - 'Newsgroups': newsgroup, - 'Subject': msg_subject || "(No subject)", - 'Message-ID': "<"+session_data.generatePassword(16) + "@" + minisrv_config.config.domain_name+">", - 'Date': strftime('%A, %d-%b-%y %k:%M:%S %z', new Date()) - } - if (msg_body) { - articleData.body = msg_body.split("\n"); - } else { - articleData.body = []; - } - return response.send(articleData); - } else { - headers = doClientError("Could not send post. Server returned error " + response.code); - sendToClient(socket, headers, ''); - return client.quit(); - } - }) - .then(response => { - if (response.code !== 240) { - headers = doClientError("Could not send post. Server returned error " + response.code); - sendToClient(socket, headers, ''); - } else { - headers = `300 OK -wtv-expire: wtv-news:/news?group=${newsgroup} -wtv-expire: wtv-mail:/sendmail -Location: wtv-news:/news?group=${newsgroup}`; - sendToClient(socket, headers, ''); - return client.quit() - } - }).catch(e => { - console.log('usenet upstream uncaught error', e); - headers = doClientError("Could not send post. Server returned unknown error"); - - sendToClient(socket, headers, ''); - }); + if (typeof message_voicemail_data == "object") { + attachment.data = new Buffer.from(message_voicemail_data).toString('base64'); + attachment.is_base64 = true; + } else + attachment.data = message_voicemail_data; + + attachments.push(attachment); + } + + if (newsgroup !== null) { + var request_is_async = true; + var local_service_name = request_headers.query['discuss-prefix'] || "wtv-news" + const wtvnews = new WTVNews(minisrv_config, local_service_name); + var service_config = minisrv_config.services[local_service_name]; + if (wtvnewsserver) { + var tls_path = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + '/wtv-news'); + var tls_options = { + ca: this.fs.readFileSync(tls_path + '/localserver_ca.pem'), + key: this.fs.readFileSync(tls_path + '/localserver_key.pem'), + cert: this.fs.readFileSync(tls_path + '/localserver_cert.pem'), + checkServerIdentity: () => { return null; } + } + if (wtvnewsserver.username) + wtvnews.initializeUsenet("127.0.0.1", service_config.local_nntp_port, tls_options, wtvnewsserver.username, wtvnewsserver.password); + else + wtvnews.initializeUsenet("127.0.0.1", service_config.local_nntp_port, tls_options); + } else { + if (service_config.upstream_auth) + wtvnews.initializeUsenet(service_config.upstream_address, service_config.upstream_port, service_config.upstream_tls || null, service_config.upstream_auth.username || null, service_config.upstream_auth.password || null); + else + wtvnews.initializeUsenet(service_config.upstream_address, service_configupstream_port, service_config.upstream_tls || null); } + from_addr = userdisplayname + " <" + from_addr + ">"; + news_headers = null; + if (signature && signature != "" && !no_signature) { + var signature_tuple = null; + if (signature.indexOf('') >= 0) { + attachments.push({ + "Content-Type": 'text/html', + "data": signature, + "use_base64": false, + "filename": "wtv_signature.html" + }); + } else { + if (msg_body) msg_body += "\n" + signature; + else msg_body = signature; + } + } + + if (attachments.length > 0) { + // usenet attachments + var tuples = [{ + "mime": 'text/plain', + "content": msg_body || '', + "use_base64": false + }]; + if (signature_tuple) tuples.push(signature_tuple); + attachments.forEach((attachment) => { + var tuple = {}; + tuple.mime = attachment['Content-Type']; + tuple.content = attachment.data; + tuple.use_base64 = (typeof attachment.use_base64 === 'boolean') ? attachment.use_base64 : true; + tuple.is_base64 = (typeof attachment.is_base64 === 'boolean') ? attachment.is_base64 : false; + tuple.filename = attachment.filename || null; + tuples.push(tuple); + }); + var multipart_data = wtvmime.generateMultipartMIME(tuples); + news_headers = { + "Content-Type": multipart_data.content_type, + "MIME-Version": multipart_data.mime_version, + "User-Agent": minisrv_version_string + " for WebTV", + "Content-Language": "en-US" + } + msg_body = multipart_data.content.toString(); + } + wtvnews.postToGroup(newsgroup, from_addr, msg_subject, msg_body, article, news_headers).then(() => { + session_data.deleteSessionData("usenet_draft"); + session_data.deleteSessionData("usenet_draft_attachments"); + headers = `300 OK +wtv-expire-all: wtv-news:/news?group=${newsgroup} +wtv-expire-all wtv-mail:/sendmail +Location: wtv-news:/news?group=${newsgroup}`; + sendToClient(socket, headers, ''); + }).catch((e) => { + var err = this.wtvshared.doErrorPage(500, null, e.toString()) + sendToClient(socket, err[0], err[1]); + }); + + } else { var messagereturn = session_data.mailstore.sendMessageToAddr(from_addr, to_addr, msg_body, msg_subject, userdisplayname, to_name, signature, attachments, msg_url, msg_url_title); if (messagereturn !== true) { @@ -184,8 +260,8 @@ Location: wtv-news:/news?group=${newsgroup}`; session_data.deleteSessionData("mail_draft"); session_data.deleteSessionData("mail_draft_attachments"); headers = `300 OK -wtv-expire: wtv-mail:/listmail -wtv-expire: wtv-mail:/sendmail +wtv-expire-all: wtv-mail:/listmail +wtv-expire-all: wtv-mail:/sendmail Location: wtv-mail:/listmail`; } } @@ -198,38 +274,38 @@ Location: wtv-mail:/listmail`; no_signature: no_signature, msg_url: msg_url, msg_url_title: msg_url_title, - newsgroup: newsgroup } - session_data.setSessionData("mail_draft", mail_draft_data); + if (newsgroup) mail_draft_data.article = article; + session_data.setSessionData((newsgroup) ? "usenet_draft" : "mail_draft", mail_draft_data); headers = `200 OK Content-type: text/html -wtv-expire: wtv-mail:/sendmail`; +wtv-expire-all: wtv-mail:/sendmail`; } } else { headers = `200 OK Content-type: text/html`; - var mail_draft_data = session_data.getSessionData("mail_draft_attachments") || {}; + var mail_draft_data = session_data.getSessionData((newsgroup) ? "usenet_draft_attachments" : "mail_draft_attachments") || {}; if (request_headers.query.snapping == "false") { - headers += "\nwtv-expire: cache:snapshot.jpg"; + headers += "\nwtv-expire-all: cache:snapshot.jpg"; if (mail_draft_data.message_snapshot_data) mail_draft_data.message_snapshot_data = null; - session_data.setSessionData("mail_draft_attachments", mail_draft_data); + session_data.setSessionData((newsgroup) ? "usenet_draft_attachments" : "mail_draft_attachments", mail_draft_data); } if (request_headers.query.gabbing == "false") { - headers += "\nwtv-expire: cache:voicemail.wav"; + headers += "\nwtv-expire-all: cache:voicemail.wav"; if (mail_draft_data.message_voicemail_data) mail_draft_data.message_voicemail_data = null; - session_data.setSessionData("mail_draft_attachments", mail_draft_data); + session_data.setSessionData((newsgroup) ? "usenet_draft_attachments" : "mail_draft_attachments", mail_draft_data); } if (request_headers.query.message_snapshot_data) { mail_draft_data.message_snapshot_data = request_headers.query.message_snapshot_data - session_data.setSessionData("mail_draft_attachments", mail_draft_data); + session_data.setSessionData((newsgroup) ? "usenet_draft_attachments" : "mail_draft_attachments", mail_draft_data); } if (request_headers.query.message_voicemail_data) { mail_draft_data.message_voicemail_data = request_headers.query.message_voicemail_data - session_data.setSessionData("mail_draft_attachments", mail_draft_data); + session_data.setSessionData((newsgroup) ? "usenet_draft_attachments" : "mail_draft_attachments", mail_draft_data); } var message_colors = null; if (no_signature) message_colors = session_data.mailstore.getSignatureColors(null, true); @@ -267,6 +343,10 @@ function DoneGabbing() { var myURL; myURL = "client:submitform?name=sendform&submitname=gabbing&submitvalue=cache%3Avoicemail.wav"; location = "client:submitform?name=sendform&submitname=gabbing&submitvalue=true"; location.reload(); } +function clearDraft() { + location = "client:submitform?name=sendform&submitname=clear&submitvalue=true"; + location.reload(); +} ${pageTitle} @@ -276,8 +356,9 @@ ${pageTitle} <form action="wtv-mail:/sendmail#focus" method="post" name=sendform > <input type=hidden name="wtv-saved-message-id" value="writemessage-outbox"> <input type=hidden name="message_reply_all_cc" value=""> +${(request_headers.query.article) ? `<input type="hidden" name="article" value="${request_headers.query.article}">` : ''} <input type=hidden name="saveoff" value="true" autosubmit="onleave"> -<input type=hidden name="discuss" value="${request_headers.query.discuss ? true : false}"> +<input type=hidden name="discuss" value="${wtvshared.parseBool(request_headers.query.discuss)}"> <sidebar width=109> <table cellspacing=0 cellpadding=0> <tr> @@ -300,12 +381,22 @@ ${pageTitle} <tr> <td width=10 height=26> <td width=89 valgn=middle> -<table cellspacing=0 cellpadding=0 href="wtv-mail:/listmail" > -<tr> +<table cellspacing=0 cellpadding=0 href="` + if (newsgroup) { + data += "wtv-news:/news?group=" + newsgroup; + } else { + data += "wtv-mail:/listmail"; + } +data += `"><tr> <td height=1> -<tr> -<td><shadow><font sizerange=medium color=#E6CD4A>Mail list</font></shadow> -</table>`; +<tr>`; + if (newsgroup) { + data += `<td><shadow><font sizerange=medium color=#E6CD4A>Group list</font></shadow>`; + } else { + data += `<td><shadow><font sizerange=medium color=#E6CD4A>Mail list</font></shadow>`; + } + +data += `</table>`; if (!newsgroup) { data += ` <td width=5> @@ -349,7 +440,7 @@ data += ` <tr> <td width=10 height=26> <td width=89 valgn=middle> -<table cellspacing=0 cellpadding=0 href="client:showalert?sound=none&message=Are%20you%20sure%20you%20want%20to%20erase%20this%20entire%20message%3F&buttonlabel2=Don't%20Erase&buttonaction2=client:donothing&buttonlabel1=Erase&buttonaction1=wtv-mail:/sendmail%3Fclear%3Dtrue%26wtv-saved-message-id%3Dwritemessage-outbox" id=addressbook> +<table cellspacing=0 cellpadding=0 href="client:showalert?sound=none&message=Are%20you%20sure%20you%20want%20to%20erase%20this%20entire%20message%3F&buttonlabel2=Don't%20Erase&buttonaction2=client:donothing&buttonlabel1=Erase&buttonaction1=javascript:clearDraft()" id=addressbook> <tr> <td height=1> <tr> @@ -600,7 +691,7 @@ USESTYLE NOARGS> data += ` </td></tr><tr> <td colspan="2" align="center"> -<img src="${(mail_draft_attachments.message_snapshot_data) ? 'wtv-mail:/sendmail?get_snap=true' : 'cache:snapshot.jpg'}" width="380" height="290"> +<img src="${(mail_draft_attachments.message_snapshot_data) ? 'wtv-mail:/sendmail?get_snap=true' : (request_headers.query.message_snapshot_url) ? request_headers.query.message_snapshot_url : 'cache:snapshot.jpg'}" width="380" height="290"> </td></tr><tr> <td colspan="2" abswidth="386" absheight="10"> </td></tr><tr> diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-news/get-attachment.js b/zefie_wtvp_minisrv/ServiceVault/wtv-news/get-attachment.js new file mode 100644 index 00000000..3913cd11 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-news/get-attachment.js @@ -0,0 +1,69 @@ +var minisrv_service_file = true; + +var request_is_async = true; +var errpage = null; +var group = request_headers.query.group; +var article = request_headers.query.article; +var attachment_id = parseInt(request_headers.query.attachment_id); +if ((!attachment_id && attachment_id != 0) || !group || !article) { + errpage = wtvshared.doErrorPage(400, "Attachment ID required."); + sendToClient(socket, errpage[0], errpage[1]); +} else { + const wtvnews = new WTVNews(minisrv_config, service_name); + var service_config = minisrv_config.services[service_name]; + if (service_config.local_nntp_port && wtvnewsserver) { + var tls_path = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + '/wtv-news'); + var tls_options = { + ca: this.fs.readFileSync(tls_path + '/localserver_ca.pem'), + key: this.fs.readFileSync(tls_path + '/localserver_key.pem'), + cert: this.fs.readFileSync(tls_path + '/localserver_cert.pem'), + checkServerIdentity: () => { return null; } + } + if (wtvnewsserver.username) + wtvnews.initializeUsenet("127.0.0.1", service_config.local_nntp_port, tls_options, wtvnewsserver.username, wtvnewsserver.password); + else + wtvnews.initializeUsenet("127.0.0.1", service_config.local_nntp_port, tls_options); + } else { + if (service_config.upstream_auth) + wtvnews.initializeUsenet(service_config.upstream_address, service_config.upstream_port, service_config.upstream_tls || null, service_config.upstream_auth.username || null, service_config.upstream_auth.password || null); + else + wtvnews.initializeUsenet(service_config.upstream_address, service_config.upstream_port, service_config.upstream_tls || null); + } + var article = parseInt(article); + wtvnews.connectUsenet().then(() => { + wtvnews.selectGroup(group).then((response) => { + wtvnews.getArticle(article).then((response) => { + wtvnews.quitUsenet(); + if (response.code == 220) { + var message_data = wtvnews.parseAttachments(response); + if (message_data.attachments) { + if (attachment_id < message_data.attachments.length) { + var attachment = message_data.attachments[attachment_id]; + var encoding = attachment.content_encoding.toLowerCase() + if (encoding == 'base64') { + data = Buffer.from(attachment.data, encoding); + headers = "200 OK\n" + headers += "Content-Type: " + attachment.content_type + "\n"; + if (attachment.filename) headers += "Content-Disposition: attachment; filename=\"" + attachment.filename + "\"\n"; + sendToClient(socket, headers, data); + } else { + errpage = wtvshared.doErrorPage(400, "Unimplemented encoding type:", encoding); + sendToClient(socket, errpage[0], errpage[1]); + } + + } else { + errpage = wtvshared.doErrorPage(400, "Attachment ID exceeds available attachments"); + sendToClient(socket, errpage[0], errpage[1]); + } + } else { + errpage = wtvshared.doErrorPage(400, "Article does not contain attachments."); + sendToClient(socket, errpage[0], errpage[1]); + } + } else { + errpage = wtvshared.doErrorPage(400); + sendToClient(socket, errpage[0], errpage[1]); + } + }); + }); + }); +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListLeftEdge.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListLeftEdge.gif new file mode 100644 index 00000000..d4499d26 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListLeftEdge.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListNext.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListNext.gif new file mode 100644 index 00000000..f886677c Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListNext.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListNext_D.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListNext_D.gif new file mode 100644 index 00000000..955d3bb6 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListNext_D.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListPrevious.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListPrevious.gif new file mode 100644 index 00000000..0324abcc Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListPrevious.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListPrevious_D.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListPrevious_D.gif new file mode 100644 index 00000000..e85edac2 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListPrevious_D.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListRightEdge.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListRightEdge.gif new file mode 100644 index 00000000..9a13a3d8 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/ListRightEdge.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/news_logo.gif b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/news_logo.gif new file mode 100644 index 00000000..546dfc82 Binary files /dev/null and b/zefie_wtvp_minisrv/ServiceVault/wtv-news/images/news_logo.gif differ diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-news/lobby.js b/zefie_wtvp_minisrv/ServiceVault/wtv-news/lobby.js index 488f5788..1c1b3d44 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-news/lobby.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-news/lobby.js @@ -1,5 +1,7 @@ var minisrv_service_file = true; +// max of 6, any more will be ignored + headers = `200 OK Connection: Keep-Alive Content-Type: text/html` @@ -35,7 +37,7 @@ data = `<HTML> <tr> <td abswidth=6 > <td abswidth=93 absheight=26 > -<table href="wtv-news:news?category=1" +<table href="wtv-news:/news?category=1" cellspacing=0 cellpadding=0> <tr> <td abswidth=5> @@ -82,7 +84,8 @@ cellspacing=0 cellpadding=0> <img src="wtv-home:/ROMCache/Spacer.gif" width=1 height=1> <tr> <td colspan=3 height=237 valign=bottom align=right > -<img src="wtv-forum:/images/BannerDiscuss.gif" width=50 height=165> <tr><td colspan=3 absheight=36> +<img src="wtv-news:/images/BannerDiscuss.gif" width=50 height=165> +<tr><td colspan=3 absheight=36> </table> </sidebar> <body @@ -103,27 +106,26 @@ Featured discussions <td abswidth=20> <tr> <td> -<td WIDTH=198 HEIGHT=200 VALIGN=top ALIGN=left> -<a href="wtv-news:/news?group=webtv.users"><b>WebTV</b></a><br> -A moderated discussion with WebTV customers<br> -<IMG SRC="wtv-home:/ROMCache/Spacer.gif" WIDTH=1 HEIGHT=18><BR> -<a href="wtv-news:/news?group=alt.discuss.webtv.hacking"><b>Hacking</b></a><br> -Not grandma friendly<br> -<IMG SRC="wtv-home:/ROMCache/Spacer.gif" WIDTH=1 HEIGHT=18><BR> -<a href="wtv-news:/news?group=rec.autos.4x4"><b>4x4s</b></a><br> -The on and off-road four wheel drive vehicle<br> -<IMG SRC="wtv-home:/ROMCache/Spacer.gif" WIDTH=1 HEIGHT=18><BR> -<td WIDTH=20> -<td WIDTH=198 HEIGHT=220 VALIGN=top ALIGN=left> -<a href="wtv-news:/news?group=webtv.plus"><b>WebTV Plus</b></a><br> -bf0 is for bitches and BPS is boring<br> -<IMG SRC="wtv-home:/ROMCache/Spacer.gif" WIDTH=1 HEIGHT=18><BR> -<a href="wtv-news:/news?group=alt.discuss.midis"><b>MIDIs</b></a><br> -The best music format<br> -<IMG SRC="wtv-home:/ROMCache/Spacer.gif" WIDTH=1 HEIGHT=18><BR> -<a href="wtv-news:/news?group=alt.discuss.html"><b>HTML</b></a><br> -Every timeline starts with HTML<br> -<IMG SRC="wtv-home:/ROMCache/Spacer.gif" WIDTH=1 HEIGHT=18><BR> +<td WIDTH=198 HEIGHT=200 VALIGN=top ALIGN=left>`; + +var featuredGroups = minisrv_config.services[service_name].featuredGroups; +var limit = 6; +while (featuredGroups.length > limit) featuredGroups.pop(); // remove anything passing our limit + +function printGroup(group) { + return `<a href="wtv-news:/news?group=${group.group}"><b>${group.name}</b></a><br>${group.description}<br><IMG SRC="wtv-home:/ROMCache/Spacer.gif" WIDTH=1 HEIGHT=18><BR>`; +} + +// evens +Object.keys(featuredGroups).forEach((k) => { if (k % 2 == 0) { data += printGroup(featuredGroups[k]); } }); + +if (featuredGroups.length > 1) data += `<td WIDTH=20><td WIDTH=198 HEIGHT=220 VALIGN=top ALIGN=left>`; + +// odds +Object.keys(featuredGroups).forEach((k) => { if (k % 2 != 0) data += printGroup(featuredGroups[k]); }); + + +data += ` </table> <TABLE width=446 cellspacing=0 cellpadding=0> <tr> @@ -145,7 +147,7 @@ Every timeline starts with HTML<br> <td abswidth=416 valign=top align=left> Type a discussion topic<br> <img src="/ROMCache/Spacer.gif" width=1 height=4> -<form action="wtv-news:search"> +<form action="wtv-news:/news" method="GET"> <input name="search" bgcolor=#202020 cursor=#cc9933 text="E7CE4A" font=proportional value="" SIZE=28 MAXLENGTH=100>   <font color=E7CE4A><shadow> diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-news/news.js b/zefie_wtvp_minisrv/ServiceVault/wtv-news/news.js index 562dffdf..f484a392 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-news/news.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-news/news.js @@ -1,22 +1,61 @@ var minisrv_service_file = true; -console.log('f') - +const wtvnews = new WTVNews(minisrv_config, service_name); +var service_config = minisrv_config.services[service_name]; +if (service_config.local_nntp_port && wtvnewsserver) { + var tls_path = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + '/wtv-news'); + var tls_options = { + ca: this.fs.readFileSync(tls_path + '/localserver_ca.pem'), + key: this.fs.readFileSync(tls_path + '/localserver_key.pem'), + cert: this.fs.readFileSync(tls_path + '/localserver_cert.pem'), + checkServerIdentity: () => { return null; } + } + if (wtvnewsserver.username) + wtvnews.initializeUsenet("127.0.0.1", service_config.local_nntp_port, tls_options, wtvnewsserver.username, wtvnewsserver.password); + else + wtvnews.initializeUsenet("127.0.0.1", service_config.local_nntp_port, tls_options); +} else { + if (service_config.upstream_auth) + wtvnews.initializeUsenet(service_config.upstream_address, service_config.upstream_port, service_config.upstream_tls || null, service_config.upstream_auth.username || null, service_config.upstream_auth.password || null); + else + wtvnews.initializeUsenet(service_config.upstream_address, service_config.upstream_port, service_config.upstream_tls || null); +} + async function throwError(e) { + console.log(e); var errpage = wtvshared.doErrorPage(400, null, e.toString()); sendToClient(socket, errpage[0], errpage[1]); } +function isToday (chkdate) { + const today = new Date() + return chkdate.getDate() == today.getDate() && + chkdate.getMonth() == today.getMonth() && + chkdate.getFullYear() == today.getFullYear() +} async function WebTVListGroup(group) { + var page_limit_default = 100; wtvnews.connectUsenet().then(() => { - wtvnews.selectGroup(group).then(() => { - wtvnews.listGroup(group).then((response) => { + wtvnews.selectGroup(group).then((response) => { + var limit_per_page = (request_headers.query.limit) ? parseInt(request_headers.query.limit) : page_limit_default; + var page = (request_headers.query.chunk) ? parseInt(request_headers.query.chunk) : 0; + console.log(response); + var page_start = (limit_per_page * page) + 1; + var page_end = (page + 1) * limit_per_page; + if (page_end > response.group.high) { + page_end = response.group.high; + limit_per_page = (page_end - (limit_per_page / (page + 1))) + limit_per_page; + } + + wtvnews.listGroup(group, page, limit_per_page).then((response) => { if (response.code == 211) { NGCount = response.group.number; NGArticles = response.group.articleNumbers; - + page_start = (limit_per_page * page) + 1; + page_end = (page + 1) * limit_per_page; wtvnews.getHeaderObj(NGArticles).then((messages) => { + messages = wtvnews.sortByResponse(messages); wtvnews.quitUsenet(); headers = `200 OK Connection: Keep-Alive @@ -30,6 +69,7 @@ top.location="news:${request_headers.query.group}"; </script> <TITLE>${request_headers.query.group} + @@ -56,7 +96,31 @@ top.location="news:${request_headers.query.group}"; + + + +
- + +
+ + + + +
+
+Lobby
+
+
+
+ +
+
+ +
+ + -
@@ -102,16 +166,10 @@ cellspacing=0 cellpadding=0>
-
+ +
- @@ -148,9 +206,40 @@ Group: ${request_headers.query.group}
+`; + if (NGCount > 0) { + data += ` +
+ + + + + +
+${(page > 0) ? `` : ``} + + + + + + + +${(page_end < NGCount) ? `` : ``} + +
+ +
+${page_start}-${page_end} +
+ +
+
`; + } + data += `
-
+ +
@@ -165,8 +254,10 @@ Group: ${request_headers.query.group} if (NGCount > 0) { Object.keys(messages).forEach(function (k) { - var message = messages[k] - var message_date = message.headers.DATE; + var message = messages[k].article; + var has_relation = (messages[k].relation !== null) ? true : false; + var date_obj = new Date(Date.parse(message.headers.DATE)); + var date = (isToday(date_obj)) ? strftime("%I:%M %p", date_obj) : strftime("%b %d", date_obj) data += ` @@ -174,13 +265,13 @@ Group: ${request_headers.query.group}
+${(has_relation) ? `
•` : ''} ${(message.headers.SUBJECT) ? message.headers.SUBJECT : "(No Subject)"}
-${message.headers.FROM}, ${message.headers.DATE} - +${(message.headers.FROM.indexOf(' ') > 0) ? message.headers.FROM.split(' ')[0] : message.headers.FROM}, ${date}
`; @@ -191,8 +282,6 @@ ${message.headers.FROM}, ${message.headers.DATE} @@ -314,11 +433,11 @@ cellspacing=0 cellpadding=0> @@ -384,7 +503,7 @@ cellspacing=0 cellpadding=0>
- -
@@ -211,25 +300,55 @@ ${message.headers.FROM}, ${message.headers.DATE} `; sendToClient(socket, headers, data); - }).catch((e) => { throwError(e) });; + }).catch((e) => { + // getHeaderObj err + throwError(e) + });; } - }).catch((e) => { throwError(e) });; - }).catch((e) => { throwError(e) });; - }).catch((e) => { throwError(e) }); + }).catch((e) => { + // listGroup error + throwError(e) + });; + }).catch((e) => { + // selectGroup error + throwError(e) + }); + }).catch((e) => { + // connect error + throwError(e) + }); } -async function WebTVShowMessage(client, group, article) { - var connected = await clientConnect(client) - if (connected) { - response = await selectGroup(client, group); - if (response) { - response = await getArticle(client, article); - console.log(response); - if (response.code == 220) { +async function WebTVShowMessage(group, article) { + var article = parseInt(article); + wtvnews.connectUsenet().then(() => { + wtvnews.selectGroup(group).then((response) => { + wtvnews.getArticle(article).then((response) => { + wtvnews.quitUsenet(); headers = `200 OK -Content-type: text/html`; - +Content-type: text/html +wtv-expire-all: wtv-news:/news?group=${group}&article=`; + var signature = null; var message_colors = session_data.mailstore.defaultColors; + var display_signature = true; // todo make a toggle + var message = wtvnews.parseAttachments(response); + var message_body = message.text; + var attachments = null; + var signature_index = null; + if (message.attachments) attachments = message.attachments; + if (attachments) { + if (Object.keys(attachments).length > 0) { + Object.keys(attachments).forEach((k) => { + if (attachments[k].filename == "wtv_signature.html" && attachments[k].content_type.match(/text\/html/)) { + signature = attachments[k].data; + signature_index = k; + return false; + } + }); + attachments.splice(signature_index, 1); + } + } + if (signature) message_colors = session_data.mailstore.getSignatureColors(signature); data = `
- +
-
Previous
+
Previous
- +
-
Next
+
Next
-
@@ -461,8 +580,7 @@ ${wtvshared.htmlEntitize(response.article.headers.NEWSGROUPS)}
Date: -${console.log(Date.parse(response.article.headers.DATE))} -${strftime("%a, %b %e, %Y, %I:%M%P", new Date(Date.parse(response.article.headers.DATE) / 1000))} +${strftime("%a, %b %e, %Y, %I:%M%P", new Date(Date.parse(response.article.headers.DATE)))}
@@ -487,67 +605,257 @@ ${(response.article.headers.SUBJECT) ? wtvshared.htmlEntitize(response.article.h
-`; - var message_body = response.article.body.join("\n"); +` data += ` ${wtvshared.htmlEntitize(message_body, true)}

`; - data += `

-`; - /* - if (message.attachments) { - message.attachments.forEach((v, k) => { - if (v) { - console.log("*****************", v['Content-Type']); - switch (v['Content-Type']) { - case "image/jpeg": - data += `

`; - break; - case "audio/wav": - data += ` -
  recording.wav (wav attachment) - -


-`; - break; - } + if (signature) data += wtvshared.sanitizeSignature(signature); + data += "

"; + + if (attachments) { + var supported_images = /image\/(jpe?g|png|gif|x-wtv-bitmap)/; + var supported_audio = /audio\/(mp[eg|2|3]|midi?|wav|x-wav|mod|x-mod)/; + attachments.forEach((v, k) => { + if (v.content_type) { + if (v.content_type.match(supported_images)) + data += `

`; + else if (v.content_type.match(supported_audio)) + data += ` +
  ${(v.filename) ? (v.filename) : "Audio file"} (${v.content_type.split('/')[1]} attachment) + +


`; + else + data += `
A file ${(v.filename) ? `(${v.filename}) ` : ''}that WebTV cannot use, with type ${v.content_type} is attached to this message.` } }); } + /* if (message.url) { data += `Included Page: ${wtvshared.htmlEntitize(message.url_title).replace(/'/gi, "'")}`; } */ - data += ` -
- - -`; + data += "

"; sendToClient(socket, headers, data); - } else { - var errpage = wtvshared.doErrorPage(400, null, "No such article in group "+group+""); - sendToClient(socket, errpage[0], errpage[1]); - } - } else { - var errpage = wtvshared.doErrorPage(400, null, "No such group: "+group+""); - sendToClient(socket, errpage[0], errpage[1]); - } - } + + }).catch((e) => { + // no such article + var post_unavailable_file = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + '/wtv-news/post-unavailable.html'); + console.log(e); + if (fs.existsSync(post_unavailable_file)) { + headers = "200 OK\nContent-type: text/html"; + data = fs.readFileSync(post_unavailable_file).toString('ascii').replace("${group}", group).replace("${minisrv_config.config.service_logo}", minisrv_config.config.service_logo).replace("${message_colors.bgcolor}",session_data.mailstore.defaultColors.bgcolor); + sendToClient(socket, headers, data); + } else { + throwError(e); + } + }); + }).catch((e) => { + // no such group + throwError(e); + }); + }).catch((e) => { + //no connection + throwError(e); + }); } -if (!minisrv_config.services[service_name].upstream_address || !minisrv_config.services[service_name].upstream_port) { +function WebTVSearchGroups(search) { + wtvnews.connectUsenet().then(() => { + wtvnews.listGroups(search).then((response) => { + wtvnews.quitUsenet(); + headers = `200 OK +Content-type: text/html +wtv-expire-all: wtv-news:/news?search=`; + + data = ` + + +${(response.length == 0) ? "No " : ""}Discussion groups found + + + + + + + + + + + + + + + + + +
+ + +
+ + + +
+ +
+
+
+ +
+
+ +
+ + + +
+ + + + +
+
+All groups
+
+
+
+ +
+
+ +
+ + + +
+ + + + +
+
+Help
+
+
+
+ +
+
+ +
+ +
+
+
+ + + + +
+ + + +
+ +${(response.length == 0) ? "No " : ""}Discussion groups found +
+
+
+`; + + if (response.length == 0) { + data += `There are no discussion groups that match your request. Do you want to look for something else?`; + } else { + response.forEach((group) => { + data += `
+
+ + +
+ + +
+${group.name}
+
+ +` + if (group.description) { + data += `
${group.description}` + } + data += "
"; + }); + } + + data += ` +
+ + + + +
+ + + +
+
+ +
+ + + +
+ +
+Do you want to look for something else?
+ + + +  + + + + +
+ +`; + sendToClient(socket, headers, data); + }).catch((e) => { + // listGroups error + throwError(e); + }); + + }).catch((e) => { + // no connection + throwError(e); + }); +} + + +if (!wtvnews.client) { var errpage = doErrorPage(); headers = errpage[0]; data = errpage[1]; } else { var request_is_async = true; - if (request_headers.query.group) { + if (request_headers.query.search) { + WebTVSearchGroups(request_headers.query.search) + } else if (request_headers.query.group) { if (request_headers.query.article) { WebTVShowMessage(request_headers.query.group, request_headers.query.article); } else { WebTVListGroup(request_headers.query.group); } + } else { + // redirect to lobby if no understandable queries passed + headers = "300 OK\nLocation: wtv-news:/lobby"; + sendToClient(socket, headers, null); } } \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateAccountInfo.js b/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateAccountInfo.js index ce5ce4b6..583beb51 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateAccountInfo.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-register/ValidateAccountInfo.js @@ -61,7 +61,7 @@ correct an item, press Back.

`;
  USERNAME
-${request_headers.query.subscriber_name} +${request_headers.query.subscriber_username}

diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/add-user.js b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/add-user.js index bda36f7b..947ddf46 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/add-user.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/add-user.js @@ -98,6 +98,8 @@ Display name
bgcolor=#444444 text=#ffdd33 cursor=#cc9933 TYPE="text" ASCIIONLY SIZE="18" +selected +autoactivate MAXLENGTH="18">
diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/edit-password.js b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/edit-password.js index 29d01e0a..05eb0d76 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/edit-password.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/edit-password.js @@ -123,7 +123,7 @@ MAXLENGTH="${minisrv_config.config.passwords.max_length}">


Type again to confirm
- @@ -67,13 +81,16 @@ Mail signature <td abswidth=20> <TR> <td> -<td colspan=3 WIDTH=416 HEIGHT=98 VALIGN=top ALIGN=left> +<td colspan=3 WIDTH=416 HEIGHT=68 VALIGN=top ALIGN=left> <spacer type=block height=24 width=1> -Type a short text <B>signature</B> here and it will be added to the end of each mail message you send. +Type a short text <B>signature</B> here and it will be added to the end of each mail message you send.<br> +If you wish to use HTML, the first line of your signature should be <b><html></b>. +<TR> +<TD absheight=6> <TR> <TD> <TD colspan=3 WIDTH=416 HEIGHT=118 VALIGN=top ALIGN=left> -<FORM method="POST" action="/validate-mail-signature"> +<FORM method="POST" name="sig" action="/validate-mail-signature"> <INPUT type=hidden autosubmit=onleave> <TEXTAREA name="mail_signature" action="/validate-mail-signature" @@ -84,7 +101,7 @@ cols=45 rows=5 autoactivate nosoftbreaks maxlength=4096 -font=proportional>${session_data.getSessionData("subscriber_signature") || ""}</TEXTAREA></FORM></TD> +font=proportional>${signature || ""}</TEXTAREA></FORM></TD> </FORM> <TR> <TD> @@ -96,16 +113,26 @@ font=proportional>${session_data.getSessionData("subscriber_signature") || ""}</ <tr> <TD> <td colspan=4 height=1 valign=top align=left> +${(request_headers.query.preview) ? "<tr><td><td colspan=3><b>Signature Preview:</b>" : ""} <tr> <TD> -<td colspan=3 height=2 valign=top align=left bgcolor="0D0D0D"> -<img src="wtv-home:/ROMCache/Spacer.gif" width=436 height=1> +<td colspan=3 valign=top align=left bgcolor="${(request_headers.query.preview) ? message_colors.bgcolor : "0D0D0D"}"> +${(request_headers.query.preview) ? `<embed src="wtv-mail:/get-signature?sanitize=true&demotext=${encodeURIComponent(`<hr>This is a preview of your signature. The text below the line will not appear in your outgoing messages. It is provided to demonstrate what a message composed with this signature may look like. <a href="client:donothing">This is what a link looks like</a>.`)}" height=40></embed><br><br>` : ''} +<tr> +<td> +<td colspan=3 height=2 valign=top align=left> +<img src="wtv-home:/ROMCache/Spacer.gif" width=436 height=6> <TR> <TD> -<TD COLSPAN=4 HEIGHT=4 VALIGN=top ALIGN=left> -<TR> +<TD VALIGN=top ALIGN=left> +<FORM action="/mail-signature" METHOD="POST" onsubmit="this.mail_signature.value = document.forms[0].mail_signature.value"> +<INPUT type=hidden name="mail_signature"> +<FONT COLOR="#E7CE4A" SIZE=-1><SHADOW> +<INPUT TYPE=SUBMIT BORDERIMAGE="file://ROM/Borders/ButtonBorder2.bif" Value=Preview NAME="preview" USESTYLE WIDTH=103> +</SHADOW></FONT></FORM> + <TD> -<TD COLSPAN=3 VALIGN=top ALIGN=right> +<TD VALIGN=top ALIGN=right> <FORM action="client:goback"> <FONT COLOR="#E7CE4A" SIZE=-1><SHADOW> <INPUT TYPE=SUBMIT BORDERIMAGE="file://ROM/Borders/ButtonBorder2.bif" Value=Done NAME="Done" USESTYLE WIDTH=103> diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/setup.js b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/setup.js index ebee2778..a2073e56 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/setup.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/setup.js @@ -128,7 +128,9 @@ data += ` <spacer type=block width=1 height=5><BR> <img src="ROMCache/BulletArrow.gif" width=6 height=13 valign=absmiddle><spacer type=block width=6 height=1> <a href="wtv-setup:/phone">Dialing</a><BR> - +<spacer type=block width=1 height=5><BR> +<img src="ROMCache/BulletArrow.gif" width=6 height=13 valign=absmiddle><spacer type=block width=6 height=1> +<a href="wtv-setup:/tweaks">Tweaks</a><BR> <TD WIDTH=20> <TD WIDTH=300 VALIGN=top ALIGN=left> <spacer type=block width=6 height=14><font size="2"><br> @@ -157,7 +159,8 @@ Configure Messenger<BR>`; data += `<spacer type=block width=6 height=6><font size="2"><br> Connecting to WebTV<BR> - +<spacer type=block width=6 height=6><font size="2"><br> +minisrv specific settings<BR> <tr> <td colspan=4 height=2> diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/tweaks.js b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/tweaks.js new file mode 100644 index 00000000..b0ba6538 --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/tweaks.js @@ -0,0 +1,124 @@ +var minisrv_service_file = true; + + +headers = `200 OK +Connection: Keep-Alive +wtv-expire-all: wtv-setup:/tweaks +Content-Type: text/html` + +data = `<!--- *=* Copyright 1996, 1997 WebTV Networks, Inc. All rights reserved. ---> +<HTML> +<HEAD> +<TITLE> +Tweaks and extra configuration + + + + + + +
+ + +
+ + + +
+ +
+
+
+ +
+ +
+
+ +
+
+
+ +
+
+
+ + + + + + + + + + + + + + +
+ + + +
+ +Tweaks and extra config +
+
+
+ + +
+ +
+ + + +
+ + +
+Speeds up the splash logo page +by not waiting for the splash music to finish. +
+
+ +
+ + +
+ + +
+ + + +FastSplash™ +
+
+
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
+
+ + +`; \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-change-password.js b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-change-password.js index 0fefcad5..ba9c45bf 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-change-password.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-change-password.js @@ -36,7 +36,7 @@ Content-Type: text/html` data = errpage[1]; } else { - if (request_headers.query.password.length == 0 && request_headers.query.verify.length == 0) { + if (request_headers.query.password.length == 0 && request_headers.query.password_verify.length == 0) { userSession.disableUserPassword(); headers = `300 OK Content-type: text/html @@ -50,7 +50,7 @@ Location: ${request_headers.query.return_to}`; } else if (request_headers.query.password.length < minisrv_config.config.passwords.min_length) errpage = wtvshared.doErrorPage(400, "Your password must contain at least " + minisrv_config.config.passwords.min_length + " characters."); else if (request_headers.query.password.length > minisrv_config.config.passwords.max_length) errpage = wtvshared.doErrorPage(400, "Your password must contain no more than than " + minisrv_config.config.passwords.max_length + " characters."); - else if (request_headers.query.password !== request_headers.query.verify) errpage = wtvshared.doErrorPage(400, "The passwords you entered did not match. Please check them and try again."); + else if (request_headers.query.password !== request_headers.query.password_verify) errpage = wtvshared.doErrorPage(400, "The passwords you entered did not match. Please check them and try again."); else { if (errpage) { headers = errpage[0]; diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-mail-signature.js b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-mail-signature.js index 4536b2c5..5e2660f8 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-mail-signature.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-mail-signature.js @@ -1,8 +1,11 @@ var minisrv_service_file = true; if (request_headers.query && session_data) { - session_data.setSessionData("subscriber_signature", (request_headers.query.mail_signature) ? request_headers.query.mail_signature : ""); - session_data.saveSessionData(); + var signature = session_data.getSessionData("subscriber_signature"); + if (request_headers.query.mail_signature != signature) { + session_data.setSessionData("subscriber_signature", (request_headers.query.mail_signature) ? request_headers.query.mail_signature : ""); + session_data.saveSessionData(); + } headers = `200 OK Content-type: text/html` } else { diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-remove-users.js b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-remove-users.js index d2c085be..d5fcae74 100644 --- a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-remove-users.js +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-remove-users.js @@ -54,7 +54,6 @@ Connection: Keep-Alive Content-Type: text/html wtv-expire-all: wtv-setup:/remove-users wtv-expire-all: wtv-setup:/accounts -wtv-visit: ${confirmAlert} Location: ${confirmAlert}` } else { Object.keys(usersToRemove).forEach(function (k) { @@ -69,7 +68,6 @@ Connection: Keep-Alive Content-Type: text/html wtv-expire-all: wtv-setup:/remove-users wtv-expire-all: wtv-setup:/accounts -wtv-visit: ${gourl} Location: ${gourl}` } } \ No newline at end of file diff --git a/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-tweaks.js b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-tweaks.js new file mode 100644 index 00000000..4bf000ca --- /dev/null +++ b/zefie_wtvp_minisrv/ServiceVault/wtv-setup/validate-tweaks.js @@ -0,0 +1,12 @@ +var minisrv_service_file = true; + + +var fast_splash = wtvshared.parseBool(request_headers.query.fast_splash); +session_data.setSessionData("fast_splash", fast_splash); +session_data.saveSessionData(); + +headers = `200 OK +Connection: Keep-Alive +wtv-expire-all: wtv- +wtv-expire-all: http +Content-Type: text/html` diff --git a/zefie_wtvp_minisrv/UserTemplates/wtv-guide/glossary.json b/zefie_wtvp_minisrv/UserTemplates/wtv-guide/glossary.json new file mode 100644 index 00000000..0824c1c1 --- /dev/null +++ b/zefie_wtvp_minisrv/UserTemplates/wtv-guide/glossary.json @@ -0,0 +1,863 @@ +{ + "A": { + "accessnumber": { + "word": "access number", + "definition": "The phone number your dials to connect to the WebTV service.The access number is displayed on your TV screen each time you turn yourterminal on. If you are unsure whether the connection to your access number is local or toll, contact your phone company." + }, + "accessrestriction": { + "word": "access restriction", + "definition": "A feature that lets parents limit what a young viewer can see on the Internet. WebTV provides two restrictive services for kids: Kidfriendly,recommended for children under age 11, and Surfwatch, recommended for older children. Access restrictions can only be set up on secondary accounts and are controlled by the Primary user." + }, + "address": { + "word": "address", + "definition": "Web page address

The Internet address of a Web page, also called a URL (Universal Resource Locator).

E-mail address

The address of an Internet user's e-mail account. An e-mail address includes a user name, as well as the domain that sponsors the address. To send someone e-mail, you need to know their e-mail address." + }, + "addressbook": { + "word": "Address book", + "definition": "The Address book is feature that allows you to store e-mail addresses. Your Address book can hold up to 140 different e-mail addresses." + }, + "altkey": { + "word": "alt key", + "definition": "The Alt key, when pressed simultaneously with other specific keys, creates various symbols. For example, the Alt key can be used to insert accent marks when writing in a foreign language." + }, + "americaonline": { + "word": "America Online", + "definition": "An Online Service Provider for personal computer users. WebTV subscriberscannot connect to any portion of America Online's service, as it is notcompatible with WebTV. You can, however, send e-mailto AOL subscribers, as well as chat with them in non-AOL chat rooms." + }, + "analog": { + "word": "analog", + "definition": "A process by which information is transmitted from one location to another. Most phone communication is conducted over an analog connection. Yourterminal is compatible with analog lines only." + }, + "artemisresearch": { + "word": "Artemis Research", + "definition": "The name of the original research group that developed WebTV Networks." + }, + "attachments": { + "word": "attachments", + "definition": "Files or documents that are sent with e-mail messages. To read an attachment, the e-mail program you are using must support the program in which the attachment was created. WebTV's e-mail system supports someattachments but not others. At this time, attachments created with Microsoft's Word and Excel do not work with WebTV." + }, + "audibledialing": { + "word": "audible dialing", + "definition": "A feature that allows you to listen to your dial in and connect to WebTV.

To activate audible dialing, follow these steps:

  1. Choose Settings from Web Home.
  2. Choose Dialing.
  3. Choose Advanced.
  4. Put a check in the box next to Audible dialing.
  5. Choose Done.
" + }, + "audiocontrolpanel": { + "word": "audio control panel", + "definition": "An on-screen panel that allows you to control audio files. To make the audio panel appear, simply press the Options button while listening to an audio file." + }, + "autoretrieval": { + "word": "auto retrieval", + "definition": "A feature that automatically downloads new television listings to your during the night.

To manually activate the Auto retrieval feature, Choose Settings from TV Home, choose Listings setup from the next page, then follow the on-screen instructions.", + "plusonly": true + + }, + "autoselect": { + "word": "auto select", + "definition": "The Auto select feature improves your channel surfing by filtering out all unviewable TV channels. When you use the Auto select feature, only the TV channels that come in clearly are viewable.

To activate Auto select:

  1. Choose Settings from your TV Home page
  2. Choose Channels
  3. Choose Auto Select
  4. After the Auto Select is complete, choose Done
" + } + }, + "B": { + "backbutton": { + "word": "Back button", + "definition": "A button on your remote control that returns you to the last Web page you visited." + }, + "baud": { + "word": "baud", + "definition": "Measurement describing the amount of information a modem sends or receives per second." + }, + "bulletinboards": { + "word": "bulletin boards (BBs)", + "definition": "Please see newsgroup." + }, + "beta": { + "word": "beta", + "definition": "Testing stage that software goes through before it is released to the general public. During Beta testing, testers attempt to identify all bugs in the software." + }, + "bitmap": { + "word": "bitmap", + "definition": "A type of image file on the Internet. Bitmaps are complex rows and columns of bits, or dots, that connect to form a larger, graphical image." + }, + "blindcarboncopy": { + "word": "blind carbon copy (BCC)", + "definition": "A feature that allows computer users to send e-mail to someone without that person's e-mail address appearing on the message.If you have ever received e-mail that does not contain your e-mail address, you may have been blind carbon copied. does not allow users to send messages using Blind carbon copy." + }, + "bookmark": { + "word": "bookmark", + "definition": "(Verb) To save the Internet address (URL) of a Web page so it can be easily accessed later.

(Noun) On , bookmarks are referred to as Favorites." + }, + "bounce": { + "word": "bounce", + "definition": "Any time an e-mail message cannot reach its intended destination,it is returned, or bounced, to the original sender. An e-mail messagecan be bounced for any of the following reasons:

  • The sender typed the e-mail address incorrectly
  • The e-mail address no longer exists
  • The recipient's mail box is full
  • There may be server problems.
" + }, + "bps": { + "word": "BPS (Bits Per Second)", + "definition": "The amount of information traveling within an area of space in any given second." + }, + "browser": { + "word": "browser", + "definition": "A program used to access Web pages on the World Wide Web.Your comes equipped with its own browser that is specifically designed to view Web pages on a television screen." + }, + "bug": { + "word": "bug", + "definition": "An error in the software or hardware that causes a program to perform abnormally." + }, + "byte": { + "word": "byte", + "definition": "A measure of computer memory. One thousand bytes is equal to one kilobyte and one million bytes is equal to one megabyte." + } + }, + "C": { + "cablemodem": { + "word": "cable modem", + "definition": "A modem that transmits data over television cable lines.A standard analog modem transmits data over telephone lines.Cable modems process data much faster than analog modems.At this time, the majority of cable providers do not providecable modem Internet access." + }, + "cache": { + "word": "cache", + "definition": "A type of memory used to temporarily store Web pages.Cached Web pages load more quickly because they are stored locally in your terminal.

If your cache memory fills up, you may experience slower Web surfing,or receive an error message that says, This page is too big to beshown completely. To clear your cache memory, simply power off your terminaland turn it on again." + }, + "callwaiting": { + "word": "call waiting", + "definition": "A service provided by your phone company that lets you receive incomingphone calls while your phone line is in use.If you subscribe to a call waiting service, follow these steps:

  1. Log on as the Primary user.
  2. Choose Settings from ,
  3. Choose Dialing.
  4. Choose Call waiting.
  5. Choose the box next to Accept calls.
  6. Choose Done.
" + }, + "carboncopy": { + "word": "carbon copy (cc)", + "definition": "A feature that allows you to send an e-mail message to both a primaryrecipient and multiple secondary recipients at the same time." + }, + "casesensitive": { + "word": "case sensitive", + "definition": "When letters typed in uppercase are read differently thanletters typed in lowercase.

For example, your e-mail address is notcase sensitive. If your e-mail address is yourname@webtv.net,someone can send a message to YoUrNaMe@webtv.net, and it will stillget to you.

Your password is case sensitive. For example, if yourpassword is Surfwatch, you must type it in exactly that way." + }, + "cd-rom": { + "word": "CD-ROM", + "definition": "(Compact Disc-Read-Only Memory)

A small disc capable of storing large amounts of information." + }, + "chat": { + "word": "chat", + "definition": "A forum on the Internet where people communicate by exchanging typedmessages in real time.`; supports both HTML chat and real time IRC (Internet Relay Chat).At this time, we do not support Java-based chat." + }, + "client": { + "word": "client", + "definition": "A program or device that relies on a larger computer, or server,to perform the majority of its functions. Your can be thoughtof as a client, and so can some of the programs that run within it (e.g. 's e-mail system)." + }, + "commandkey": { + "word": "Command key", + "definition": "The Command key (Cmd), when pressed simultaneously withspecific keys on the keyboard, activates a number of features.For example, pressing Cmd and the < b>R keyat the same time reloads the page you're viewing." + }, + "cookies": { + "word": "cookies", + "definition": "Cookies are electronic packets of information that a Web page givesout to visiting Internet users. Cookies have many uses, the mostcommon of which lets Web pages offer custom information to its visitors.For example, while viewing a specific Web page, you may be askedto provide your name and a few comments about your personal interests.The next time you visit that page, you may be presented with a welcomemessage that includes your name and content specific to your personal interests." + }, + "crossoverlink": { + "word": "Crossover link", + "definition": "A hyperlink in the form of a small circled i thatsometimes appears on your screen during a television program.If selected, a crossover link will take you to a Web pagerelated to the TV program you are viewing.", + "plusonly": true + }, + "cross-post": { + "word": "cross-post", + "definition": "To submit a single post to several different newsgroups. To cross-posta message, simply add the newsgroup names to the post you have written,separating each name with a comma. Posts should only be cross-posted ifthey are relevant to all receiving newsgroups. Doing otherwise isconsidered bad netiquette." + }, + "cursor": { + "word": "cursor", + "definition": "A blinking symbol on the screen that indicates where typed letters and words will go or appear.

The cursor can be moved from one text-entry field to another by using the Tab key." + }, + "cutcopyandpaste": { + "word": "Cut, Copy, and Paste", + "definition": "A feature that lets you copy text from one place, such as a Web page, and pasteit somewhere else, such as in an e-mail message you're writing." + } + }, + "D": { + "deletekey": { + "word": "Delete key", + "definition": "Removes text from a text field. Pressing the Delete key removes text one character at a time, while pressing the Cmd key and the Delete key at the same time deletes an entire line of text." + }, + "dialingoptions": { + "word": "Dialing options", + "definition": "The place to make adjustments to your dialing settings. From the Dialing Options page, you can choose a dialing prefix, set up your terminal to work with a call waiting service,and activate audible dialing. Only the primary user can access and modify Dialing options.

To access Dialing options:

  1. Choose Settings from .
  2. Choose Dialing.
" + }, + "discuss": { + "word": "Discuss", + "definition": "WebTV's newsgroup section, which contains a list of featured newsgroups,a moderated newsgroup especially for WebTV users, and a search featureto help you find groups on specific discussion topics.To access Discuss:
  1. Choose Community from
  2. Choose Discuss.
" + }, + "discussiongroup": { + "word": "discussion group", + "definition": "Please see newsgroup." + }, + "dishplayer": { + "word": "DISHPlayer", + "definition": "The DISHPlayer is a satellite receiver that has the ability to access the WebTV service." + }, + "domainname": { + "word": "domain name", + "definition": "The part of a URL or e-mail address that indicates where a Web page or mail box resides.For example, the webtv.net portion of the URL http://www.webtv.netlets you know that this URL belongs to the WebTV domain. The same applies tothe webtv.net part of your e-mail address." + }, + "download": { + "word": "download", + "definition": "To move information from a host computer or server to a personal computer or device. For example, when an upgrade is available for, our host computers move the upgrade information toyour .

We maintain all of the information that is downloaded to your terminal. Therefore, it is not possible for you to download programs on your own." + }, + "dpi": { + "word": "dpi", + "definition": "The number of \"dots per inch\" in an image or Web page. Regardless of the dpi of a particular image, your terminal's maximum printing capability with most printers is 72 dpi .Because of this, the items you print may not appear exactly as they do on your television screen. If you're using an HP printer that has Smart Focus technology, however, yourmaximum printing capability is increased to 144 dpi." + } + }, + "E": { + "editkey": { + "word": "Edit key", + "definition": "Modifies what you have written in a text entry field. After highlighting a text entry field, pressing the Edit key onyour keyboard allows you to move the cursor within that text field." + }, + "e-mail": { + "word": "e-mail", + "definition": "Short for electronic mail, e-mail is a message sent from one Internet user to another. To send e-mail to another Internet user,you need that user's e-mail address. Likewise, someone will need your e-mail address to send e-mail to you." + }, + "e-mailaddress": { + "word": "e-mail address", + "definition": "The address of an Internet user's e-mail account. An e-mail address includes a user name, as well as a domain name, which is thename of the company, organization that sponsors the address.

For example, in the e-mail address yourname@webtv.net,yourname is the user name, while webtv.net is the domain name." + }, + "emoticons": { + "word": "emoticons", + "definition": "Combinations of letters and symbols used to convey emotion in an e-mail message or newsgroup post.

The following are a few of the more popular emoticons (Rotate your head to the left to view them properly):

:-) Joking

;-) Winking

:-( Sad" + }, + "encryption": { + "word": "encryption", + "definition": "A coding method used to help protect information on the Internet.Encrypted information is translated into a secret code, sentover the Internet, then translated back to its original form when it reaches its destination. supports a very high level of encryption." + }, + "extras": { + "word": "Extras", + "definition": "Mail features that are available only when activated in Settings. The following features are Extras:

  • Reply to All
  • Attach
  • CC (Carbon Copy)" + } + }, + "F": { + "faq": { + "word": "FAQ", + "definition": "(Frequently Asked Questions)

    A list of questions and answers relating to a particular topic." + }, + "favorite": { + "word": "Favorite", + "definition": "A Web page you save in order to return to it easily at a later time. Saving Web pages as Favorites allows you to keep track of the pages you visit most often and allows you to access them quickly. Each user can save a total of 640 Favorites." + }, + "favoritesfolders": { + "word": "Favorites folders", + "definition": "A feature that allows you to organizes the Web pages you save as Favorites.You can name your Favorite folders anything you'd like, and can store yourFavorites accordingly. For example, you might store your favorite sports-related Web page in a folder named Sports. Each user can create up to 20 Favorites folders." + }, + "file": { + "word": "File", + "definition": "A collection of information that is stored in one location. Files are used by computers and other devices to easily transfer large amounts of information. One example of a file is a document created with Microsoft Word." + }, + "fileformats": { + "word": "File formats", + "definition": "The particular method by which information is put into a file.Every file is created using a particular computer program. The following is a complete listing of the file formats supported by :

    • AIFF AU SND WAV
    • GIF GSM JPEG
    • Macromedia Flash 1.0
    • MIDI + Karaoke
    • MOD MPEG Video
    • MPEG-2, 3 Audio
    • QuickTime Audio RealAudio 1.0, 2.0, 3.0
    • Shockwave Audio" + }, + "findkey": { + "word": "Find key", + "definition": "A key on your keyboard that lets you look for specific words or phrases on a Web page. For example, if you wanted to find the word astronaut on NASA's Web page, you could use the Find keyto quickly locate that word. You can use the Find key on your keyboard, or press the Options button on your remote and choose find from the on-screen panel that appears." + }, + "flame": { + "word": "Flame", + "definition": "Term used to describe a malicious e-mail message or newsgroup post, often sent without provocation." + }, + "forward": { + "word": "forward", + "definition": "To send an e-mail message you've received to someone else." + }, + "frames": { + "word": "frames", + "definition": "An HTML feature that divides your screen into a set of smaller windows. Frames are often used on the Internet to keep a table of contents or a directory on the screen at all times." + }, + "freeware": { + "word": "freeware", + "definition": "Copyrighted computer software that can be obtained free of charge when using a computer." + }, + "ftp": { + "word": "FTP", + "definition": "A method by which files are transferred over the Internet from one Internet device to another. In order to FTP a file, you need to use an FTP program." + }, + "fuck": { + "word": "fuck", + "definition": "A word used by zefie frequently when developing minisrv." + } + }, + "G": { + "gif": { + "word": "GIF", + "definition": "A file format used to make pictures and images on the World Wide Web." + }, + "goto": { + "word": "Go To", + "definition": "You can use the Go To feature to go directly to a Web page. If you know the Internet address (URL) of a Web page, press Go To on your keyboard, or press Options on your remote and choose go to from the on-screen Options panel. Type in the URL, then choose Go to Page." + } + }, + "H": { + "hangupoption": { + "word": "Hang up option", + "definition": "An advanced option that allows you to temporarily disconnect your terminal from the service. When you're ready to connect again, select Reconnect. You'll be taken to the page you were viewing prior to hanging up. The Hang up feature does not power off your it simply disconnects it, freeing up your phone line." + }, + "harddrive": { + "word": "hard drive", + "definition": "A storage device used to store files, software, and/or programs." + }, + "hardware": { + "word": "hardware", + "definition": "Any physical object used in the computer/technology environment. Your , remote, and/or keyboard are examples of hardware." + }, + "header": { + "word": "header", + "definition": "The \"travel information\" for a particular e-mail message. Headers indicate who sent the e-mail message, to whom the message is being sent, and the time it was sent." + }, + "hoaxes": { + "word": "hoaxes", + "definition": "Messages purposefully crafted to fool or trick other Internet users. Hoaxes can be sent by e-mail and posted in newsgroups. One popular hoax attempts to fool people into thinking they have just downloaded a virus.If you encounter a hoax message such as this, it is best to simply ignore it." + }, + "homepage": { + "word": "Home page", + "definition": "The first Web page you are taken to when you connect to the Internet.To get to at any time, press the Home button on your remote or keyboard." + }, + "hotlink": { + "word": "hot link", + "definition": "Words or symbols on a Web page that, when selected, take you to a new location on the Internet. Hot links can take you to a different spot on the page you are viewing, or to a new page altogether. Hot links are typically a different color or design than the rest of the text on a given page. On , any word or image that you can highlight with the yellow box is a hot link." + }, + "html": { + "word": "HTML", + "definition": "The computer programming language used to make all Web pages. users can use HTML to add graphics and sound to their e-mail, as well as produce their own Web sites." + }, + "http": { + "word": "http", + "definition": "(Hypertext Transfer Protocol)

      The format by which Web pages are transferred back and forth on the Internet.You'll notice that the Internet address, or URL, of every Web page you view begins with http://" + }, + "hyperlink": { + "word": "hyperlink", + "definition": "Words or symbols on a Web page that, when selected, take you to a new location on the Internet. Hyperlinks can take you to a different spot on the page you are viewing , or to a new page altogether. Hyperlinks are typically a different color or design than the rest of the text on a given page. On , any word or image you can highlight with the yellowbox is a hyperlink." + } + }, + "I": { + "icon": { + "word": "icon", + "definition": "A selectable symbol or small picture on a Web page that, when selected,takes you to a different location on the Internet." + }, + "icq": { + "word": "ICQ", + "definition": "(I Seek You)

      A program that informs Internet users when a specified person is online.ICQ can also be used to send real time messages. At this time, does not support ICQ." + }, + "imagemap": { + "word": "image map", + "definition": "An image on a Web page that, when selected, takes you to a different location on the Internet. A single image map usually contains several hyperlinks. When you highlight and select an image map, a small yellow arrow will appear, allowing you to select a specific hyperlink within the image map." + }, + "infobutton": { + "word": "Info button", + "definition": "Used to find the Internet address (URL) of a Web page. Selecting the Info buttonwhile viewing a Web page will indicate the URL of that Web page. The Info button can be found on both the keyboard and the on-screen Options panel." + }, + "instantmessenger": { + "word": "Instant Messenger", + "definition": "A program that lets Internet users send messages to each other in real time." + }, + "internet": { + "word": "Internet", + "definition": "A large network of computers that enables people to communicate and exchange information across the globe. Also referred to as \"the Net.\"" + }, + "internetaddress": { + "word": "Internet address", + "definition": "Web pages are identified by their Internet addresses, or URLs. An Internet address is to a Web page what a street address is to a residence. If you know the Internet address of a Web page you can access it directly by using the Go to feature. To find the URL of a Web page while viewing it, press the Info key on your keyboard, or press Options on your remote and then choose info from the on-screen Options panel." + }, + "internetexplorer": { + "word": "Internet Explorer", + "definition": "An Internet browser created by Microsoft Corporation for computer users to surf the World Wide Web." + }, + "internettraffic": { + "word": "Internet traffic", + "definition": "The result of too many people connecting to the Internet at the same time. Just as automobile traffic may delay your commute to work, Internet traffic may slow down your Internet connection." + }, + "irblaster": { + "word": "IR blaster", + "definition": "A device that lets you control your VCR, satellite receiver, or cable box with the WebTV remote control and keyboard. IR stands for Infra-red." + }, + "irc": { + "word": "IRC", + "definition": "A program that allows Internet users to participate in live chat conversations." + }, + "irkeyboard": { + "word": "IR keyboard", + "definition": "A wireless keyboard you can use to control your . IR stands for Infra-red." + }, + "isp": { + "word": "ISP", + "definition": "A company that provides Internet access." + } + }, + "J": { + "jarhead": { + "word": "JarHead (aka JarHead4)", + "definition": "One of the developers of the WebTV minisrv project. JarHead has done a lot of work to create a service that recreates the experience of the original production WebTV Service.See also: zefie" + }, + "java": { + "word": "Java", + "definition": "A multipurpose computer language developed by Sun Microsystems Inc.Among other applications, Java is used to create animated graphics for Web pages. does not currently support Java." + }, + "javascript": { + "word": "Javascript", + "definition": "A scripting language that adds functionality to Web pages. For example,Javascript is used to create drop down menus on many Web pages.Javascript is often confused with Java, but the two languages are not related. supports Javascript." + }, + "jpeg": { + "word": "JPEG", + "definition": "A format used to create images and pictures on the World Wide Web. supports JPEGs." + } + }, + "K": { + "keywordsearch": { + "word": "keyword search", + "definition": "Some databases and Web sites can be searched by keyword. With a keyword search, you can search for information on a general topic by inputting a single word, like "pork."" + }, + "kid-friendly": { + "word": "Kid-Friendly", + "definition": "Software that reduces the chance of children accessing adult material on the Internet. Kid-Friendly provides content that is both educational and appropriate for children under the age of eleven. Once set up, thisservice helps to filter out inappropriate material on the Internet and allowsonly pre-approved content to be viewed. The option to set up Kid-Friendly accounts is provided to customers free of charge." + }, + "kilobyte": { + "word": "kilobyte", + "definition": "A measure of computer memory. One kilobyte is equal to one thousand bytes." + } + }, + "L": { + "link": { + "word": "link", + "definition": "Words or symbols on a Web page that, when selected, take you to a new location on the Internet. Links (also called hyperlinks) can take you to a different spot on the page you are viewing, or to a new page altogether. Links are typically a different color or design than the rest of the text on a given page. On , any word or image you can highlight with the yellow box is a link." + }, + "load": { + "word": "load", + "definition": "To move information from a host-computer or server to a personal computer or device. For example, when a service update is available, (the server) loads the update information to your . Because maintains all of the information that is loaded to your terminal, it is not possible for you to download programs on your own." + }, + "login": { + "word": "login", + "definition": "The act of connecting to a remote system or network. Every time you connect to , you are \"logging in.\"" + }, + "logon": { + "word": "logon", + "definition": "See login" + }, + "lurk": { + "word": "lurk", + "definition": "The act of reading posts in a newsgroup (Discuss) without responding. Newsgroup lurking is a perfectly normal Internet activity." + } + }, + "M": { + "macromediaflash": { + "word": "Macromedia Flash", + "definition": "A file format used to add animation to Web pages." + }, + "mailinglist": { + "word": "mailing list", + "definition": "A list of e-mail addresses compiled for wide-scale distribution. In general, people sign up for mailing lists in order to receive up-to-date information on a particular subject." + }, + "mattman69": { + "word": "MattMan69", + "definition": "A user who was notorious for hacking the service. MattMan69 created a Web site to expose all of the service secrets.

      To this day, MattMan69's Web site, found at
      http://turdinc.kicks-ass.net/Msntv/index2.html, is still one of the largest and most comprehensive archives of
      service history." + }, + "megabytes": { + "word": "megabytes", + "definition": "A measure of computer memory. One megabyte is equal to one million bytes or one thousand kilobytes." + }, + "messagelight": { + "word": "Message light", + "definition": "A small red light on the front of your that illuminates when a user has new e-mail. The message light is activated when you connect to the service and new e-mail is available. It canalso be activated by setting up the Message watch feature." + }, + "messagewatch": { + "word": "Message watch", + "definition": "A feature that lets you program your to automatically check for new e-mail, even while the terminal is off.

      To change the time Message watch checks for messages:

      1. Choose Settings from
      2. Choose Mail.
      3. Choose Message light.
      4. Follow the on-screen directions.
      " + }, + "mime": { + "word": "MIME", + "definition": "MIME protocol makes it possible to transfer non-text information, such as images, audio, and video, over the Internet. 's e-mail system is MIME compliant, so it can send and receive e-mail messages that are MIME encapsulated." + }, + "minisrv": { + "word": "minisrv", + "definition": "An open-source product written in nodejs designed to replicate the propritary comminucations between a WebTV client and the server. minisrv is the server software that provides the user experience. This page was sent to you via minisrv!" + }, + "modem": { + "word": "modem", + "definition": "A device or program that enables two computers or Internet devices to communicate over a telephone line." + }, + "moderatednewsgroup": { + "word": "moderated newsgroup", + "definition": "A newsgroup that lists only pre-approved posts. Because every post is reviewed by a moderator, moderated newsgroups are typically more organized and civilized than un-moderated newsgroups." + }, + "moderator": { + "word": "moderator", + "definition": "A person or program that reviews newsgroup submissions before they are posted. The job of a moderator is to keep newsgroup conversations focused and non-inflammatory." + }, + "mosaic": { + "word": "Mosaic", + "definition": "The first Internet browser used to navigate the World Wide Web.The Mosaic browser was developed at the National Center for Supercomputing Applications (NCSA) at the University of Illinois." + }, + "mouse": { + "word": "mouse", + "definition": "The mating device utilized by personal computer users." + }, + "mpeg": { + "word": "MPEG", + "definition": "A file format used to make animated video clips. supports MPEG video files, which are widely available on the Internet." + }, + "mud": { + "word": "MUD", + "definition": "A multi-player text-based game that is played on the Internet. The concept of MUD was developed in 1980 in the tradition of Dungeons and Dragons and other role-playing games. does not support MUDs." + } + }, + "N": { + "navigate": { + "word": "navigate", + "definition": "To move from one location to another on the Internet." + }, + "net": { + "word": "Net", + "definition": "Short for Internet." + }, + "netiquette": { + "word": "netiquette", + "definition": "Short for Internet etiquette, netiquette is a set of unwritten rules or guidelines that Internet users follow when posting to a newsgroup or using a chat room. For example, it is considered bad netiquette to type in all capital letters when posting to a newsgroup. This is equivalent to SHOUTING!" + }, + "netscapenavigator": { + "word": "Netscape Navigator", + "definition": "An Internet browser created by Netscape Communications Corporation for computer users to surf the World Wide Web." + }, + "newbie": { + "word": "newbie", + "definition": "A slang term used to describe someone new to the Internet." + }, + "newsgroup": { + "word": "newsgroup", + "definition": "A forum where Internet users gather to exchange ideas on a broad range of topics. So the conversation is easy to follow, newsgroup messages, or posts, are organized categorically by threads." + }, + "noob": { + "word": "noob", + "definition": "Please see newbie" + } + }, + "O": { + "on-screenkeyboard": { + "word": "On-screen keyboard", + "definition": "The on-screen keyboard lets you type letters and words using the hand-held remote control. To activate the on-screen keyboard, select a text entry field and then press the center button on your remote." + }, + "optionspanel": { + "word": "Options panel", + "definition": "An on-screen panel that appears after you press the OPTIONS button on your remote or keyboard." + } + }, + "P": { + "pagebuilder": { + "word": "Page Builder", + "definition": "Page Builder is a tool that helps you create your own Web pages and publish them on the World Wide Web." + }, + "pap": { + "word": "PAP", + "definition": "(Password Authentication Protocol)

      A protocol used to authenticate passwords. PAP is like a two-way handshaking procedure that validates a password every time you log on." + }, + "parallelport": { + "word": "parallel port", + "definition": "A port on a personal computer or Internet device used to connect external devices. WebTV Plus receivers and DISHPlayers have a built-in parallel port that can be used to connect a compatible printer." + }, + "pip": { + "word": "PIP", + "definition": "(Picture-in-Picture)

      Also known as the TV Window. A feature that lets you watch television while surfing the Web. To activate PIP, select TV windowfrom the Options panel, or press the Cmd key and the W key on your keyboard at the same time.", + "plusonly": true + }, + "pop": { + "word": "POP", + "definition": "(Point Of Presence)

      A phone number used to connect a computer or Internet device to the Internet." + }, + "post": { + "word": "post", + "definition": "(verb) To submit a message to a newsgroup.

      (noun) A message that can be read on a newsgroup." + }, + "ppp": { + "word": "PPP", + "definition": "(Point to Point Protocol)

      Communication protocol used over standard phone lines to support Internet connectivity. PPP allows computers to communicate with each other." + }, + "primaryuser": { + "word": "Primary user", + "definition": "Subscriber who originally registered for the service. The Primary user is responsible for payment of the service and for the actions of all secondary users.Additionally, only the Primary user can add or remove users,adjust dialing options, and set up access restrictions, such as SurfWatch and Kid Friendly." + }, + "printeradapter": { + "word": "printer adapter", + "definition": "A device needed to connect a printer to a WebTV Classic Internet terminal. You can find printer adapters in most stores that carry WebTV terminals. The WebTV Plus receiver comes with a built-in printer adapter." + }, + "printercable": { + "word": "printer cable", + "definition": "A cable that is used to connect a printer to a computer or Internet device.You must use an IEEE-1284 compliant bi-directional cable to print with yourterminal." + }, + "privateroom": { + "word": "private room", + "definition": "A chat room not listed on a chat service's list of public rooms. Private rooms are only available in IRC and are temporary.Once all participants have left a private room, the room no longer exists." + }, + "programinformation": { + "word": "program information", + "definition": "Information that is related to the television program you are viewing.Program information gives you:

      • A brief description of a television program
      • The amount of time remaining in the program
      • The rating of the television program (if available)
      • Closed captioning information
      ", + "plusonly": true + }, + "protocol": { + "word": "protocol", + "definition": "A standard format computers use to communicate.One popular protocol is http, the underlying format of the World Wide Web." + } + }, + "Q": { + "quicktime": { + "word": "Quicktime", + "definition": "A file format used to produce sound and video clips on the Internet. currently supports the audio portion of Quicktime files, butdoes not support Quicktime video." + } + }, + "R": { + "ram": { + "word": "RAM", + "definition": "A type of temporary computer memory. RAM is used to temporarily store the Web content you access during an Internet session. This type of memory makes content you recently viewed more quickly accessible." + }, + "realaudio": { + "word": "Real Audio", + "definition": "Software developed by Progressive Networks Inc. used to transmit, receive, and play audio on the Internet." + }, + "recent": { + "word": "Recent", + "definition": "The Recent feature allows you to see a list of the Web pages that you've just visited. To see this list, press Recent on yourkeyboard or remote." + }, + "reload": { + "word": "Reload", + "definition": "The Reload feature allows you to view the most recent version of a Web page. This is useful for Web pages that are updated frequently, such as sports and weather pages, and newsgroups.

      To reload a page, press Options on your remote or keyboard, then choose Reload from the on-screen Options panel." + }, + "reply": { + "word": "reply", + "definition": "To respond to a person who has sent you an e-mail message." + }, + "replyall": { + "word": "reply all", + "definition": "To respond to all of the original recipients of an e-mail message you have received. Reply all can only be used when an e-mail message contains multiple recipients and you've activated the Extras feature in the Settings section of Mail." + }, + "rfadapter": { + "word": "RF adapter", + "definition": "Used to connect devices, such as video game consoles and Internet set-top boxes, to TV sets that are not equipped with cable and/or audio-video jacks.

      RF stands for Radio Frequency." + }, + "rom": { + "word": "ROM", + "definition": "A type of computer memory that cannot be changed by an end user. If you disconnect from , the ROM memory will not be affected." + } + }, + "S": { + "save": { + "word": "Save", + "definition": "To store something in order to be able to access it later. You might save a Web page in a Favorites folder, an e-mail message in Storage, or an e-mail address in the Address book." + }, + "screensaver": { + "word": "screen saver", + "definition": "A program that prevents damage to a TV screen or PC monitor by maintaining the constant movement of images. If a stationary image remains on a screen for an extended period of time, the image may burn into the screen. The screen saver is activated when you stop using your terminal, but do not turn it off." + }, + "scrollbuttons": { + "word": "Scroll buttons", + "definition": "To move up and down on a Web page. Both the keyboard and the remote haveScroll up and Scroll down buttons." + }, + "search": { + "word": "Search", + "definition": "A service used to locate information on the Internet. To search for information, select Search from and type what you're looking for. The more descriptive words you use in a search, the better." + }, + "searchengine": { + "word": "search engine", + "definition": "A program used to find specific information on the Internet. Excite, Yahoo, and Alta Vista are all examples of popular search engines. features Infoseek as its Internet search engine." + }, + "send": { + "word": "Send", + "definition": "A feature that lets you send an e-mail message or a URL to another Internet user while you are surfing the Internet. The Send feature can also be used to forward newsgroup posts." + }, + "server": { + "word": "server", + "definition": "A computer on the Internet that is used to store information, such as your e-mail and Favorites. Each time you turn your on, you are connected to a server. That server then connects to other servers to access information." + }, + "serviceprovider": { + "word": "service provider", + "definition": "A company that provides Internet access." + }, + "shockwave": { + "word": "Shockwave", + "definition": "A program used to create animations and sounds on the Internet. does not support the video segments of Shockwave, but does support Shockwave audio." + }, + "shortcuts": { + "word": "shortcuts", + "definition": "Programmable keys (F1-F7) on the IR keyboard that, when set up, allow you to access Favorites with one keystroke." + }, + "site": { + "word": "site", + "definition": "A set of Web pages that together represent one specific location on the World Wide Web. A Web site is like a book, and the Web pages within it are like pages in a book. Web sites typically have a main page, where the idea, story, or purpose of the site is clearly defined." + }, + "smartcards": { + "word": "Smart cards", + "definition": "Smart cards are a new technology still in development. Your includes a smart card slot in anticipation of their widespread use. In the future, smart cards will be used to store information, including financial data for banking and other online transactions." + }, + "spam": { + "word": "spam", + "definition": "An unsolicited e-mail message or newsgroup post, often advertising a useless product or service. It is a violation of 's Terms of Service to send spam." + }, + "ssl": { + "word": "SSL", + "definition": "A security protocol on the Internet. SSL encrypts data in order to help protectthe transmission of confidential information over the Internet.We support this standard, allowing you to conduct online banking, shopping and trading. To be sure that you are making an SSL-backed transaction, you can select the Info button on the keyboard while on a Web page. If the page is encrypted, an icon on the bottom left of the screen will appeargiving you the option to view the page's security details." + }, + "storage": { + "word": "Storage", + "definition": "A feature that lets you save and sort e-mail. The Storage feature includes:

      • e-mail you have saved
      • e-mail you have discarded (during the past week)
      • e-mail you have sent (during the past week).
      " + }, + "streaming": { + "word": "streaming", + "definition": "A method used to send information over the Internet. The first part of streaming information arrives in a usable form before the last part is fully loaded. Audio files, for example, are commonly put into a streaming format. You can begin to play a streaming audio file before the last part of the file has fully loaded." + }, + "surf": { + "word": "surf", + "definition": "To navigate from one point to another on the World Wide Web." + }, + "surfwatch": { + "word": "SurfWatch", + "definition": "Software that reduces the likelihood of children accessing adult material on the Internet. SurfWatch blocks access to sites that it has identified as containing adult material. SurfWatch has also compiled a list of words which, when used in searches, may find inappropriate Web content. SurfWatch prevents these words from being used.

      SurfWatch can be set up by the Primary user (subscriber) for any secondary userbut cannot be set up on the Primary user's account." + }, + "s-video": { + "word": "S-video", + "definition": "A technology used to transmit video signals from one device to another. S-video technology produces a high quality image and is more commonly found on newer televisions." + } + }, + "T": { + "telnet": { + "word": "Telnet", + "definition": "A protocol used to access information on a remote computer. does not support Telnet connections." + }, + "termsofservice": { + "word": "Terms of Service", + "definition": "A legal contract between WebTV and each individual subscriber. All subscribers are required to follow the guidelines mandated within WebTV's Terms of service (TOS). Violations of the TOS can result in the suspension and possible cancellation of your account." + }, + "textentryfield": { + "word": "text entry field", + "definition": "A blank field or box on a Web page where text can be typed." + }, + "threads": { + "word": "threads", + "definition": "A connected group of posts in a newsgroup that share the same subject title. Each thread in a newsgroup represents a different topic of conversation." + }, + "timestamp": { + "word": "time stamp", + "definition": "The listed time on an e-mail message that indicates when it was sent." + }, + "transloader": { + "word": "Transloader", + "definition": "A Web site that allows you to capture images from other Web pages and savethem in your Scrapbook. You can then add these images to Web pages youcreate with Page Builder." + }, + "troll": { + "word": "troll", + "definition": "Someone who attempts to disrupt the fluidity of newsgroup conversationby posting irrelevant and sometimes hostile messages.If you encounter a troll, it is best to not respond publicly to their messages." + }, + "tvhome": { + "word": "TV Home", + "definition": "Your home base for watching TV, browsing television listings,and setting up your TV for use with your .", + "plusonly": true + }, + "tvlistings": { + "word": "TV Listings", + "definition": "A 24-hour schedule of television programming accessible from the TV Home page. TV Listings are available even if your terminal is offline, or not connected to .", + "plusonly": true + }, + "tvwindow": { + "word": "TV Window", + "definition": "Also known as Picture-in-Picture or PIP. A feature that lets you watch television while surfing the Web. To activate the TV window, select PIPfrom the Options panel, or press the Cmd key and the W key on your keyboard at the same time.", + "plusonly": true + } + }, + "U": { + "update": { + "word": "update", + "definition": "Please see upgrade" + }, + "upgrade": { + "word": "upgrade", + "definition": "The addition or enhancement of a new feature to a service. provides periodic upgrades to your service." + }, + "upload": { + "word": "upload", + "definition": "To transfer information from a personal computer or device to a host computer or server." + }, + "url": { + "word": "URL", + "definition": "Web pages are identified by their URLs, or Internet addresses. An Internet address is to a Web page what a street address is to a residence. If you know the Internet address of a Web page you can access it directly by using the Go To feature.

      To find the URL of a Web page, select the Info key on your keyboard, or press Options and then Info on your remote, while viewing a particular Web page." + }, + "usenet": { + "word": "Usenet", + "definition": "A large system of newsgroups that can be accessed through the Internet." + }, + "user": { + "word": "user", + "definition": "Any account set up on your . Each terminal can have a total of six users; one Primary user and up to five secondary users. Only the Primary user can add secondary users." + }, + "useyourisp": { + "word": "Use Your ISP", + "definition": "A feature that allows users to connect to using an ISP (Internet Service Provider) of their choosing. Use Your ISP is beneficial to those who have Internet access through another ISP, and for those who live in an area without a local access number." + } + }, + "V": { + "vidcap": { + "word": "Vidcap", + "definition": "Video capture, or vidcap, lets you connect a VCR, video camera, or digital camerato your terminal and capture a picture. You can send vidcaps in e-mail messages or keep them in your scrapbook in Page Builder.", + "plusonly": true + }, + "videoflash": { + "word": "VideoFlash", + "definition": "A technology developed by WebTV Networks that produces full-screen, full-motion video. In contrast to conventional Internet video technology, VideoFlash provides a level of video quality comparable to standard TV and is capable of providing significantly faster download times." + }, + "viewbutton": { + "word": "view button", + "definition": "Button on the remote control and keyboard used to switch between Web Homeand the TV Home page." + }, + "virus": { + "word": "virus", + "definition": "A program or code that interferes with the normal functioning of a personal computer. Your is immune to viruses." + }, + "vrml": { + "word": "VRML", + "definition": "A computer programming language used to create three-dimensional graphics on the World Wide Web. does not support VRML." + } + }, + "W": { + "web": { + "word": "Web", + "definition": "An enormous network of computers that can read and exchange information created by a single programming language, known as HTML. HTML is a simple and flexible programming language that is used to display text, audio, images, and animations. The World Wide Web is often referred to as the Internet. However, the World Wide Web is a subset of the Internet, not the Internet itself.Internet users navigate the World Wide Web using Web browsers." + }, + "webaddress": { + "word": "Web address", + "definition": "Please see Internet address" + }, + "webbrowser": { + "word": "Web browser", + "definition": "Please see browser" + }, + "webmaster": { + "word": "Webmaster", + "definition": "A person who is responsible for maintaining a Web site." + }, + "webpage": { + "word": "Web page", + "definition": "An HTML formatted document that resides on the World Wide Web.Web pages generally combine text and pictures, but can also contain animation and video. Each Web page on the World Wide Webis identified by a unique Internet address, or URL." + }, + "website": { + "word": "Web site", + "definition": "A set of Web pages that together represent one specific location on the World Wide Web. A Web site is like a book, and the Web pages within it are like pages in a book. Web sites typically have a main page, where the idea, story, or purpose of the site is clearly defined." + }, + "webtvclassic": { + "word": "WebTV Classic", + "definition": "WebTV's original Internet set-top box. The WebTV Classic Internet terminal, manufactured by Sony and Phillips Magnavox, is an easy and affordable way to access the Internet." + }, + "webtvplus": { + "word": "WebTV Plus", + "definition": "An Internet set-top box that connects to the WebTV Plus service.The WebTV Plus receiver, manufactured by Sony, Phillips Magnavox, Samsung, RCA, and Mitsubishi, is WebTV's second product offering." + }, + "whispering": { + "word": "whispering", + "definition": "A feature in Chat that lets you send a private message to another person in a chat room. Only you and the specified recipient will see the whispered message." + }, + "windows": { + "word": "Windows", + "definition": "A computer operating system developed by Microsoft Corporation." + }, + "worldwideweb": { + "word": "World Wide Web", + "definition": "An enormous network of computers that can read and exchange information created by a single programming language, known as HTML.HTML is a simple and flexible programming language that is usedto display text, audio, images, and animations. The World Wide Webis often referred to as the Internet. However, the World Wide Web is a subset of the Internet, not the Internet itself. Internet users navigate the World Wide Web using Web browsers." + } + }, + "Z": { + "zefie": { + "word": "zefie", + "definition": "Primary developer of the WebTV minisrv project. zefie is responsible for creating the project, as well maintaining the open-source project on GitHub.See also: JarHead" + } + } +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/app.js b/zefie_wtvp_minisrv/app.js index b4eaf918..b433e4e1 100644 --- a/zefie_wtvp_minisrv/app.js +++ b/zefie_wtvp_minisrv/app.js @@ -8,8 +8,8 @@ const fs = require('fs'); const tls = require('tls'); const path = require('path'); const zlib = require('zlib'); -const http = require('http'); -const https = require('https'); +const http = require('follow-redirects').http +const https = require('follow-redirects').https const net = require('net'); const crypto = require('crypto') const CryptoJS = require('crypto-js'); @@ -23,6 +23,7 @@ const WTVMime = require(classPath + "/WTVMime.js"); const WTVFlashrom = require(classPath + "/WTVFlashrom.js"); const vm = require('vm'); const express = require('express'); +var wtvnewsserver = null; process .on('SIGTERM', shutdown('SIGTERM')) @@ -38,6 +39,44 @@ function shutdown(signal = 'SIGTERM') { }; } +function findServiceByPort(port) { + var service_name = null; + Object.keys(minisrv_config.services).forEach(function(k) { + if (service_name) return; + if (minisrv_config.services[k].port) { + if (port == parseInt(minisrv_config.services[k].port)) + service_name = k; + } + }) + return service_name; +} + + +function getPortByService(service) { + if (minisrv_config.services[service]) return minisrv_config.services[service].port; + else return null; +} + +function getSocketDestinationPort(socket) { + return parseInt(socket._server._connectionKey.split(':')[2]); +} + +function verifyServicePort(service_name, socket) { + if (!minisrv_config.config.enable_port_isolation) return service_name; + if (socket._server._connectionKey) { + var socketPort = getSocketDestinationPort(socket); + if (minisrv_config.services[service_name]) { + if (minisrv_config.services[service_name].port == socketPort) { + if (minisrv_config.services[service_name].servicevault_dir) + return minisrv_config.services[service_name].servicevault_dir; + else + return service_name; + } + } + } + return false; +} + // Where we store our session information var ssid_sessions = new Array(); var socket_sessions = new Array(); @@ -45,6 +84,7 @@ var socket_sessions = new Array(); var ports = []; var pc_ports = []; + // add .reverse() feature to all JavaScript Strings in this application // works for service vault scripts too. if (!String.prototype.reverse) { @@ -164,16 +204,16 @@ var runScriptInVM = function (script_data, user_contextObj = {}, privileged = fa contextObj[vm_modules[k]] = require(module_file); modules_loaded.push(module_file) } catch (e) { - console.error(" *!* Could not load module", module_file, "requested by service", contextObj.service_name) + console.error(" *!* Could not load module", module_file, "requested by service", contextObj.service_name, e) } + if (vm_modules[k] === "WTVNews") contextObj['wtvnewsserver'] = wtvnewsserver; }) } } switch (contextObj.service_name) { case "wtv-guide": // wtv-guide is a special case due to needing this function - modules_to_load.push({ "name": "WTVGuide", "file": classPath + "/WTVGuide.js" }); - contextObj.wtvguide = new tmpmod(minisrv_config, ssid_sessions[contextObj.socket.ssid], contextObj.socket, runScriptInVM); + contextObj.wtvguide = new contextObj["WTVGuide"](minisrv_config, ssid_sessions[contextObj.socket.ssid], contextObj.socket, runScriptInVM); break; case "wtv-1800": @@ -254,9 +294,16 @@ async function processPath(socket, service_vault_file_path, request_headers = ne ] if (!pc_services) { + updateFromVM.push([`ssid_sessions[${socket.ssid}]`, "session_data"]); // user-specific session data from unprivileged scripts + } + + 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; + + if (privileged) { updateFromVM.push(["ssid_sessions", "ssid_sessions"]); // global ssid_sessions object for privileged service scripts, such as wtv-setup, wtv-head-waiter, etc updateFromVM.push(["socket_sessions", "socket_sessions"]); // global socket_sessions object for privileged service scripts, such as wtv-1800, etc - updateFromVM.push([`ssid_sessions[${socket.ssid}]`, "session_data"]); // user-specific session data from unprivileged scripts } try { @@ -417,11 +464,8 @@ async function processPath(socket, service_vault_file_path, request_headers = ne // expose var service_dir for script path to the root of the wtv-service socket_sessions[socket.id].starttime = Math.floor(new Date().getTime() / 1000); var script_data = fs.readFileSync(service_vault_file_path + ".js").toString(); - var priv = false; - if (minisrv_config.services[service_name]) priv = (minisrv_config.services[service_name].privileged) ? true : false; - else if (pc_services) priv = (minisrv_config.services['pc_services'].privileged) ? true : false; - var vmResults = runScriptInVM(script_data, contextObj, priv, service_vault_file_path + ".js"); + var vmResults = runScriptInVM(script_data, contextObj, privileged, service_vault_file_path + ".js"); // Here we read back certain data from the ServiceVault Script Context Object updateFromVM.forEach((item) => { try { @@ -461,11 +505,8 @@ async function processPath(socket, service_vault_file_path, request_headers = ne if (!minisrv_config.config.debug_flags.quiet) console.log(" * Found catchall at " + catchall_file + " to handle request (JS Interpreter Mode) [Socket " + socket.id + "]"); request_headers.service_file_path = catchall_file; var script_data = fs.readFileSync(catchall_file).toString(); - var priv = false; - if (minisrv_config.services[service_name]) priv = (minisrv_config.services[service_name].privileged) ? true : false; - else if (pc_services) priv = (minisrv_config.services['pc_services'].privileged) ? true : false; - runScriptInVM(script_data, contextObj, priv, catchall_file); + runScriptInVM(script_data, contextObj, privileged, catchall_file); // Here we read back certain data from the ServiceVault Script Context Object try { @@ -771,6 +812,7 @@ async function doHTTPProxy(socket, request_headers) { port: request_data.port, path: request_data.path, method: request_data.method, + followAllRedirects: true, headers: { "User-Agent": request_headers["User-Agent"] || "WebTV" } @@ -968,7 +1010,7 @@ function headerStringToObj(headers, response = false) { async function sendToClient(socket, headers_obj, data) { var headers = ""; var content_length = 0; - if (typeof (data) === 'undefined') data = ''; + if (typeof (data) === 'undefined' || data === null) data = ''; if (typeof (headers_obj) === 'string') { // string to header object headers_obj = headerStringToObj(headers_obj, true); @@ -984,7 +1026,11 @@ async function sendToClient(socket, headers_obj, data) { if (!headers_obj['minisrv-no-mail-count']) { if (ssid_sessions[socket.ssid]) { if (ssid_sessions[socket.ssid].isRegistered()) { - if (ssid_sessions[socket.ssid].mailstore) { + if (!ssid_sessions[socket.ssid].isUserLoggedIn()) { + // not logged in probe all users + headers_obj['wtv-mail-count'] = ssid_sessions[socket.ssid].getAccountTotalUnreadMessages(); + } else if (ssid_sessions[socket.ssid].mailstore) { + // logged in headers_obj['wtv-mail-count'] = ssid_sessions[socket.ssid].mailstore.countUnreadMessages(0); } } @@ -998,7 +1044,7 @@ async function sendToClient(socket, headers_obj, data) { // add Connection header if missing, default to Keep-Alive if (!headers_obj.Connection) { headers_obj.Connection = "Keep-Alive"; - headers_obj = moveObjectElement('Connection', 'Response', headers_obj); + headers_obj = wtvshared.moveObjectElement('Connection', 'Response', headers_obj); } var content_length = 0; @@ -1090,7 +1136,7 @@ async function sendToClient(socket, headers_obj, data) { // encrypt if needed if (socket_sessions[socket.id].secure == true && !socket_sessions[socket.id].do_not_encrypt) { headers_obj["wtv-encrypted"] = 'true'; - headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj); + headers_obj = wtvshared.moveObjectElement('wtv-encrypted', 'Connection', headers_obj); if (content_length > 0 && socket_sessions[socket.id].wtvsec) { if (!minisrv_config.config.debug_flags.quiet) console.log(" * Encrypting response to client ...") var enc_data = socket_sessions[socket.id].wtvsec.Encrypt(1, data); @@ -1127,7 +1173,7 @@ async function sendToClient(socket, headers_obj, data) { if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64) { if (ssid_sessions[socket.ssid].data_store.wtvsec_login.update_ticket) { headers_obj["wtv-ticket"] = ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64; - headers_obj = moveObjectElement("wtv-ticket", "Connection", headers_obj); + headers_obj = wtvshared.moveObjectElement("wtv-ticket", "Connection", headers_obj); ssid_sessions[socket.ssid].data_store.wtvsec_login.update_ticket = false; } } @@ -1241,30 +1287,6 @@ function concatArrayBuffer(buffer1, buffer2) { return tmp.buffer; } -function moveObjectElement(currentKey, afterKey, obj) { - var result = {}; - var val = obj[currentKey]; - delete obj[currentKey]; - var next = -1; - var i = 0; - if (typeof afterKey == 'undefined' || afterKey == null) afterKey = ''; - Object.keys(obj).forEach(function (k) { - var v = obj[k]; - if ((afterKey == '' && i == 0) || next == 1) { - result[currentKey] = val; - next = 0; - } - if (k == afterKey) { next = 1; } - result[k] = v; - ++i; - }); - if (next == 1) { - result[currentKey] = val; - } - if (next !== -1) return result; else return obj; -} - - function isUnencryptedString(string) { // a generic "isAscii" check is not sufficient, as the test will see the binary // compressed / encrypted data as ASCII. This function checks for characters expected @@ -1392,8 +1414,10 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 = headers["wtv-ticket"]; ssid_sessions[socket.ssid].data_store.wtvsec_login.DecodeTicket(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64); if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id != null) { - if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id >= 0) + if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id >= 0) { ssid_sessions[socket.ssid].switchUserID(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id, true, false); + ssid_sessions[socket.ssid].setUserLoggedIn(true); + } } } else { if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64 != headers["wtv-ticket"]) { @@ -1403,8 +1427,10 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq ssid_sessions[socket.ssid].data_store.wtvsec_login.DecodeTicket(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_b64); if (headers["wtv-incarnation"]) ssid_sessions[socket.ssid].data_store.wtvsec_login.set_incarnation(headers["wtv-incarnation"]); if (ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id >= 0) { - if (ssid_sessions[socket.ssid].user_id != ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id) + if (ssid_sessions[socket.ssid].user_id != ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id) { ssid_sessions[socket.ssid].switchUserID(ssid_sessions[socket.ssid].data_store.wtvsec_login.ticket_store.user_id, true, false); + ssid_sessions[socket.ssid].setUserLoggedIn(true); + } } } } @@ -1836,6 +1862,7 @@ Object.keys(minisrv_config.services).forEach(function (k) { if (minisrv_config.services[k].pc_services) pc_ports.push(minisrv_config.services[k].port); else ports.push(minisrv_config.services[k].port); } + // minisrv_config service toString minisrv_config.services[k].toString = function (overrides) { var self = Object.assign({}, this); @@ -1858,7 +1885,37 @@ Object.keys(minisrv_config.services).forEach(function (k) { } return outstr; } + console.log(" * Configured Service:", k, "on Port", minisrv_config.services[k].port, "- Service Host:", minisrv_config.services[k].host, "- Bind Port:", !minisrv_config.services[k].nobind, "- PC Services Mode:", (minisrv_config.services[k].pc_services) ? true : false); + + if (minisrv_config.services[k].local_nntp_port) { + if (!wtvnewsserver) { + const WTVNewsServer = require(classPath + "/WTVNewsServer.js"); + var local_nntp_using_auth = false; + if (minisrv_config.services[k].local_nntp_requires_auth) { + local_nntp_using_auth = true; + if (minisrv_config.services[k].local_auth) { + // auth required, and info defined in config + wtvnewsserver = new WTVNewsServer(minisrv_config, minisrv_config.services[k].local_nntp_port, true, minisrv_config.services[k].local_auth.username, minisrv_config.services[k].local_auth.password); + console.log(" * Configured Service: Local NNTP", "on 127.0.0.1:" + minisrv_config.services[k].local_nntp_port, "(TLS) - Auth required:", local_nntp_using_auth, "- Auth: As Configured"); + } else { + // auth required, but randomly generated + wtvnewsserver = new WTVNewsServer(minisrv_config, minisrv_config.services[k].local_nntp_port, true); + console.log(" * Configured Service: Local NNTP", "on 127.0.0.1:" + minisrv_config.services[k].local_nntp_port, "(TLS) - Auth required:", local_nntp_using_auth, "- Auth (randgen): User:", wtvnewsserver.username, "Pass:", wtvnewsserver.password); + } + } else { + // no auth required on local server + wtvnewsserver = new WTVNewsServer(minisrv_config, minisrv_config.services[k].local_nntp_port); + console.log(" * Configured Service: Local NNTP", "on 127.0.0.1:" + minisrv_config.services[k].local_nntp_port, "(TLS) - Auth required:", local_nntp_using_auth, "- Auth: None"); + } + if (minisrv_config.services[k].featuredGroups) { + Object.keys(minisrv_config.services[k].featuredGroups).forEach((j) => { + wtvnewsserver.createGroup(minisrv_config.services[k].featuredGroups[j].group, minisrv_config.services[k].featuredGroups[j].description || null); + }) + } + } + } + }) if (minisrv_config.config.hide_ssid_in_logs) console.log(" * Masking SSIDs in console logs for security"); else console.log(" * Full SSIDs will be shown in console logs"); @@ -1894,44 +1951,6 @@ process.on('uncaughtException', function (err) { console.error((err && err.stack) ? err.stack : err); }); - -function findServiceByPort(port) { - var service_name = null; - Object.keys(minisrv_config.services).forEach(function (k) { - if (service_name) return; - if (minisrv_config.services[k].port) { - if (port == parseInt(minisrv_config.services[k].port)) - service_name = k; - } - }) - return service_name; -} - - -function getPortByService(service) { - if (minisrv_config.services[service]) return minisrv_config.services[service].port; - else return null; -} - -function getSocketDestinationPort(socket) { - return parseInt(socket._server._connectionKey.split(':')[2]); -} - -function verifyServicePort(service_name, socket) { - if (socket._server._connectionKey) { - var socketPort = getSocketDestinationPort(socket); - if (minisrv_config.services[service_name]) { - if (minisrv_config.services[service_name].port == socketPort) { - if (minisrv_config.services[service_name].servicevault_dir) - return minisrv_config.services[service_name].servicevault_dir; - else - return service_name; - } - } - } - return false; -} - var initstring = ''; var initstring_pc = ''; ports.sort(); diff --git a/zefie_wtvp_minisrv/includes/WTVClientSessionData.js b/zefie_wtvp_minisrv/includes/WTVClientSessionData.js index 4187369c..33687c8c 100644 --- a/zefie_wtvp_minisrv/includes/WTVClientSessionData.js +++ b/zefie_wtvp_minisrv/includes/WTVClientSessionData.js @@ -40,20 +40,7 @@ class WTVClientSessionData { this.ssid = ssid; this.data_store = new Array(); this.session_store = {}; - this.lockdownWhitelist = [ - "wtv-1800:/preregister", - "wtv-head-waiter:/login", - "wtv-head-waiter:/ValidateLogin", - "wtv-head-waiter:/login-stage-two", - "wtv-head-waiter:/relogin", - "wtv-head-waiter:/ROMCache/Spacer.gif", - "wtv-head-waiter:/ROMCache/NameStrip.gif", - "wtv-head-waiter:/images/PasswordBanner.gif", - "wtv-head-waiter:/ROMCache/UtilityBullet.gif", - "wtv-head-waiter:/images/NameBanner.gif", - "wtv-head-waiter:/bad-disk", - "wtv-log:/log" - ]; + this.lockdownWhitelist = minisrv_config.config.lockdownWhitelist; this.lockdownWhitelist.push(minisrv_config.config.unauthorized_url); this.lockdownWhitelist.push(minisrv_config.config.service_logo); this.mailstore = new WTVMail(this.minisrv_config, this) @@ -61,14 +48,16 @@ class WTVClientSessionData { this.loginWhitelist = Object.assign([], this.lockdownWhitelist); // clone lockdown whitelist into login whitelist this.loginWhitelist.push("wtv-head-waiter:/choose-user"); this.loginWhitelist.push("wtv-head-waiter:/password"); - this.loginWhitelist.push("http://*"); // allow http proxy without login - this.loginWhitelist.push("https://*"); // allow https proxy without login } assignMailStore() { this.mailstore = new WTVMail(this.minisrv_config, this) } + assignFavoriteStore() { + this.mailstore = this.favstore = new WTVFavorites(this.minisrv_config, this) + } + createWTVSecSession() { return new WTVSec(this.minisrv_config) } @@ -79,22 +68,39 @@ class WTVClientSessionData { var total_unread_messages = 0; - for (var i = 0; i < this.minisrv_config.config.user_accounts.max_users_per_account; i++) { - var subUserSession = new this.constructor(this.minisrv_config, this.ssid); - subUserSession.switchUserID(i, false, false); + var accounts = this.listPrimaryAccountUsers(); + var self = this; + Object.keys(accounts).forEach((k) => { + var user_id = accounts[k].user_id; + var subUserSession = new self.constructor(self.minisrv_config, self.ssid); + subUserSession.switchUserID(user_id, false, false); subUserSession.assignMailStore(); if (subUserSession.mailstore) { total_unread_messages += subUserSession.mailstore.countUnreadMessages(0); } - } + }); return total_unread_messages; } - switchUserID(user_id, update_mail = true, update_ticket = true) { + clearUserSessionMemory() { + this.setUserLoggedIn(false); + this.data_store = new Array(); + this.session_store = {}; + this.assignFavoriteStore(); + this.assignMailStore() + } + + switchUserID(user_id, update_mail = true, update_ticket = true, update_favorite = true) { this.user_id = user_id; - this.loadSessionData(); - if (this.isRegistered()) this.assignMailStore(); - if (this.data_store.wtvsec_login && update_ticket) this.setTicketData('user_id', user_id); + if (user_id != null) { + this.loadSessionData(); + if (this.isRegistered() && update_mail) this.assignMailStore(); + if (this.isRegistered() && update_favorite) this.assignMailStore(); + if (this.data_store.wtvsec_login && update_ticket) this.setTicketData('user_id', user_id); + } else { + this.user_id = 0; + this.clearUserSessionMemory(); + } } setTicketData(key, value) { @@ -153,8 +159,14 @@ class WTVClientSessionData { if (f.substr(0, 4) == "user") { var user_file = master_directory + self.path.sep + f + self.path.sep + f + ".json"; if (self.fs.existsSync(user_file)) { - if (f == "user0") account_data['subscriber'] = JSON.parse(this.fs.readFileSync(user_file)); - else account_data[f] = JSON.parse(this.fs.readFileSync(user_file)); + if (f == "user0") { + account_data['subscriber'] = JSON.parse(this.fs.readFileSync(user_file)); + account_data['subscriber'].user_id = 0; + } + else { + account_data[f] = JSON.parse(this.fs.readFileSync(user_file)); + account_data[f].user_id = parseInt(f.replace("user", '')) + } } } } @@ -426,10 +438,6 @@ class WTVClientSessionData { return encoded_passwd.toString(CryptoJS.enc.Base64); } - generatePassword(len) { - return CryptoJS.lib.WordArray.random(Math.round(len / 2)).toString(CryptoJS.enc.Hex); - } - setUserPassword(passwd) { var encoded_passwd = this.encodePassword(passwd); this.setSessionData("subscriber_password", encoded_passwd); @@ -465,7 +473,6 @@ class WTVClientSessionData { } isUserLoggedIn() { - if (!this.getUserPasswordEnabled()) return true; // no password is set so always validate var password_valid = this.get("password_valid"); return (password_valid); } diff --git a/zefie_wtvp_minisrv/includes/WTVGuide.js b/zefie_wtvp_minisrv/includes/WTVGuide.js index 47e93726..9906a083 100644 --- a/zefie_wtvp_minisrv/includes/WTVGuide.js +++ b/zefie_wtvp_minisrv/includes/WTVGuide.js @@ -8,7 +8,7 @@ class WTVGuide { constructor(minisrv_config, session_data, socket, runScriptInVM) { if (!minisrv_config) throw ("minisrv_config required"); if (!session_data) throw ("WTVClientSessionData required"); - var WTVShared = require("./WTVShared.js")['WTVShared']; + const WTVShared = require("./WTVShared.js")['WTVShared']; this.minisrv_config = minisrv_config; this.session_data = session_data; this.wtvshared = new WTVShared(minisrv_config); @@ -24,8 +24,8 @@ class WTVGuide { switch (topic.toLowerCase()) { case "glossary": - var template = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + "/wtv-guide/templates/glossary.js"); - var glossary_datafile = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + "/wtv-guide/glossary.json"); + var template =this.wtvshared.getTemplate("wtv-guide", "templates/glossary.js", true); + var glossary_datafile =this.wtvshared.getTemplate("wtv-guide", "glossary.json", true); if (!this.fs.existsSync(template)) break; if (!this.fs.existsSync(glossary_datafile)) break; @@ -44,13 +44,9 @@ class WTVGuide { var start = definition.indexOf(search) + search.length; original_start = start; // handle - console.log("start:", start) - console.log("debug > position:", definition.substr(start, 1)); if (definition.substr(start, 1) != ">") { - console.log("debug: detecting word in tag") start++; // +1 to skip = end = definition.indexOf(">", start); - console.log("debug > position 2:", definition.indexOf(">", start)); link_word_override = definition.substring(start, end); // strip any quotes if (link_word_override.substr(0, 1).match(/[\"\']/)) link_word_override = link_word_override.substring(1); @@ -60,10 +56,8 @@ class WTVGuide { link_word_start_letter = link_word_for_link.substr(0, 1).toUpperCase(); start = end + 1; // update start pos for rest of processing } else { - console.log("debug: generating word") start++; } - console.log("end:", end) end = definition.indexOf("", start); var link_word = definition.substring(start, end); if (!link_word_for_link) link_word_for_link = link_word.replace(/ /g, '').replace(/\'/g,'').replace(/\"/g,'').toLowerCase(); @@ -72,13 +66,6 @@ class WTVGuide { var link = `wtv-guide:/help?topic=Glossary&subtopic=${link_word_start_letter}&page=${link_word_for_link}&word=${encodeURIComponent(link_word_override)}` var new_definition = definition.substring(0, original_start - search.length) + `${link_word}` + definition.substring(end + 7); - console.log("start:", start) - console.log("end:", end) - console.log("link_word:", link_word) - console.log("link_word_for_link:", link_word_for_link); - console.log("link_word_start_letter:", link_word_start_letter); - console.log("link:", link) - console.log("new_definition:", new_definition) definition = new_definition; } // replaces with the friendly name of the type of unit the user has @@ -110,7 +97,7 @@ class WTVGuide { } } else { // glossary letter word index - var template = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + "/wtv-guide/templates/glossary_word_index.js"); + var template =this.wtvshared.getTemplate("wtv-guide", "templates/glossary_word_index.js", true); var isPlusBox = false; if (this.session_data.hasCap("client-has-tv-experience")) isPlusBox = true; var worddb = []; @@ -133,9 +120,8 @@ class WTVGuide { case "index": switch (subtopic.toLowerCase()) { case "glossary": - var template = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + "/wtv-guide/templates/glossary_index.js"); - console.log(template); - var glossary_datafile = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + "/wtv-guide/glossary.json"); + var template =this.wtvshared.getTemplate("wtv-guide", "templates/glossary_index.js", true); + var glossary_datafile =this.wtvshared.getTemplate("wtv-guide", "glossary.json", true); if (!this.fs.existsSync(template)) break; if (!this.fs.existsSync(glossary_datafile)) break; @@ -154,8 +140,8 @@ class WTVGuide { // fallback to old js file method try { var prerendered = null; - if (!page) prerendered = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + "/wtv-guide/prerendered/" + topic + "/" + subtopic + ".js"); - else prerendered = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + "/wtv-guide/prerendered/" + topic + "/" + subtopic + "/" + page + ".js"); + if (!page) prerendered = this.wtvshared.getTemplate("wtv-guide", "prerendered/" + topic + "/" + subtopic + ".js", true); + else prerendered =this.wtvshared.getTemplate("wtv-guide", "prerendered/" + topic + "/" + subtopic + "/" + page + ".js", true); if (!this.fs.existsSync(prerendered)) break; @@ -184,7 +170,7 @@ class WTVGuide { console.log(" * wtv-template error:", e) } // unload and clean up module - wtvshared.unloadModule(template); + this.wtvshared.unloadModule(template); } // return generated page diff --git a/zefie_wtvp_minisrv/includes/WTVMail.js b/zefie_wtvp_minisrv/includes/WTVMail.js index 426f862c..2b17fb40 100644 --- a/zefie_wtvp_minisrv/includes/WTVMail.js +++ b/zefie_wtvp_minisrv/includes/WTVMail.js @@ -39,7 +39,7 @@ class WTVMail { this.trashMailboxName ]; this.defaultColors = { - bgcolor: "#171726", + bgcolor: "#191919", text: "#82A9D9", link: "#BDA73A", vlink: "#62B362" @@ -156,7 +156,7 @@ class WTVMail { return this.uuid.v1(); } - createMessage(mailboxid, from_addr, to_addr, msgbody, subject = null, from_name = null, to_name = null, signature = null, date = null, known_sender = false, attachments = [], url = null, url_title = null) { + createMessage(mailboxid, from_addr, to_addr, msgbody, subject = null, from_name = null, to_name = null, signature = null, date = null, known_sender = false, attachments = [], url = null, url_title = null, allow_html = false) { if (this.createMailbox(mailboxid)) { if (!date) date = Math.floor(Date.now() / 1000); @@ -177,7 +177,8 @@ class WTVMail { "unread": true, "attachments": attachments, "url": url, - "url_title": url_title + "url_title": url_title, + "allow_html": allow_html } try { if (this.fs.existsSync(message_file_out)) { @@ -202,14 +203,53 @@ class WTVMail { } createWelcomeMessage() { - var from_addr = (this.minisrv_config.config.service_owner_account) ? this.minisrv_config.config.service_owner_account : this.minisrv_config.config.service_owner; - from_addr += "@" + this.minisrv_config.config.service_name; - var from_name = this.minisrv_config.config.service_owner + var welcomeTemplate = this.wtvshared.getTemplate("wtv-mail", "welcomeMail.txt").toString('ascii'); + var end_of_headers = false; + var msg = ""; + var self = this; var to_addr = this.wtvclient.getSessionData("subscriber_username") + "@" + this.minisrv_config.config.service_name; var to_name = this.wtvclient.getSessionData("subscriber_name"); - var subj = "Welcome to " + this.minisrv_config.config.service_name; - var msg = "poop"; - return this.createMessage(0, from_addr, to_addr, msg, subj, from_name, to_name, null, null, true); + var available_tags = { + ...this.minisrv_config.config, + "user_address": to_addr, + "user_name": to_name + } + var from_name, from_addr, subj = null; + var lines = welcomeTemplate.replace(/\r/g, '').split("\n"); + lines.forEach((line) => { + if (line.indexOf(": ") > 1 && !end_of_headers) { + var header = [line.slice(0, line.indexOf(':')), line.slice(line.indexOf(':') + 2).trim()]; + switch (header[0].toLowerCase()) { + case "from": + if (header[1].indexOf("<") >= 0) { + var email = header[1].match(/(.+) \<(.+)\>/); + if (email) { + from_name = email[1]; + from_addr = email[2]; + } else { + var email = header[1].match(/\<(.+)\>/); + from_addr = email[1]; + } + } else if (header[1].indexOf('@') >= 0) { + from_addr = header[1]; + } + break; + + case "subject": + subj = header[1]; + break; + } + } else if (line == '') end_of_headers = true; + else { + msg += line.replace(/\$\{(\w{1,})\}/g, function (x) { + var out = ''; + var tag = x.replace("${", '').replace('}', ''); + if (available_tags[tag]) out = available_tags[tag]; + return out + }) + "\n"; + } + }); + return this.createMessage(0, from_addr, to_addr, msg, subj, from_name, to_name, null, null, true, [], null, null, true); } getMessage(mailboxid, messageid) { diff --git a/zefie_wtvp_minisrv/includes/WTVMime.js b/zefie_wtvp_minisrv/includes/WTVMime.js index 771e2824..3c30a565 100644 --- a/zefie_wtvp_minisrv/includes/WTVMime.js +++ b/zefie_wtvp_minisrv/includes/WTVMime.js @@ -11,7 +11,7 @@ class WTVMime { constructor(minisrv_config) { - var WTVShared = require("./WTVShared.js")['WTVShared']; + const { WTVShared } = require("./WTVShared.js"); this.minisrv_config = minisrv_config; this.wtvshared = new WTVShared(minisrv_config); if (!String.prototype.reverse) { @@ -199,6 +199,67 @@ class WTVMime { return new Array(wtv_mime_type, modern_mime_type); } + // modified from https://github.com/sergi/mime-multipart/blob/master/index.js + + generateMultipartMIME(tuples, options) { + // modified for creating usenet compliant headers/content from an attachment + var CRLF = '\n'; + if (tuples.length === 0) { + // according to rfc1341 there should be at least one encapsulation + throw new Error('Missing argument. At least one part to generate is required'); + } + + options = options || {}; + var preamble = options.preamble || "This is a multi-part message in MIME format."; + var epilogue = options.epilogue; + var boundary = options.boundary || "------------" + this.wtvshared.generateString(24); + + if (boundary.length < 1 || boundary.length > 70) { + throw new Error('Boundary should be between 1 and 70 characters long'); + } + + var boundary_header = 'multipart/mixed; boundary="' + boundary + '"'; + + var delimiter = CRLF + '--' + boundary; + var closeDelimiter = delimiter + '--'; + + var wtvshared = this.wtvshared; + + var encapsulations = tuples.map(function (tuple, i) { + var mimetype = tuple.mime || 'text/plain'; + var encoding = tuple.encoding || 'utf-8'; + var use_base64 = tuple.use_base64 || !wtvshared.isASCII(tuple.content); + var is_base64 = tuple.is_base64 || wtvshared.isBase64(tuple.content); + var filename = (tuple.filename) ? tuple.filename : (use_base64) ? ('file' + i) : null; + + var headers = [ + `Content-Type: ${mimetype}; ${(use_base64) ? `name="${filename}"` : `charset=${encoding.toUpperCase()}; format=flowed`}`, + ]; + + if (filename) headers.push(`Content-Disposition: attachment; filename="${filename}"`); + headers.push(`Content-Transfer-Encoding: ${(use_base64) ? 'base64' : '7bit'}`); + + var bodyPart = headers.join(CRLF) + CRLF + CRLF; + if (use_base64 && !is_base64) bodyPart += wtvshared.lineWrap(Buffer.from(tuple.content).toString('base64'),72) + CRLF; + else bodyPart += wtvshared.lineWrap(tuple.content,72); + + return delimiter + CRLF + bodyPart; + }); + + var multipartBody = [ + preamble ? preamble : undefined, + encapsulations.join(''), + closeDelimiter, + epilogue ? CRLF + epilogue : undefined, + ].filter(function (element) { return !!element; }); + + return { + "mime_version": "1.0", + "content_type": boundary_header, + "content": multipartBody.join('') + }; + } + } module.exports = WTVMime; diff --git a/zefie_wtvp_minisrv/includes/WTVNews.js b/zefie_wtvp_minisrv/includes/WTVNews.js index 352b3cba..1b43ef2b 100644 --- a/zefie_wtvp_minisrv/includes/WTVNews.js +++ b/zefie_wtvp_minisrv/includes/WTVNews.js @@ -2,23 +2,61 @@ class WTVNews { minisrv_config = null; newsie = require('newsie').default; + strftime = require('strftime'); + wtvshared = null; service_name = null; client = null; + username = null; + password = null; + posting_allowed = true; constructor(minisrv_config, service_name) { this.minisrv_config = minisrv_config; this.service_name = service_name; - this.client = new this.newsie({ - host: this.minisrv_config.services[service_name].upstream_address, - port: this.minisrv_config.services[service_name].upstream_port - }) + const { WTVShared } = require("./WTVShared.js"); + this.wtvshared = new WTVShared(minisrv_config); + } + + initializeUsenet(host, port = 119, tls_options = null, username = null, password = null) { + // use local self-signed cert for local server + var newsie_options = { + host: host, + port: port, + tlsPort: (tls_options !== null) ? true : false, + } + if (newsie_options.tlsPort) newsie_options.tlsOptions = tls_options; + this.client = new this.newsie(newsie_options); + if (username && password) { + this.username = username; + this.password = password; + } } connectUsenet() { return new Promise((resolve, reject) => { this.client.connect().then((response) => { - if (response.code == 200) { - resolve(true); + if (response.code == 200 || response.code == 201) { + if (response.code == 201) this.posting_allowed = false; + if (this.username && this.password) { + this.client.authInfoUser(this.username).then((res) => { + if (res.code == "381") { + res.authInfoPass(this.password).then((res) => { + if (res.code == 281) resolve(true); + else reject(res.description); + }).catch((e) => { + console.error(" * WTVNews Error:", "Command: connect", e); + reject("Could not connect to upstream usenet server"); + }); + } else { + reject(res.description) + } + }).catch((e) => { + console.error(" * WTVNews Error:", "Command: connect", e); + reject("Could not connect to upstream usenet server"); + }); + } else { + resolve(true); + } } }).catch((e) => { console.error(" * WTVNews Error:", "Command: connect", e); @@ -27,21 +65,63 @@ class WTVNews { }); } - listGroup(group) { + listGroup(group, page = 0, limit = 100, raw_range = null) { + // list of articles from group return new Promise((resolve, reject) => { - this.client.listGroup(group).then((data) => { - resolve(data); + this.selectGroup(group).then((res) => { + if (!raw_range) { + var range = { + start: (limit * page) + res.group.low, + } + range.end = range.start + limit; + if (page) range.start++; + if (range.end > res.high) delete range.group.end; + } else { + range = raw_range; + } + this.client.listGroup(group, range).then((data) => { + resolve(data); + }).catch((e) => { + console.error(" * WTVNews Error:", "Command: listGroup", e); + reject(`No such group ${group}`); + }); }).catch((e) => { - console.error(" * WTVNews Error:", "Command: listGroup", e); - reject(`No such group ${group}`); + console.error(" * WTVNews Error:", "Command: selectGroup", e); }); }) } + processGroupList(list) { + if (list) return list.newsgroups; + else return null; + } + + listGroups(search = null) { + // list of groups on the server + return new Promise((resolve, reject) => { + if (!search) { + this.client.list().then((data) => { + console.log('listGroups data', data) + resolve(this.processGroupList(data)); + }).catch((e) => { + console.error(" * WTVNews Error:", "Command: listGroups (all)", e); + reject(e); + }); + } else { + this.client.listNewsgroups((search === '*') ? '*' : '*' + search + '*').then((data) => { + resolve(this.processGroupList(data)); + }).catch((e) => { + console.error(" * WTVNews Error:", "Command: listGroups (search)", search, e); + reject(e); + }); + } + }) + } + selectGroup(group) { return new Promise((resolve, reject) => { this.client.group(group).then((response) => { - if (response.code == 211) resolve(true); + if (response.code == 211) resolve(response); else reject(`No such group ${group}`); }).catch((e) => { console.error(" * WTVNews Error:", "Command: selectGroup", e); @@ -50,20 +130,102 @@ class WTVNews { }); } - getArticle(articleID) { + getArticle(articleID, get_next_last = true) { + var articleID = parseInt(articleID); return new Promise((resolve, reject) => { + var promises = []; this.client.article(articleID).then((data) => { - resolve(data) + if (get_next_last) { + // ask server for next article + promises.push(new Promise((resolve, reject) => { + this.client.next().then((res) => { + data.next_article = res.article.articleNumber; + resolve(data.next_article); + }).catch((e) => { + data.next_article = null; + resolve(data.next_article); + }) + })); + + // ask server for previous article + promises.push(new Promise((resolve, reject) => { + this.client.last().then((res) => { + data.prev_article = res.article.articleNumber; + if (data.prev_article === articleID) { + // do it again, needed this for CodoSoft NNTPd? + this.client.article(data.prev_article).then(() => { + this.client.last().then((res) => { + data.prev_article = res.article.articleNumber; + resolve(data.prev_article); + }).catch(() => { + data.prev_article = null; + resolve(data.prev_article); + }); + }).catch(() => { + data.prev_article = null; + resolve(data.prev_article); + }); + } else { + resolve(data.prev_article); + } + }).catch(() => { + data.prev_article = null; + resolve(data.prev_article); + }) + })); + + Promise.all(promises).then(() => { + var self = this; + if (data.article.headers) Object.keys(data.article.headers).forEach((k) => { + data.article.headers[k] = self.decodeCharset(data.article.headers[k]) + }); + resolve(data); + }); + } else { + var self = this; + if (data.article.headers) Object.keys(data.article.headers).forEach((k) => { + data.article.headers[k] = self.decodeCharset(data.article.headers[k]) + }); + resolve(data); + } }).catch((e) => { reject(`Error reading article ID ${articleID}`); - console.error(" * WTVNews Error:", "Command: article", e); + console.error(" * WTVNews Error:", "Command: article", "args:", articleID, "Error:", e); }); }); } + decodeCharset(string) { + var regex = /=\?{1}(.+)\?{1}([B|Q])\?{1}(.+)\?{1}=/; + var decoded = null; + var check = string.match(regex); + if (check) { + var match = check[0]; + var charset = check[1]; + var encoding = check[2]; + var encoded_text = check[3]; + switch (encoding) { + case "B": + var buffer = new Buffer.from(encoded_text, 'base64') + decoded = buffer.toString(charset).replace(/[^\x00-\x7F]/g, "");; + break; + + case "Q": + // unimplemented + return string; + } + if (decoded) return string.replace(match, decoded); + } + return string; + } + getHeader(articleID) { return new Promise((resolve, reject) => { this.client.head(articleID).then((data) => { + var self = this; + if (data.article.headers) Object.keys(data.article.headers).forEach((k) => { + data.article.headers[k] = self.decodeCharset(data.article.headers[k]) + }); resolve(data); }).catch((e) => { reject(`Error getting header for article ID ${articleID}`); @@ -72,6 +234,19 @@ class WTVNews { }); } + getHeaderFromMessage(message, header) { + var response = null; + if (message.article.headers) { + Object.keys(message.article.headers).forEach((k) => { + if (k.toLowerCase() == header.toLowerCase()) { + response = message.article.headers[k]; + return false; + } + }) + } + return response; + } + quitUsenet() { return new Promise((resolve, reject) => { this.client.quit().then((response) => { @@ -87,24 +262,263 @@ class WTVNews { }); } + postToGroup(group, from_addr, msg_subject, msg_body, article = null, headers = null) { + return new Promise((resolve, reject) => { + var promises = []; + var messageid = null; + this.connectUsenet() + .then(() => { + if (article) { + promises.push(new Promise((resolve, reject) => { + this.selectGroup(group).then((res) => { + this.getArticleMessageID(article).then((data) => { + messageid = data; + resolve(data); + }).catch((e) => { + console.log('Error getting articleID',article, e) + reject(e) + }); + }).catch((e) => { + console.log('Error selecting group', e) + reject(e) + }); + })); + } + Promise.all(promises).then(() => { + this.client.post() + .then((response) => { + if (response.code == 340) { + var articleData = {}; + articleData.headers = { + 'Relay-Version': "version zefie_wtvp_minisrv " + this.minisrv_config.version + "; site " + this.minisrv_config.config.domain_name, + 'Posting-Version': "version zefie_wtvp_minisrv " + this.minisrv_config.version + "; site " + this.minisrv_config.config.domain_name, + 'Path': "@" + this.minisrv_config.config.domain_name, + 'From': from_addr, + 'Newsgroups': group, + 'Subject': msg_subject || "(No subject)", + 'Message-ID': "<" + this.wtvshared.generateString(16) + "@" + this.minisrv_config.config.domain_name + ">", + 'Date': this.strftime('%a, %-d %b %Y %H:%M:%S %z', new Date()) + } + if (headers) { + Object.keys(headers).forEach((k) => { + articleData.headers[k] = headers[k]; + }); + } + if (messageid) { + articleData.headers.References = messageid; + articleData.headers['In-Reply-To'] = messageid; + } + if (msg_body) articleData.body = msg_body.split("\n"); + else articleData.body = []; + + response.send(articleData).then((response) => { + this.client.quit(); + if (response.code !== 240) { + reject("Could not send post. Server returned error " + response.code); + } else { + resolve(true); + } + }).catch((e) => { + console.error(e); + this.client.quit(); + reject("Could not send post. Server returned error " + response.code); + }); + } else { + this.client.quit(); + console.error('usenet upstream uncaught error', e); + reject("Could not send post. Server returned unknown error"); + }; + }).catch((e) => { + console.error('could not connect to server', e); + reject("could not connect to server"); + }); + }); + }); + }); + } + + getArticleMessageID(articleID) { + return new Promise((resolve, reject) => { + this.client.article(articleID).then((data) => { + resolve(data.article.messageId); + }).catch((e) => { + console.error("error getting messageID from article", articleID, e) + reject(e); + }); + }); + } + getHeaderObj(NGArticles) { return new Promise((resolve, reject) => { var messages = []; - var failed = false; + var promises = []; for (var article in NGArticles) { - if (failed) continue; if (article == "getCaseInsensitiveKey") continue; - this.getHeader(NGArticles[article]).then((data) => { - if (data.article) messages.push(data.article) + promises.push(new Promise((resolve, reject) => { + this.getHeader(NGArticles[article]).then((data) => { + if (data.article) messages.push(data.article) + resolve(); + }).catch((e) => { + reject(e); + }); + })); + } + if (promises.length > 0) { + Promise.all(promises).then(() => { + if (messages.length > 0) resolve(messages); }).catch((e) => { - console.log(e, article); - failed = e; + reject("Could not read message list", e); + }); + } else { + resolve(messages); + } + }); + } + + + parseAttachments(message) { + var contype = this.getHeaderFromMessage(message, 'Content-Type'); + if (contype) { + var regex = /multipart\/mixed\; boundary=\"(.+)\"/i; + var match = contype.match(regex); + if (match) { + var boundary = "--" + match[1]; + var body = message.article.body.join("\n").split(boundary); + var attachments = []; + var i = 0; + var message_body = ''; + var message_type = 'text/plain'; + body.forEach((element) => { + var section_type = null; + var section = element.split("\n"); + attachments[i] = {}; + section.forEach((line) => { + var section_header_match = line.match(/^Content\-/i) + if (section_header_match) { + var section_match = line.match(/^Content\-Type\: (.+)\;/i) + if (section_match) { + if (section_match[1].match("text/plain")) { + section_type = section_match[1].match("text/plain")[1]; + message_type = section_type; + } else { + section_type = section_match[1]; + attachments[i].content_type = section_match[1] + } + } + section_match = line.match(/^Content\-Disposition\: (.+)\;/i) + if (section_match) { + section_match = line.match(/^Content\-Disposition\: (.+)\; filename=\"(.+)\"/i) + if (section_match) attachments[i].filename = section_match[2]; + } + section_match = line.match(/^Content-Transfer-Encoding: (.+)/i) + if (section_match) attachments[i].content_encoding = section_match[1]; + } else { + if (section_type != null) { + if (section_type.match("text/plain")) message_body += line; + else { + if (attachments[i].data) attachments[i].data += line; + else attachments[i].data = line; + } + } + } + }) + if (attachments[i].content_type) i++; + }) + attachments.pop(); + return { + text: message_body, + text_type: message_type || "text/plain", + attachments: attachments + } + } else { + var message_body = ''; + if (message.article.body) message_body = message.article.body.join("\n") + + return { text: message_body } + } + } else { + var message_body = ''; + if (message.article.body) message_body = message.article.body.join("\n") + + return { text: message_body } + } + + } + + sortByResponse(messages) { + var sorted = []; + var message_id_roots = []; + var message_relations = []; + Object.keys(messages).forEach((k) => { + var messageId = messages[k].messageId; + var ref = messages[k].headers.REFERENCES; + if (ref) { + var res = message_id_roots.find(e => e.messageId == ref); + if (res) { + // see if its attached to a root post + if (message_relations[res.messageId]) message_relations[res.messageId].push({ "messageId": messageId, "index": k }); + else message_relations[res.messageId] = [{ "messageId": messageId, "index": k }]; + } else { + // see if its related to a relation + if (Object.keys(message_relations).length > 0) { + var found = false; + Object.keys(message_relations).forEach((j) => { + if (message_relations[j].length > 0) { + Object.keys(message_relations[j]).forEach((h) => { + if (found) return; + if (message_relations[j][h].messageId == ref) { + var searchref = messages[message_relations[j][h].index].headers.REFERENCES || null; + var mainref = null; + while (searchref !== null) { + var searchart = messages.find(e => e.messageId == searchref); + var searchref = searchart.headers.REFERENCES || null; + } + mainref = searchart.messageId; + message_relations[mainref].push({ "messageId": messageId, "index": k }); + found = true; + } + }); + } + }) + } else { + message_id_roots.push({ "messageId": messageId, "index": k }); + } + } + } + else { + message_id_roots.push({ "messageId": messageId, "index": k }); + } + }); + + // sort the relations, putting root articles first, followed by their relations + var message_roots_sorted = []; + Object.keys(message_id_roots).forEach((k) => { + // sort relations by date + var article = messages[message_id_roots[k].index]; + var article_date = Date.parse(article.headers.DATE); + message_roots_sorted.push({ "article": article, "relation": null, "date": article_date }); + }); + message_roots_sorted.sort((a, b) => { return (a.date - b.date) }); + Object.keys(message_roots_sorted).forEach((k) => { + sorted.push(message_roots_sorted[k]); + + if (message_relations[message_id_roots[k].messageId]) { + var relations = []; + Object.keys(message_relations[message_id_roots[k].messageId]).forEach((j) => { + // sort relations by date + var article = messages[message_relations[message_id_roots[k].messageId][j].index]; + var article_date = Date.parse(article.headers.DATE); + relations.push({ "article": article, "relation": message_id_roots[k].messageId, "date": article_date }) + }); + relations.sort((a, b) => { return (a.date - b.date) }); + Object.keys(relations).forEach((j) => { + sorted.push(relations[j]); }); } - if (!failed) resolve(messages); - else reject("Could not read message list", failed); - }); + }) + return sorted; } + } module.exports = WTVNews; \ No newline at end of file diff --git a/zefie_wtvp_minisrv/includes/WTVNewsServer.js b/zefie_wtvp_minisrv/includes/WTVNewsServer.js new file mode 100644 index 00000000..ad72f302 --- /dev/null +++ b/zefie_wtvp_minisrv/includes/WTVNewsServer.js @@ -0,0 +1,476 @@ +class WTVNewsServer { + fs = require('fs'); + path = require('path'); + minisrv_config = null; + strftime = require('strftime'); + wtvshared = null; + username = null; + password = null; + using_auth = false; + local_server = null; + data_path = null; + featuredGroups = null + + 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.featuredGroups = minisrv_config.services['wtv-news'].featuredGroups; + const nntp_server = require('nntp-server-zefie'); + var nntp_statuses = require('nntp-server-zefie/lib/status'); + + this.username = username || null; + 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.createDataStore(); + + if (using_auth && (!username && !password)) { + // using auth, but no auth info specified, so randomly generate it + this.username = this.wtvshared.generateString(8); + this.password = this.wtvshared.generatePassword(16); + } + + if (run_server) { + // nntp-server module overrides + var self = this; + + nntp_server.prototype = { + ...nntp_server.prototype, + _authenticate: function (session) { + // authenticate + if (session.authinfo_user == self.username && session.authinfo_pass == self.password) { + session.posting_allowed = true; + return Promise.resolve(true); + } + return Promise.resolve(false); + }, + _postArticle: function (session) { + try { + session.group.name = self.getHeader(session.post_data, "newsgroups"); + if (session.group.name.indexOf(',') >= 0) return false; // cross post not implemented + return self.postArticle(session.group.name, session.post_data) + } catch (e) { + console.error(e) + return false; + } + }, + + _getGroups: function (session, time = 0, wildmat = null) { + if (time > 0) return false // unimplemented + return self.getGroups(wildmat); + }, + _getLast: function (session) { + if (!session.group.name) return nntp_statuses._412_GRP_NOT_SLCTD; + if (!session.group.current_article) return nntp_statuses._420_ARTICLE_NOT_SLCTD; + if (!self.articleExists(session.group.name, session.group.current_article)) return nntp_statuses._420_ARTICLE_NOT_SLCTD; + var res = self.getLastArticle(session.group.name, session.group.current_article); + if (!res) return nntp_statuses._422_NO_LAST_ARTICLE; + return res; + }, + + _getNext: function (session) { + if (!session.group.name) return nntp_statuses._412_GRP_NOT_SLCTD; + if (!session.group.current_article) return nntp_statuses._420_ARTICLE_NOT_SLCTD; + if (!self.articleExists(session.group.name, session.group.current_article)) return nntp_statuses._420_ARTICLE_NOT_SLCTD; + var res = self.getNextArticle(session.group.name, session.group.current_article); + if (!res) return nntp_statuses._421_NO_NEXT_ARTICLE; + return res; + }, + + _selectGroup: function (session, name) { + // selectGroup + var res = self.selectGroup(name); + if (!res.failed) { + session.group = res; + return true; + } + return false; + }, + + _buildHead: function (session, message) { + var out = ""; + Object.keys(message.headers).forEach((k) => { + if (k.length > 0) out += `${k}: ${message.headers[k]}\r\n`; + }); + out = out.substr(0, out.length - 2); + return out; + }, + + _buildHeaderField: function (session, message, field) { + if (field.indexOf(':') > 0) field = field.replace(/\:/g, ''); + var search = self.getHeader(message, field); + if (search) return search; + else return null; + }, + + _getOverviewFmt: function (session) { + var headers = [ + "Subject:", + "From:", + "Date:", + "Message-ID:", + "References:", + ":bytes", + ":lines" + ] + return headers; + }, + _getArticle: function (session, message_id) { + // getArticle + return new Promise((resolve, reject) => { + var res = self.getArticle(session.group.name, message_id); + if (!res.messageId) reject(res); + else resolve(res) + }); + }, + + _buildBody: function (session, message) { + return message.body; + }, + + _getRange: function (session, first, last) { + var res = self.listGroup(session.group.name, first, last) + if (res.failed) return false; + session.group = res.group_data; + return res.articles; + } + + } + + var tls_path = this.wtvshared.getAbsolutePath(this.minisrv_config.config.ServiceDeps + '/wtv-news'); + var tls_options = { + ca: this.fs.readFileSync(tls_path + this.path.sep + 'localserver_ca.pem'), + key: this.fs.readFileSync(tls_path + this.path.sep + 'localserver_key.pem'), + cert: this.fs.readFileSync(tls_path + 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://localhost:' + local_server_port); + } + } + + getMetaFilename(group) { + var g = this.getGroupPath(group); + if (g) return g + this.path.sep + "meta.json"; + else return null; + } + + getHeader(message, header) { + if (message.headers) { + var search = Object.keys(message.headers).find(e => (e.toLowerCase() == header.toLowerCase())); + if (search) return message.headers[search]; + } + return null; + } + + createDataStore() { + if (!this.fs.existsSync(this.data_path)) return this.fs.mkdirSync(this.data_path); + return true; + } + + + createMetaFile(group, description = null) { + const g = this.getMetaFilename(group); + if (this.fs.existsSync(g)) return false; + var metadata = this.selectGroup(group, true, true); + if (description) metadata.description = description; + this.saveMetadata(group, metadata, true); + return (!metadata.failed) ? metadata : false + } + + saveMetadata(group, metadata, creating = false) { + const g = this.getMetaFilename(group); + if (g) { + if (!this.fs.existsSync(g) && !creating) this.createMetaFile(group); + else this.fs.writeFileSync(g, JSON.stringify(metadata)); + } else return false; + } + + getMetadata(group) { + const g = this.getMetaFilename(group); + if (g) { + if (this.fs.existsSync(g)) return JSON.parse(this.fs.readFileSync(g)); + else return false + } else return false; + } + + findHeaderCaseInsensitive(headers, header) { + // returns the key with the found case + var response = null; + if (headers) { + Object.keys(headers).forEach((k) => { + if (k.toLowerCase() == header.toLowerCase()) { + response = k; + return false; + } + }) + } + return response; + } + + postArticle(group, post_data) { + var articleNumber = this.getMetadata(group).max_index + 1; + if (!articleNumber) return false; + try { + post_data.articleNumber = articleNumber; + post_data.messageId = this.getHeader(post_data, "message-id"); + if (!post_data.messageId) { + var messageId = "<" + this.wtvshared.generateString(16) + "@" + this.minisrv_config.config.domain_name + ">"; + post_data.messageId = post_data.headers['Message-ID'] = messageId; + } + + if (!post_data.headers.Path) post_data.headers.Path = "@" + this.minisrv_config.config.domain_name; + if (!post_data.headers.Subject) post_data.headers.Subject = "(No subject)"; + + post_data.headers.Date = this.strftime("%a, %-d %b %Y %H:%M:%S %z", Date.parse(post_data.headers.date)) + + // server added Injection-Date + post_data.headers['Injection-Date'] = this.strftime("%a, %-d %b %Y %H:%M:%S %z", Date.parse(Date.now())) + + // Reorder headers per examples in RFC3977 sect 6.2.1.3, not sure if needed + post_data.headers = this.wtvshared.moveObjectElement('Path', null, post_data.headers, true); + post_data.headers = this.wtvshared.moveObjectElement('From', 'Path', post_data.headers, true); + post_data.headers = this.wtvshared.moveObjectElement('Newsgroups', 'From', post_data.headers, true); + post_data.headers = this.wtvshared.moveObjectElement('Subject', 'Newsgroups', post_data.headers, true); + post_data.headers = this.wtvshared.moveObjectElement('Date', 'Subject', post_data.headers, true); + post_data.headers = this.wtvshared.moveObjectElement('Organization', 'Date', post_data.headers, true); + post_data.headers = this.wtvshared.moveObjectElement('Message-ID', 'Organization', post_data.headers, true); + // end reordering of headers + + if (this.articleExists(group, post_data.articleNumber)) return false // should not occur, but just in case + return this.createArticle(group, post_data.articleNumber, post_data); + } catch (e) { + console.error(" * WTVNewsServer Error: postArticle: ", e); + } + return false; + } + + createArticle(group, articleNumber, article) { + var g = this.getGroupPath(group); + var file = g + this.path.sep + articleNumber + ".newz"; + try { + this.fs.writeFileSync(file, JSON.stringify(article)); + var metadata = this.getMetadata(group); + metadata.max_index = metadata.max_index + 1; + metadata.total = metadata.total + 1; + this.saveMetadata(group, metadata) + return true; + } catch (e) { + console.error(" * WTVNewsServer Error: createArticle: ", e); + return false; + } + } + + getGroupPath(group) { + return this.data_path + this.path.sep + group; + } + + getArticlePath(group, article) { + return this.getGroupPath(group) + this.path.sep + article + ".newz"; + } + + articleExists(group, article) { + const g = this.getArticlePath(group, article); + if (this.fs.existsSync(g)) return true; + return false; + } + + createGroup(group, description = null) { + var g = this.getGroupPath(group); + if (!this.fs.existsSync(g)) { + this.fs.mkdirSync(g); + return this.createMetaFile(group, description) + } + return false + } + + getArticle(group, article) { + const g = this.getArticlePath(group, article); + if (!this.fs.existsSync(g)) return false; + try { + var data = JSON.parse(this.fs.readFileSync(g)); + if (data.article) data = data.article; + data.index = data.articleNumber; + if (!data.body) data.body = ['']; + if (!this.findHeaderCaseInsensitive(data.headers,'subject')) data.headers.Subject = "(No subject)"; + return data + } catch (e) { + console.error(" * WTVNewsServer Error: getArticle: ", e); + } + return null; + } + + + selectGroup(group, force_update = false, initial_update = false) { + var g = this.getGroupPath(group); + var meta = this.getMetadata(group); + if (!meta) force_update, initial_update = true; + + if (initial_update) { + var out = { + total: 0, + min_index: 0, + max_index: 0, + name: group + } + } else var out = { ...meta } + + if (meta.min_index == 0) force_update = true; + if (this.featuredGroups) { + Object.keys(this.featuredGroups).forEach((k) => { + if (group == this.featuredGroups[k].name) { + out.wildmat = 'y'; + out.description = this.featuredGroups[k].description + return false; + } + }) + } + try { + if (force_update || this.doesMetaNeedRefreshing(meta)) { + out.total = 0; + this.fs.readdirSync(g).forEach(file => { + if (file == "meta.json") return; + var articleNumber = parseInt(file.split('.')[0]); + if (out.min_index == 0) out.min_index = articleNumber; + else if (articleNumber < out.min_index) out.min_index = articleNumber; + else if (articleNumber > out.max_index) out.max_index = articleNumber; + + + out.total++; + }); + if (initial_update) { + out.last_scan = Math.floor(Date.now() / 1000); + } else { + meta = { ...meta, ...out } + if (meta.wildmat) delete meta.wildmat; + meta.last_scan = Math.floor(Date.now() / 1000); + this.saveMetadata(group, meta); + } + } + } catch (e) { + out.failed = e; + } + return out; + } + + getGroups(wildmat = null) { + var groups = []; + this.fs.readdirSync(this.data_path).forEach(file => { + if (this.fs.lstatSync(this.data_path + this.path.sep + file).isDirectory()) { + if (wildmat) { + if (file.match(wildmat)) groups.push(this.selectGroup(file)); + } else groups.push(this.selectGroup(file)); + } + }); + return groups; + } + + getLastArticle(group, current) { + var g = this.getGroupPath(group); + var res = null; + try { + var articleNumbers = []; + this.fs.readdirSync(g).forEach(file => { + if (file == "meta.json") return; + var articleNumber = parseInt(file.split('.')[0]); + articleNumbers.push(articleNumber); + }); + articleNumbers.sort((a, b) => a - b) + var index = articleNumbers.findIndex((e) => e == current) - 1; + if (index >= 0) res = articleNumbers[index]; + } catch (e) { + return e; + } + if (res) { + if (res == current) return null; + var message = this.getArticle(group, res); + if (message.messageId) { + res = { "articleNumber": res, "message_id": message.messageId }; + } + } + return res; + } + + getNextArticle(group, current) { + var g = this.getGroupPath(group); + var res = null; + try { + var articleNumbers = []; + this.fs.readdirSync(g).forEach(file => { + if (file == "meta.json") return; + var articleNumber = parseInt(file.split('.')[0]); + articleNumbers.push(articleNumber); + }); + articleNumbers.sort((a, b) => a - b) + var index = articleNumbers.findIndex((e) => e == current) + 1; + if (index < articleNumbers.length) res = articleNumbers[index]; + } catch (e) { + return e; + } + if (res) { + var message = this.getArticle(group, res); + if (message.messageId) { + res = { "articleNumber": res, "message_id": message.messageId }; + } + } + return res; + } + + doesMetaNeedRefreshing(meta) { + if (!meta) return true; + if (!meta.max_index) return true; + if (!meta.min_index) return true; + if (!meta.total) return true; + if (!meta.last_scan) return true; + if (meta.last_scan) { + if ((Math.floor(Date.now() / 1000) - this.scan_interval) > meta.last_scan) { + return true; + } + } + + return false; + } + + listGroup(group, start, end, force_update = false) { + var g = this.getGroupPath(group); + var out = { + total: 0, + min_index: 0, + max_index: 0, + name: group + } + var articles = []; + try { + var meta = this.getMetadata(group); + this.fs.readdirSync(g).forEach(file => { + if (file == "meta.json") return; + var articleNumber = parseInt(file.split('.')[0]); + if (articleNumber < start) return; + if (articleNumber > end) return false; + if (out.min_index == null) out.min_index = articleNumber; + else if (articleNumber < out.min_index) out.min_index = articleNumber; + + if (articleNumber > out.max_index) out.max_index = articleNumber; + articles.push(this.getArticle(group, articleNumber)); + out.total++; + }); + if (force_update || this.doesMetaNeedRefreshing(meta)) { + meta = { ...meta, ...out } + meta.last_scan = Math.floor(Date.now() / 1000); + this.saveMetadata(group, meta); + } + } catch (e) { + console.error(" * WTVNewsServer Error: listGroup: ", e); + out.failed = e; + } + articles.sort((a, b) => a.index - b.index) + if (out.min_index === null) out.min_index = 0; + return { + articles: articles, + group_data: meta + } + } +} + +module.exports = WTVNewsServer; \ No newline at end of file diff --git a/zefie_wtvp_minisrv/includes/WTVRegister.js b/zefie_wtvp_minisrv/includes/WTVRegister.js index 838b8dd0..9884f0d1 100644 --- a/zefie_wtvp_minisrv/includes/WTVRegister.js +++ b/zefie_wtvp_minisrv/includes/WTVRegister.js @@ -24,7 +24,6 @@ class WTVRegister { checkUsernameSanity(username) { var regex_str = "^([A-Za-z0-9\-\_]{" + this.minisrv_config.config.user_accounts.min_username_length + "," + this.minisrv_config.config.user_accounts.max_username_length + "})$"; var regex = new RegExp(regex_str); - console.log(username, username.length, regex.test(username)); return regex.test(username); } @@ -37,12 +36,14 @@ class WTVRegister { if (directory) search_dir = directory; this.fs.readdirSync(search_dir).forEach(file => { if (self.fs.lstatSync(search_dir + self.path.sep + file).isDirectory() && !return_val) { - return_val = self.checkUsernameAvailable(username, search_dir + self.path.sep + file); + if (search_dir.match(/minisrv\_internal\_nntp/)) return; + return_val = !self.checkUsernameAvailable(username, search_dir + self.path.sep + file); } - if (!file.match(/.*\.json/ig)) return; + if (!file.match(/user.*\.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); + console.log(temp_session_data.subscriber_username.toLowerCase()); if (temp_session_data.subscriber_username.toLowerCase() == username.toLowerCase()) { return_val = true; } diff --git a/zefie_wtvp_minisrv/includes/WTVShared.js b/zefie_wtvp_minisrv/includes/WTVShared.js index 995e08b9..24f2f9cd 100644 --- a/zefie_wtvp_minisrv/includes/WTVShared.js +++ b/zefie_wtvp_minisrv/includes/WTVShared.js @@ -1,7 +1,7 @@ /** * Shared functions across all classes and apps */ - +const CryptoJS = require('crypto-js'); class WTVShared { @@ -9,11 +9,11 @@ class WTVShared { fs = require('fs'); v8 = require('v8'); zlib = require('zlib'); - CryptoJS = require('crypto-js'); html_entities = require('html-entities'); // used externally by service scripts sanitizeHtml = require('sanitize-html'); iconv = require('iconv-lite'); parentDirectory = process.cwd() + extend = require('util')._extend; minisrv_config = []; @@ -40,6 +40,25 @@ class WTVShared { } } + cloneObj(src) { + if (src instanceof RegExp) { + return new RegExp(src); + } else if (src instanceof Date) { + return new Date(src.getTime()); + } else if (typeof src === 'object' && src !== null) { + var clone = null; + if (Array.isArray(src)) clone = []; + else clone = {}; + + var self = this; + Object.keys(src).forEach((k )=> { + clone[k] = self.cloneObj(src[k]); + }); + return clone; + } + return src; + } + getServiceString(service, overrides = {}) { // used externally by service scripts if (service === "all") { @@ -67,7 +86,7 @@ class WTVShared { if (typeof val === 'string') val = val.toLowerCase(); - return val === true || val === "true" || val === 1; + return (val === true || val == "on" || val === "true" || val === 1); } @@ -123,6 +142,7 @@ class WTVShared { isASCII(str) { + if (typeof str !== 'string') return false; for (var i = 0, strLen = str.length; i < strLen; ++i) { if (str.charCodeAt(i) > 127) return false; } @@ -130,7 +150,37 @@ class WTVShared { } isHTML(str) { - return /<[a-z][\s\S]*>/i.test(str); + return /<\/?[a-z][\s\S]*>/i.test() + } + + isBase64(str, opts) { + // from https://github.com/miguelmota/is-base64/blob/master/is-base64.js + if (str instanceof Boolean || typeof str === 'boolean') { + return false + } + + if (!(opts instanceof Object)) { + opts = {} + } + + if (opts.allowEmpty === false && str === '') { + return false + } + + var regex = '(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\/]{3}=)?' + var mimeRegex = '(data:\\w+\\/[a-zA-Z\\+\\-\\.]+;base64,)' + + if (opts.mimeRequired === true) { + regex = mimeRegex + regex + } else if (opts.allowMime === true) { + regex = mimeRegex + '?' + regex + } + + if (opts.paddingRequired === false) { + regex = '(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}(==)?|[A-Za-z0-9+\\/]{3}=?)?' + } + + return (new RegExp('^' + regex + '$', 'gi')).test(str) } utf8Decode(utf8String) { @@ -197,6 +247,36 @@ class WTVShared { } } + moveObjectElement(currentKey, afterKey, obj, caseInsensitive = false) { + var result = {}; + if (caseInsensitive) { + Object.keys(obj).forEach((k) => { + if (k.toLowerCase() == currentKey.toLowerCase()) { + currentKey = k; + return false; + } + }) + } + var val = obj[currentKey]; + delete obj[currentKey]; + var next = -1; + var i = 0; + if (typeof afterKey == 'undefined' || afterKey == null) afterKey = ''; + Object.keys(obj).forEach(function (k) { + var v = obj[k]; + if ((afterKey == '' && i == 0) || next == 1) { + result[currentKey] = val; + next = 0; + } + if (k == afterKey || (caseInsensitive && k.toLowerCase() == afterKey.toLowerCase())) { next = 1; } + result[k] = v; + ++i; + }); + if (next == 1) { + result[currentKey] = val; + } + if (next !== -1) return result; else return obj; + } readMiniSrvConfig(user_config = true, notices = true, reload_notice = false) { if (notices || reload_notice) console.log(" *** Reading global configuration..."); @@ -294,7 +374,8 @@ class WTVShared { var new_user_config = {}; Object.assign(new_user_config, minisrv_user_config, config); if (this.minisrv_config.config.debug_flags.debug) console.log(" * Writing new user configuration..."); - this.fs.writeFileSync(this.getAbsolutePath("user_config.json", parentDirectory), JSON.stringify(new_user_config, null, "\t")); + this.fs.writeFileSync(this.getAbsolutePath("user_config.json", this.parentDirectory), JSON.stringify(new_user_config, null, "\t")); + return true; } catch (e) { if (this.minisrv_config.config.debug_flags) { @@ -308,12 +389,48 @@ class WTVShared { } } } + return false; + } + + generateString(len, extra_chars = null) { + var result = ''; + var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + if (extra_chars) characters += extra_chars; + var charactersLength = characters.length; + for (var i = 0; i < len; i++) { + result += characters.charAt(Math.floor(Math.random() * + charactersLength)); + } + return result; + } + + generatePassword(len, simple = false) { + return this.generateString(len, (simple) ? null : '!@#$%&()[]-_+=?.'); } getMiniSrvConfig() { return this.minisrv_config; } + lineWrap(string, len = 72, join = "\n") { + if (string.length <= len) return string; + var split; + + if (string.match(" ")) { + // split if text with space, respecting words + split = string.match(new RegExp('([\\s\\S]){1,' + len + '}?!\\S', "g")); + } + if (!split) { + // fallback if above failed, or if its just a really long word (eg base64) + split = string.match(new RegExp('.{1,' + len + '}', "g")); + } else Object.keys(split).forEach((k) => { + if (split[k].substr(0, 1) == ' ') split[k] = split[k].trim(' '); + }); + + if (split) return split.join(join); + else return null; + } + /** * Returns the Last-Modified date in Unix Timestamp format @@ -389,7 +506,7 @@ class WTVShared { return obj.substr(0, 6) + ('*').repeat(9); } } else { - var newobj = Object.assign({}, obj); + var newobj = this.cloneObj(obj); if (obj.post_data) newobj.post_data = obj.post_data; if (newobj["wtv-client-serial-number"]) { var ssid = newobj["wtv-client-serial-number"]; @@ -411,18 +528,22 @@ class WTVShared { filterRequestLog(obj) { if (this.minisrv_config.config.filter_passwords_in_logs === true) { if (obj.query) { - var newobj = Object.assign({}, obj); - if (obj.post_data) newobj.post_data = obj.post_data; - Object.keys(newobj.query).forEach(function (k) { - var key = k.toLowerCase(); - switch (true) { - case /passw(or)?d/.test(key): - case /^pass$/.test(key): - newobj.query[key] = ('*').repeat(newobj.query[key].length); - break; - } - }); - return newobj; + var newobj = this.cloneObj(obj); + try { + Object.keys(obj.query).forEach(function (k) { + var key = k.toLowerCase(); + switch (true) { + case /passw(or)?d/.test(key): + case /^pass$/.test(key): + newobj.query[key] = ('*').repeat(newobj.query[key].length); + break; + } + }); + return newobj; + } catch (e) { + if (!this.minisrv_config.config.debug_flags.quiet) console.error(' *** error filtering logs', e); + return obj; + } } } return obj; @@ -435,7 +556,7 @@ class WTVShared { var post_obj = {}; post_obj.query = []; try { - var post_text = obj.post_data.toString(this.CryptoJS.enc.Utf8); + var post_text = obj.post_data.toString(CryptoJS.enc.Utf8); if (post_text.length > 0) { post_text = post_text.split("&"); for (let i = 0; i < post_text.length; i++) { @@ -454,7 +575,7 @@ class WTVShared { post_text = post_text.substring(0, post_text.length - 1); obj.post_data = post_text.hexEncode(); } catch (e) { - obj.post_data = obj.post_data.toString(this.CryptoJS.enc.Hex); + obj.post_data = obj.post_data.toString(CryptoJS.enc.Hex); } } else { // simple, no filter @@ -558,34 +679,36 @@ class WTVShared { doErrorPage(code, data = null, details = null, pc_mode = false) { var headers = null; + var minisrv_config = this.minisrv_config; switch (code) { case 401: - if (data === null) data = "Authorization Required."; + if (data === null) data = minisrv_config.config.errorMessages[code].replace(/\$\{(\w{1,})\}/g, function (x) { return minisrv_config.config[x.replace("${", '').replace('}', '')] }); if (pc_mode) headers = "401 Unauthorized\n"; else headers = code + " " + data + "\n"; headers += "Content-Type: text/html\n"; break; case 403: - if (data === null) data = "The publisher of that page has not authorized you to view it."; + if (data === null) data = minisrv_config.config.errorMessages[code].replace(/\$\{(\w{1,})\}/g, function (x) { return minisrv_config.config[x.replace("${", '').replace('}', '')] }); if (pc_mode) headers = "403 Forbidden\n"; else headers = code + " " + data + "\n"; headers += "Content-Type: text/html\n"; break; case 404: - if (data === null) data = "The service could not find the requested page."; + if (data === null) data = minisrv_config.config.errorMessages[code].replace(/\$\{(\w{1,})\}/g, function (x) { return minisrv_config.config[x.replace("${", '').replace('}', '')] }); if (pc_mode) headers = "404 Not Found\n"; else headers = code + " " + data + "\n"; headers += "Content-Type: text/html\n"; break; case 400: case 500: - if (data === null) data = this.minisrv_config.config.service_name + " ran into a technical problem."; + if (data === null) data = minisrv_config.config.errorMessages[code].replace(/\$\{(\w{1,})\}/g, function (x) { return minisrv_config.config[x.replace("${", '').replace('}', '')] }); if (details) data += "
      Details:
      " + details; if (pc_mode) headers = "500 Internal Server Error\n"; else headers = code + " " + data + "\n"; headers += "Content-Type: text/html\n"; break; default: + if (data === null && this.minisrv_config.config.errorMessages[code]) data = minisrv_config.config.errorMessages[code].replace(/\$\{(.+)\}/g, function (x) { return minisrv_config.config[x.replace("${",'').replace('}','')] }); headers = code + " " + data + "\n"; headers += "Content-Type: text/html\n"; break; @@ -652,7 +775,23 @@ class WTVShared { return this.zlib.deflateSync(data, { 'level': 9 }).toString('base64'); } - + getTemplate(service_name, path, path_only = false) { + var self = this; + var outdata = null; + var found = false + this.minisrv_config.config.ServiceTemplates.forEach(function (template_vault_dir) { + if (found) return; + var search = self.getAbsolutePath(template_vault_dir + self.path.sep + service_name + self.path.sep + path); + if (self.fs.existsSync(search)) { + if (path_only) outdata = search; + else outdata = self.fs.readFileSync(search); + if (!self.minisrv_config.config.debug_flags.quiet) console.log(" * Found " + search + " to handle template"); + found = true; + return false; + } + }); + return outdata; + } } class clientShowAlert { diff --git a/zefie_wtvp_minisrv/includes/config.json b/zefie_wtvp_minisrv/includes/config.json index 39c2e065..0c3a8049 100644 --- a/zefie_wtvp_minisrv/includes/config.json +++ b/zefie_wtvp_minisrv/includes/config.json @@ -6,7 +6,11 @@ "UserServiceVault", "ServiceVault" ], - "ServiceDeps": "ServiceDeps", + "ServiceTemplates": [ + "UserTemplates", + "ServiceDeps/templates" + ], + "ServiceDeps": "ServiceDeps", "SessionStore": "SessionStore", "SharedROMCache": "SharedROMCache", "enable_shared_romcache": true, @@ -31,8 +35,12 @@ "show_detailed_splash": true, "show_diskmap": false, "unauthorized_url": "wtv-1800:/unauthorized?", + "enable_port_isolation": true, "allow_guests": true, "domain_name": "wtv.zefie.com", + "ssid_block_list": [ + "minisrv_internal_nntp" + ], "user_accounts": { "max_users_per_account": 6, "min_username_length": 5, @@ -43,7 +51,30 @@ "min_length": 5, "max_length": 32, "form_size": 16 - } + }, + "errorMessages": { + "400": "${service_name} ran into a technical problem. Please try again.", + "401": "Authorization Required.", + "403": "The publisher of that page has not authorized you to view it.", + "404": "The service could not find the requested page.", + "500": "${service_name} ran into a technical problem. Please try again." + }, + "lockdownWhitelist": [ + "wtv-1800:/preregister", + "wtv-head-waiter:/login", + "wtv-head-waiter:/ValidateLogin", + "wtv-head-waiter:/login-stage-two", + "wtv-head-waiter:/relogin", + "wtv-head-waiter:/ROMCache/Spacer.gif", + "wtv-head-waiter:/ROMCache/NameStrip.gif", + "wtv-head-waiter:/images/PasswordBanner.gif", + "wtv-head-waiter:/ROMCache/UtilityBullet.gif", + "wtv-head-waiter:/images/NameBanner.gif", + "wtv-head-waiter:/bad-disk", + "wtv-head-waiter:/images/signin_new_mail.gif", + "wtv-head-waiter:/images/signin_no_mail.gif", + "wtv-log:/log" + ] }, "services": { "wtv-head-waiter": { @@ -60,10 +91,34 @@ }, "wtv-news": { "port": 1605, - "disabled": true, + "local_nntp_port": 57319, + "local_nntp_requires_auth": true, "modules": [ "WTVNews" - ] + ], + "featuredGroups": [ + { + "name": "WebTV", + "group": "webtv.users", + "description": "A moderated discussion with WebTV customers" + }, + { + "name": "Hacking", + "group": "alt.discuss.webtv.hacking", + "description": "Not advertiser friendly" + }, + { + "name": "minisrv", + "group": "minisrv.users", + "description": "The server behind it all" + }, + { + "name": "MIDIs", + "group": "alt.discuss.midis", + "description": "Explore the sounds of Beatnik with your WebTV" + } + ], + "groupMetaRefreshInterval": 86400 }, "wtv-register": { "port": 1607, @@ -122,11 +177,17 @@ }, "wtv-guide": { "port": 1621, - "connections": 3 + "connections": 3, + "modules": [ + "WTVGuide" + ] }, "wtv-mail": { "port": 1608, - "connections": 3 + "connections": 3, + "modules": [ + "WTVNews" + ] }, "wtv-passport": { "port": 1654 diff --git a/zefie_wtvp_minisrv/package-lock.json b/zefie_wtvp_minisrv/package-lock.json index 5fd8a344..2b4f6673 100644 --- a/zefie_wtvp_minisrv/package-lock.json +++ b/zefie_wtvp_minisrv/package-lock.json @@ -1,12 +1,12 @@ { "name": "zefie_wtvp_minisrv", - "version": "0.9.32", + "version": "0.9.33", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "zefie_wtvp_minisrv", - "version": "0.9.32", + "version": "0.9.33", "license": "GPL3", "dependencies": { "adm-zip": "^0.5.9", @@ -14,10 +14,12 @@ "easy-crc": "0.0.2", "endianness": "^8.0.2", "express": "^4.18.2", + "follow-redirects": "^1.15.2", "html-entities": "^2.3.3", "iconv-lite": "^0.6.3", "mime-types": "^2.1.35", "newsie": "^1.2.1", + "nntp-server-zefie": "git+https://git@github.com:zefie/nntp-server", "proxy-agent": "^5.0.0", "sanitize-html": "^2.7.2", "socks-proxy-agent": "^6.2.1", @@ -263,6 +265,14 @@ "node": ">= 6" } }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -535,6 +545,25 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -861,6 +890,18 @@ "node": ">=8.9.0" } }, + "node_modules/nntp-server-zefie": { + "name": "nntp-server", + "version": "3.1.0", + "resolved": "git+https://git@github.com/zefie/nntp-server.git#c2721f81a98dacda0a272dc8c98f8155a955523f", + "license": "MIT", + "dependencies": { + "debug": "^4.3.3", + "denque": "^2.0.1", + "serialize-error": "^8.1.0", + "split2": "^4.1.0" + } + }, "node_modules/object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -1179,6 +1220,20 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -1268,6 +1323,14 @@ "node": ">=0.10.0" } }, + "node_modules/split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -1313,6 +1376,17 @@ "node": ">= 0.8.0" } }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -1576,6 +1650,11 @@ "vm2": "^3.9.8" } }, + "denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1778,6 +1857,11 @@ } } }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2016,6 +2100,16 @@ "resolved": "https://registry.npmjs.org/newsie/-/newsie-1.2.1.tgz", "integrity": "sha512-41jhtKmlpSc27oIBkp681fm4aLURPT/AgeBvSRicxNPWDVeHLaq7tSvG/OsEXz7g41thgv9JMV1ZjYSABMiYVA==" }, + "nntp-server-zefie": { + "version": "git+https://git@github.com/zefie/nntp-server.git#c2721f81a98dacda0a272dc8c98f8155a955523f", + "from": "nntp-server-zefie@git+https://git@github.com:zefie/nntp-server", + "requires": { + "debug": "^4.3.3", + "denque": "^2.0.1", + "serialize-error": "^8.1.0", + "split2": "^4.1.0" + } + }, "object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -2266,6 +2360,14 @@ } } }, + "serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "requires": { + "type-fest": "^0.20.2" + } + }, "serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -2334,6 +2436,11 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" }, + "split2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", + "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==" + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2367,6 +2474,11 @@ "prelude-ls": "~1.1.2" } }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", diff --git a/zefie_wtvp_minisrv/package.json b/zefie_wtvp_minisrv/package.json index 60e5185f..e84c02a8 100644 --- a/zefie_wtvp_minisrv/package.json +++ b/zefie_wtvp_minisrv/package.json @@ -1,6 +1,6 @@ { "name": "zefie_wtvp_minisrv", - "version": "0.9.33", + "version": "0.9.35", "description": "WebTV Service (WTVP) Emulation Server", "main": "app.js", "homepage": "https://github.com/zefie/zefie_wtvp_minisrv", @@ -32,10 +32,12 @@ "easy-crc": "0.0.2", "endianness": "^8.0.2", "express": "^4.18.2", + "follow-redirects": "^1.15.2", "html-entities": "^2.3.3", "iconv-lite": "^0.6.3", "mime-types": "^2.1.35", "newsie": "^1.2.1", + "nntp-server-zefie": "git+https://git@github.com:zefie/nntp-server", "proxy-agent": "^5.0.0", "sanitize-html": "^2.7.2", "socks-proxy-agent": "^6.2.1", diff --git a/zefie_wtvp_minisrv/sync_nntp.js b/zefie_wtvp_minisrv/sync_nntp.js new file mode 100644 index 00000000..072b4c53 --- /dev/null +++ b/zefie_wtvp_minisrv/sync_nntp.js @@ -0,0 +1,123 @@ +// no wildcard (yet?) +const groups_to_sync = [ + "webtv.users" +] + + + +const fs = require('fs'); +const path = require('path'); +const crypto = require('crypto'); +var classPath = __dirname + "/includes/"; +const { WTVShared } = require(classPath + "WTVShared.js"); +const wtvshared = new WTVShared(); // creates minisrv_config +classPath = wtvshared.getAbsolutePath(classPath, __dirname); +const minisrv_config = wtvshared.getMiniSrvConfig(); +const WTVNews = require(classPath + "/WTVNews.js"); +const WTVNewsServer = require(classPath + "/WTVNewsServer.js"); +var data_path = wtvshared.getAbsolutePath(minisrv_config.config.SessionStore + '/minisrv_internal_nntp'); +const service_name = "wtv-news"; + +if (!minisrv_config.services[service_name].upstream_address) { + console.error("minisrv config not configured with usenet upstream"); + process.exit(1); +} + +if (!minisrv_config) { + console.error("Something went wrong loading minisrv config"); + process.exit(1); +} + +if (!minisrv_config.config.debug_flags.quiet) console.log(" *** Successfully read minisrv configuration...."); + + +const service_config = minisrv_config.services[service_name]; +const wtvnewsserver = new WTVNewsServer(minisrv_config, minisrv_config.services['wtv-news'].local_server_port, false, null, null, false); + +const wtvnews = new WTVNews(minisrv_config, service_name); + +if (service_config.upstream_auth) { + wtvnews.initializeUsenet(service_config.upstream_address, service_config.upstream_port, service_config.upstream_tls || null, service_config.upstream_auth.username || null, service_config.upstream_auth.password || null); +} else { + wtvnews.initializeUsenet(service_config.upstream_address, service_configupstream_port, service_config.upstream_tls || null); +} + + + +function verifyMessage(group, articleNumber, article) { + var g = wtvnewsserver.getGroupPath(group); + var file = g + path.sep + articleNumber + ".newz"; + if (!fs.existsSync(file)) return false; + var old_data = fs.readFileSync(file); + var new_data = JSON.stringify(article.article); + + var old_data_hash = crypto.createHash('md5').update(old_data).digest("hex"); + var new_data_hash = crypto.createHash('md5').update(new_data).digest("hex"); + return (old_data_hash === new_data_hash); +} + +function deleteMissing(group, articles) { + var g = wtvnewsserver.getGroupPath(group); + try { + fs.readdirSync(g).forEach(file => { + var articleNumber = parseInt(file.split('.')[0]); + file = g + path.sep + file; + if (!articles.find(e => (e == articleNumber))) { + console.log(" * ", group, "article", articleNumber, "deleted from upstream, removing locally") + fs.rmSync(file); + } + }); + return true; + } catch (e) { + console.log(e); + return false; + } +} + +wtvnews.connectUsenet().then((res) => { + if (res) { + groups_to_sync.forEach((group) => { + console.log(group); + wtvnews.selectGroup(group).then((res) => { + var range = { + start: res.group.low, + end: res.group.high + } + wtvnews.listGroup(group, null, null, range).then((res) => { + if (res.group.articleNumbers) { + var promises = []; + wtvnewsserver.createGroup(group); + var meta = wtvnewsserver.getMetadata(group); + meta.last_article_id = res.group.high; + wtvnewsserver.saveMetadata(group, meta); + //deleteMissing(group, res.group.articleNumbers) + res.group.articleNumbers.forEach((article) => { + promises.push(new Promise((resolve, reject) => { + wtvnews.getArticle(article, false).then((message) => { + res = wtvnewsserver.createArticle(group, article, message); + if (res) { + if (res == "exists") { + console.log(" * ", group, "article", article, "already exists") + } else { + console.log(" * Created", group, "article", article, res) + } + resolve(true) + } else { + console.log(" ! Failed to create file for ", group, "article", article, "with error", res); + resolve(false) + } + }); + })); + }) + Promise.all(promises).then(() => { + wtvnews.quitUsenet(); + process.exit(0); + }); + } else { + wtvnews.quitUsenet(); + } + }) + }); + }) + } +}); diff --git a/zefie_wtvp_minisrv/user_config.example.json b/zefie_wtvp_minisrv/user_config.example.json index e09e29b1..57ba47d1 100644 --- a/zefie_wtvp_minisrv/user_config.example.json +++ b/zefie_wtvp_minisrv/user_config.example.json @@ -26,7 +26,32 @@ ] }, "hide_ssid_in_logs": true, - "verbosity": 2 + "verbosity": 2, + "errorMessages": { + "999": "My Custom Error Code Message", + "400": "${service_name} ran into a technical problem. Please try again.", + "401": "Authorization Required.", + "403": "The publisher of that page has not authorized you to view it.", + "404": "The service could not find the requested page.", + "500": "${service_name} ran into a technical problem. Please try again." + }, + "lockdownWhitelist": [ + "wtv-1800:/preregister", + "wtv-head-waiter:/login", + "wtv-head-waiter:/ValidateLogin", + "wtv-head-waiter:/login-stage-two", + "wtv-head-waiter:/relogin", + "wtv-head-waiter:/ROMCache/Spacer.gif", + "wtv-head-waiter:/ROMCache/NameStrip.gif", + "wtv-head-waiter:/images/PasswordBanner.gif", + "wtv-head-waiter:/ROMCache/UtilityBullet.gif", + "wtv-head-waiter:/images/NameBanner.gif", + "wtv-head-waiter:/bad-disk", + "wtv-head-waiter:/images/signin_new_mail.gif", + "wtv-head-waiter:/images/signin_no_mail.gif", + "wtv-log:/log", + "wtv-custom-service:/my-cool-page-everyone-should-have-access-to" + ] }, "services": { "wtv-1800": { @@ -67,8 +92,13 @@ "upstream_address": "192.168.11.8", "upstream_port": 1699, "upstream_auth": { - "username": "not_yet", - "password": "implemented" + "username": "myusername", + "password": "mypassword" + }, + "upstream_tls": true, + "local_auth": { + "username": "mylocaluser", + "password": "mylocalpass" } } }, @@ -77,16 +107,17 @@ "Personal": [ { "title": "The Midnight Archive", - "url": "http://archive.midnightchanne.net/", + "url": "http://archive.midnightchannel.net/", "image_type": "url", "image": "canned/midnightchannel.gif" }, { "title": "WebTV/MSNTV Secrets", - "url": "http://turdinc.kicks-ass.net/Msntv/", + "url": "http://turdinc.kicks-ass.net/Msntv/index2.html", "image_type": "url", "image": "canned/mattman69.gif" } ] } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj index 6210d4a0..9d3f8b19 100644 --- a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj +++ b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj @@ -38,132 +38,129 @@ Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - Code - - - Code - @@ -192,6 +189,12 @@ + + Code + + + Code + @@ -933,6 +936,9 @@ Code + + Code + @@ -979,7 +985,7 @@ - + @@ -1014,6 +1020,9 @@ Code + + Code + @@ -1103,6 +1112,7 @@ + @@ -1147,48 +1157,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -