From 6300348e2e31622cd755966cfaebd532cb6b2b0a Mon Sep 17 00:00:00 2001 From: zefie Date: Sun, 11 Jul 2021 18:28:53 -0400 Subject: [PATCH] v0.6.1 - fix challenge exchange and tickets - full encrypted convo to splash - proper encryption sessions to maintain working RC4 stream - proper nodejs versioning, encryption working - minor changes, included mini tutorial, version inc - fix file loading issues --- .gitignore | 3 +- README.md | 33 + hacktv_updsrv/.gitignore | 370 +++++++++ hacktv_updsrv/README.md | 3 - .../ServiceDeps/LC2/LC2_OISP_5555732_56k.tok | Bin 0 -> 6047 bytes .../LC2/LC2_WTV_18006138199_56k.tok | Bin 0 -> 6063 bytes .../LC2/artemis_18004653537.tok | Bin .../LC2/artemis_18006138199.tok | Bin ...sted wtv-log requests will appear here.txt | 0 .../ServiceVault/htv-update/upd/diskmap.txt | 7 - .../ServiceVault/htv-update/upd/updater.html | 48 -- hacktv_updsrv/ServiceVault/wtv-1800/LC2.tok | 32 - .../ServiceVault/wtv-1800/finish-prereg.js | 46 ++ .../wtv-1800/offer-open-isp-suggest.js | 33 - .../ServiceVault/wtv-1800/preregister.js | 12 +- .../ServiceVault/wtv-flashrom/get-lc2-page.js | 98 +++ .../wtv-flashrom/lc2-download-failed.html | 50 ++ .../wtv-flashrom/lc2-download-failed.js | 53 ++ .../ServiceVault/wtv-flashrom/willie.js | 20 + .../wtv-head-waiter/finalize-security.js | 24 + .../wtv-head-waiter/login-stage-two.js | 100 ++- .../ServiceVault/wtv-head-waiter/login.js | 79 +- .../ServiceVault/wtv-head-waiter/test.js | 2 - hacktv_updsrv/ServiceVault/wtv-home/home.js | 46 ++ .../ServiceVault/wtv-home/splash.txt | 25 + hacktv_updsrv/ServiceVault/wtv-log/log.js | 15 +- .../wtv-star/images/HackTVLogo.gif | Bin 0 -> 16880 bytes .../wtv-star/images/HackTVLogoJewel.gif | Bin 0 -> 5845 bytes .../wtv-star/images/WebTVLogoJewel.gif | Bin 0 -> 7459 bytes .../ServiceVault/wtv-tricks/blastcache.txt | 17 + .../ServiceVault/wtv-tricks/go-offline.js | 42 + .../wtv-update/content/diskmaps/htvupdate.txt | 10 + .../content/htvupdate/Games}/Games.html | 2 +- .../content/htvupdate/Games}/cSetup.html | 0 .../htvupdate/MattMan/Tricks}/tricks.html | 0 hacktv_updsrv/ServiceVault/wtv-update/sync.js | 39 + .../{htv-update => wtv-update}/update.html | 12 +- .../updatesuccess.txt | 1 + hacktv_updsrv/app.js | 719 ++++++++++++++---- hacktv_updsrv/hacktv_updsrv.njsproj | 49 +- hacktv_updsrv/package-lock.json | 35 +- hacktv_updsrv/package.json | 5 +- hacktv_updsrv/services.json | 47 ++ hacktv_updsrv/wtvsec.js | 224 ++++-- 44 files changed, 1879 insertions(+), 422 deletions(-) create mode 100644 README.md create mode 100644 hacktv_updsrv/.gitignore delete mode 100644 hacktv_updsrv/README.md create mode 100644 hacktv_updsrv/ServiceDeps/LC2/LC2_OISP_5555732_56k.tok create mode 100644 hacktv_updsrv/ServiceDeps/LC2/LC2_WTV_18006138199_56k.tok rename hacktv_updsrv/{ServiceVault/wtv-1800 => ServiceDeps}/LC2/artemis_18004653537.tok (100%) rename hacktv_updsrv/{ServiceVault/wtv-1800 => ServiceDeps}/LC2/artemis_18006138199.tok (100%) create mode 100644 hacktv_updsrv/ServiceLogPost/client-posted wtv-log requests will appear here.txt delete mode 100644 hacktv_updsrv/ServiceVault/htv-update/upd/diskmap.txt delete mode 100644 hacktv_updsrv/ServiceVault/htv-update/upd/updater.html delete mode 100644 hacktv_updsrv/ServiceVault/wtv-1800/LC2.tok create mode 100644 hacktv_updsrv/ServiceVault/wtv-1800/finish-prereg.js delete mode 100644 hacktv_updsrv/ServiceVault/wtv-1800/offer-open-isp-suggest.js create mode 100644 hacktv_updsrv/ServiceVault/wtv-flashrom/get-lc2-page.js create mode 100644 hacktv_updsrv/ServiceVault/wtv-flashrom/lc2-download-failed.html create mode 100644 hacktv_updsrv/ServiceVault/wtv-flashrom/lc2-download-failed.js create mode 100644 hacktv_updsrv/ServiceVault/wtv-flashrom/willie.js create mode 100644 hacktv_updsrv/ServiceVault/wtv-head-waiter/finalize-security.js delete mode 100644 hacktv_updsrv/ServiceVault/wtv-head-waiter/test.js create mode 100644 hacktv_updsrv/ServiceVault/wtv-home/home.js create mode 100644 hacktv_updsrv/ServiceVault/wtv-home/splash.txt create mode 100644 hacktv_updsrv/ServiceVault/wtv-star/images/HackTVLogo.gif create mode 100644 hacktv_updsrv/ServiceVault/wtv-star/images/HackTVLogoJewel.gif create mode 100644 hacktv_updsrv/ServiceVault/wtv-star/images/WebTVLogoJewel.gif create mode 100644 hacktv_updsrv/ServiceVault/wtv-tricks/blastcache.txt create mode 100644 hacktv_updsrv/ServiceVault/wtv-tricks/go-offline.js create mode 100644 hacktv_updsrv/ServiceVault/wtv-update/content/diskmaps/htvupdate.txt rename hacktv_updsrv/ServiceVault/{htv-update/upd => wtv-update/content/htvupdate/Games}/Games.html (95%) rename hacktv_updsrv/ServiceVault/{htv-update/upd => wtv-update/content/htvupdate/Games}/cSetup.html (100%) rename hacktv_updsrv/ServiceVault/{htv-update/upd => wtv-update/content/htvupdate/MattMan/Tricks}/tricks.html (100%) create mode 100644 hacktv_updsrv/ServiceVault/wtv-update/sync.js rename hacktv_updsrv/ServiceVault/{htv-update => wtv-update}/update.html (69%) rename hacktv_updsrv/ServiceVault/{htv-update => wtv-update}/updatesuccess.txt (76%) create mode 100644 hacktv_updsrv/services.json diff --git a/.gitignore b/.gitignore index 9491a2fd..4a8a2dea 100644 --- a/.gitignore +++ b/.gitignore @@ -360,4 +360,5 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd +/hacktv_updsrv/ServiceLogPost/1626307222_warning_812bf30600b002bb diff --git a/README.md b/README.md new file mode 100644 index 00000000..18da1414 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# wtv minisrv node.js + +The ***wtv minisrv***, or "***hacktv_updsrv***" project is a node.js project that provides a mini WebTV Server, with wtv-encryption support for advanced level box access. + +This open source server is in alpha status. Use at your own risk. + +### Current status: +- Can encrypt and decrypt SECURE ON and arbitrary encrypted data +- Can handle psuedo encryption (box sends SECURE ON but does not encrypt) +- Can handle client "relogin" and "reconnect" events + +### Current issues: +- Probably can't handle more than one box at a time +- Power cycling box and re-connecting via ConnectSetup may invalidate encryption until server is restarted +- wtv-update:/update does not yet function as intended + +### Feature Todo: +- Test and enable flashrom flashing functionality (at least for LC2 and higher) +- (maybe) Proper wtv-star (generic service outage page) support (maybe useful for allowing a unit to multiple sub-minisrvs). +- (maybe) implement HTTP proxy (needs to be able to defluff most of the web, think retro WAP converter) +- (maybe) enable "internet mode" (let user outside of minisrv) +- (maybe) wtvchat stuff +- (probably not) url tokenizer + +### How To Use: +- Install [node.js](https://nodejs.org/en/download/) +- Download a snapshot (either of master, or of any commit/branch/relase/tag etc) +- Extract zip somewhere and enter that directory with a command prompt +- Run `npm install` +- Check any configuration (services.json) +- Run `node app.js` +- Test with a WebTV Viewer or connect with a real box +- To connect with a real box, you will need to open ports in your firewall and have a way to connect your WebTV (and preferably reroute 10.0.0.1 to the server) diff --git a/hacktv_updsrv/.gitignore b/hacktv_updsrv/.gitignore new file mode 100644 index 00000000..6d6f8150 --- /dev/null +++ b/hacktv_updsrv/.gitignore @@ -0,0 +1,370 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# ServiceLogPost Posted Logs +ServiceLogPost/*_* + +# Large files not pertaining to the service code +ServiceVault/wtv-flashrom/content/* +ServiceVault/wtv-music/content/* + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd +/hacktv_updsrv/ServiceLogPost/1626307222_warning_812bf30600b002bb diff --git a/hacktv_updsrv/README.md b/hacktv_updsrv/README.md deleted file mode 100644 index 19772a65..00000000 --- a/hacktv_updsrv/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# hacktv_updsrv - - diff --git a/hacktv_updsrv/ServiceDeps/LC2/LC2_OISP_5555732_56k.tok b/hacktv_updsrv/ServiceDeps/LC2/LC2_OISP_5555732_56k.tok new file mode 100644 index 0000000000000000000000000000000000000000..a8116c0a58a8730a064e81e7e50bf0ac6b4fb861 GIT binary patch literal 6047 zcmW-lcUV)`|Hse0Hwhr)CSiyO<^}{A0kWBa#4xsxILXlrY28$hjXzrPmLwodq^ecsPG|D1E4=lpR#=lycl^hBSDN2i1d^EjC^Bb2bxX#n{wowu{Rk zg=86&1&lx!JrWNxoL~{W5!vlw!^;}?z)fr6%_>;-I$W4cUk)U}K+cpe0A-sC{j&mr z%t>w9hJ2C=dD05y{PZAdlK>PhM&_WcHWlcG+K4TDs2VKw^o4f-NkBbVOP6f{S$F8# z1<|zd0*Wk}{t>tbk*Ap|3OyLEf~*Jx2osv?li;B!rVP?c5GXwRBr~U(QI^XJT*0E} zd=!}THyH2<%mLYvFv$h+r=ma{mh(yg8DHjspTj}49?u(NtQ;E)@B~L08?n4*dLC#< zl=FQVD?ye6F5!Sk2D~C7e?@o!gZ;R$AiRfdB8}B#CSf*Ph{hx=3_N>l=|ZZBAT@+x zpG8$ogaI)K^Va6-NXxbGQTDQ!qNCtOEUq}UwAjvz#lJ40AxdAQG>4m(8OQ}tItwW~ z#1%r55p#RO>j~1VGa51!++2AIXgd!%q(Xf>;b1gbUwK)iGmhuej zQjjfA)p8vFu*`zJ39xyyZZm-yt1x*!Q#dURhZD9|^CJ zD%|C?iVCm31ir@BFk#hm)gw8sR)MwhKZIPc4yf=d{oht|O^CmlFle8f=ZlrHQe5EM ze7A%htIRGe#TG+vL+V$6UT3J{6$4I%T#!ityv4<7gC(vd=n_h@v`xJ=uBri>ud@|3~@n5*O+SCu-AYg$j5 z)O5U#0+C)&x7iP}oTXR~4oU`zd4o!=Cu)t_r$p_wKueY0*kIEb4HnXyzKY6EWrRn(08JAvgbR6bT=&B155Y9zS37VP)c|_jw^Ts8D86R`UD5%D3z#)ClSO_hE5JaCFr9M zrDn6#PmnC(D(3}U2``zeO!-435s1?Q@&!?7u_$WgSe=LIn9ey1H;LCh}8?B|I)~)lD+hZ!r+A zDkMK2@e6c+L`lYgOIV}-F>L3}_OBWJ5xijbeP=Mj4-fVf2YVef@hHieT{uF~+Hp$C z*1<1XT^jbWd!JzEO*kTCAY*AyJAj`3}!`N(~whsry`l6Z0vT z`9BI5$q7pXOJ~p;8$KAmF_y+1*tXGzyWdkI$D~K_rftT5Mf^5X-~O^RPb1dK7#^R| zJJidM9H{0W(8xcm78tZyJ~-T}PEOx_q8}=U3T}gZ*9s84dK7Ab;`8ngy;E|v2y{YG z?Avg4e3^Of*W&yv%tR7Zqq@f4xC(e52=G&K!0E{ET%+J{$X@t45TPQ(zA`rjb<5|i zC+xbTbaI!hHG3p52RgOglBARguP8jHz$q_%K(uY0r!+okwO%lUkOC=Dygu;>AvU!SrX2 z7PCcVv3}r^2a0nh@{YI5hnDwJd$$jz!f&)CBPR5Vmo`8g<&54Gi^kF-JB@C4{i?=j z+~nVWal%GgMv?13ugvJtpKI>eU{aB0f=ndLR{aK(R0wg~ zNl}M7!SVI16xXCUCW#D(9Qa3+fme+Mjii@U6NiYT?X=mX?cQ6Y+r4Ck%8H$Bo_ksbX}Jf6Q2J$h{x9-#_Gu4!ODCaa_dTB^ zXn)2sqXuJxnDLOj$HY)WK}Vd~Xg0cyd7Qh;o1eLhD##5`^WPpzflakkeuf`^FgWNE zO(0CCrKY3l9>;=Xg#C^uChaAb@Nz&1wB6n*@(_tUgg(EIo#Scfi_m8KBC5_eW4|da zB7;(R21-iF2n|`%levughS1#m6D3)29&3pec@{XgQ_uQ{k}3P4J#uQ4cZ!%AnHmuA zBK({4USMzX%gcYodS&M~Dt_XX%4F-x`;0#J>o_1fw`$Fc0jDYvV_a=%y zpH}4U`$yqwIS@Ts9Z*rt=(mzpLH;r)zlG2+svA7su_0CTNKUj z_0GIX-+z0_{Y4$J9i>@{@o$3{q}+dnA;IcmcJ}r&IH}>^-lp3dKk9og5Gd3M z)V=6V>W!-rG+6_w7B6hlPl&zMcKb=~Rk%JlxRM0RIC8>AXI9_jAbf?H8Q{9b$ zu9W3toD3T7ulie0kiWT<*(CYQvz-l6vDHQ^dCu+r8base!hY7M4Dk3%4>5~z9xG55 zVx{E?HcX)>RA!>t@zkPP1msq;#rV9I2juQJgQ?s}hZmpB<;Kqo#VPRuesVG|Vdcz8 zOn6BbT^0V`ApLvO)tUdzpfvHV+4@NMS%3ao8W)m`FVPQqm1v z>y7;+`?ly?9KWL*%;gQr>sRP;!l$u)M+e?;ZN#_tw}4>`Z0X(H`yU331PR6NO80BY zdu^uSESD%~F9hj_dsDM#8afeoy!&hH%JTddWv8WFF=GsGQJ?35`zLb#eE;10pOl|? z8Hf|#j}ElOJX}uQ79*5ReLbb? zla|mQFV_$yg)_M;1Xl^;@@NBh<} z3k_v6K90Wh&HfplCucf~A5h6lb&pOg3S_~_WuHH?U(dGT)h1a+`;=H&@%j6bT!s?A>Yhu(Z`Mvu zZcG`vJ)1gopXBIcm*Jb#k4aBhvU;Lo0+dY*7qejnrx<+1+2G+STah!V6QNp`{f{);3al`AH)k6lv&Fok{^$sdRd)2T5?gS;}XQB55AI zJqT#_qF8#SnG+rHm46_LznF^tHylLxkK)}wsfA-8fjZ<%{M4$5m`G;Jj#l$v=X3KuBcfBh!9aTKN_Be($kue}s zB+6IVWC~1WwbU#Oyw7`(%KL!VqflUm0wR;EQyrJ#OkzX02PseEqQ_>pU;N4Dx-C?+ zT4pp4TruhU+e4=3-pr|xl@#KIxqt1KDzPXSbEn0nUke86#O+-rqPhT&m+kM9;T~63 zo4<>&T#2xzeioq_V62r3HXk@euk@jISH_f0Fq2_irwia_fWp#9k6AiL`C-JtmsTx< zS*(E#7+IUyt=3EQbc*P5!Cjre9|Z0`DGrT4t8=?$EIYU6zYJ zBTM`<>msaQN)Cium|nA*`dO_TTtDb|o;T<;H@QKycI$>`m1<*S714{m=V#ZeZk+O^ z=lw7t+V_vUX=X$C)BbpCnLV$gHC}aXGG5gg)BrkJZUu*^`{4f?u7zhiGR;<#$w=BF zKM;F<$@-FI4XgS7`0n7BL#IkwUuIRmhU{Xw6{eqPJg}!nuV|9l&5F%5ME0vMvOEBh z?^NpXtcz7G+3GUo(#bRa7F|Y@Or9i8O{(H89SV&ApSLyRCsP*~z4oL4H>qwK~HV z?lMXx6ae?=oeTPPNNh;x;hb1o>`FX$Z{UiDjv6v=&H=5Yz;lj|zv^m_0PFhT^V`~I z$R;-@8!i@`Hs2114qFN!30^noyk&rVKQ$1Ip>1XYt;;72OIo+nI!brct(8kMW~!pQ zfutWgnD#D6KLmL~iuy@g;d%GTeERtJR?Z~!=i2{*b!(g}0Y{2WLw56hNORyWS+HU} zo?7}%SChS&M$aCG;*+m2$VkTehXZv)dF&E0Fr}jrKQkkJCkaqy5Ldf*E z1K!Vey8vqcXL8Hy3a^!NW45+mrQ1K5`BmoC*!Ee;9jR(lAT#NFHG@{)Q54(RUHq}b4U_xg(&Z`ry^6A~smuPFTkp!e zziM;0LGBBN%x~!OPF7jIqNao|f)}tdOw_?Jkw+$a3i~G_1w^gHY0S=}!tQwK7R)%3tqN zkVLI1A$`_j#Kb23nIRUG7jjayR8wAbZ7ZE4p}nJV&aRaw8wM`TDt)ugo{uzpO-P|n zn14=g|LtLwr@9LLS01v6#KMi}Ms&xRrlSQ4*>;5LcH)GDgt-Nw$7T~2SEzJPWE^J9 z=(mX>VY3?+zj5Hi}(Fy7A7jvTh4wjO8U#MQBDz2g-n|Ezcmw8aiQA&5k zLdq%@W%VUx@l?b7zrf>e57|Y1-&;@Y`&T>X)kPj4T6z!~m>vK|b>hG^wQ7BFxVgL$ z!J_9QwJ}(gk;Kp<6JfA1?^XU%((za5lF@9E$4@ugpSo_<&3Vr#vr9^fN-!1o;Lw4w zKG!yrmC$KDBQCM%JFKZv0Jw|jZ&(@W3`9UbYR!m1rj1uDavt|ZD2HpL|77K@zkN?U zo^`jnLw9kbO&JgWLW%F>$$Osl7+$S?;{z4AOut=uk*=GL_~pohJ%m>)Wx?!I28Rb% ze0|xmxILC;U$npCt#76x(HF>FuST&Il!p=9F-cQIb#W_3UJHW3>*4-EtC0X!KW zp!&4d&_mYiG>@PZn?#Tzkq893_JIXZx`5A|HmtplZ#8;SbwHxT04Mip`3sqs8`qkU#9kA^4bd9U(LsfXIANfx-Z9Nu_<=8I@4 zKGb&+5w@7R4?d2>LUu%$LcIwe@bh@bqsA+Q8B+6RPuhD-hA7pKdI!k}qo#7%Omi;> zeh7<`(x_bKpg5D62i=85DXXa&9eRfFRb~y8Sp(#M<|+?*ielJn+TSZ+tTc-xF>Qtv?v2|)~8^EPwzpsMTR;|L9nR(vlJm)#*{Lb^7KYr); zzVA;_oVyYL0R4Mxgo6Ut|NLzk0P}VNAmtV<;pri0c6M_spc*j^$e@6IS_-TSfb|Rz z2JpvJQWYDnjsd!O>_`ojWZ*!-U_%_K_EipSTng6#nNl1tCz<8|!CKf{3fV}rm<4d- zS~s=MVpiOyw-I2Ls|0Zwt(e}78#T>=K#&y-Z;YS{B9YcsLU|T^zqtsm2i*4o0lqAQ zjF`0rT!tFCzlA`mI2-^~M(e+bFukD)N0_q;V?mN zT&p&t_1a=cC0h*T0y8jh2NOY-8_b6{kap5qv5KZ$aPw+-qXt&|87`L6bAT)iD4EJR zpkiZjNNy-lxGBwBNSD(gKWecuC37yNSqO?3kY=FGts1ZoYR5OFK-FN8Ul6mb;p%;M0WMxVaV;RVG!eu-V!+@7Y7cPw|VsKs-7e)1OEQGn5$i}T!8{U+PMuOJ| z7R{qra6*Th_SiJlcqEX3$N+u5fv}B54RIF7m7D-~;xW~^MWqfwJoa@Nm81?Ll`r9E zWQXzrl*uMle8?9;67v}`33T$JO9+nK zPFei9dih{frCjCvPAe$z%In~3bQKfUywSW+VphysjZ|t%U7=8y1M$!P+`4mC>MG zxPAoaUe=ATFQV|&%LPfZe7;~^WnNDC?DE8AV#&JP!kicUyj-0W;?%b@SLPvY-Ec-8 z$Uu_dZ(%Jnd;2bOdvFD+PDj$oUFn8dYnfSB+lU(>2LK4NrfQqrb>EsCcN}kY+s(njEND@;{wxJ@8$o zWy*bm39r8*dI{RkED2<^a8`J3xTqXWt8*p+PAF2#1OlEnY>+gtdh7W!JcOrKBVvI} z7*F<`^+09FiwknARURyq%J}M8Azvnt^3`ci#4@2IgHA?$tXhkvc#b9u#uMnl0S=Z5~kdx^4yPaP%`l1D4oTu(EQc6^qpCruxh($n_ zX79yFWW56;r)}>45(Ltg4YW{y3Jc(!;O2q?T=0^Sw@K9Rm44a`Nn3FOzKf8j5R{L~jG+4Bc?geey<+-b$0~o%?E81T=jGj7>(W>(flU5~ zTSZz-**nEWxIl2sP3O)@Lb*sOkf;JDI~OCU3hMQzs}?9vkXm*ko5iG9Ritv8Un02% zNrbe$Ug4S9v>Pcuh~_JCTO-?G(wiGU8n`o@!9TraLo4RXrzW1oNWz-8nEwO(=c$Iy zcjW~-iC)2=eMaxn<{Up2m`yxJ@g~+_ze&v zVv=K7ej4IK;DJ}1`V(|whoUWSFmwrYuEQGusRlA-BeYLOZe)VpeT^E#V5>4SprznD ziysMz<0(@!ypn}egV!y4stncW{NeC@g|K$!tL${N94pEzxn5C@RzYj(HvqJxav929 zJ}kRE5GSKJF{cM^x&`vDkh@Qs7iTohM_Cmr73E+tuzf4s8};;E;MmUtwd z8q;m|vFlegW^-*w=e5yR!Zt*@{b*TMj}a@pDE_>tWpD9G=aDi7kYO_|UF$3w!ip2g zxYcf4XOW8_ekURB(k3~-o|a>}H0L;;_O-^=!O4MUU5v) zlv}%TJ*W50I8J>Y&y4MlpUX^ylsy)P7Mgq9ormNhTbQT#I|5R&cTj}+EN#kPhSOk6 z9VI0zIHf;q?sckAlu1p`L^5e7!{S7J&Q})wb++gRD;(-@bc<lM*N6idm6pj}Ez zY(ScX5|hqiy$%2D{wdTYeK+SZ>QY?Yp!!izHnTm=ZmKnz8%<<~&^u)DNi8(V&JqU`%e1s!(vhmX>qj2p4?uJQVc_6dG_COIBk z{^$FY$_Ubmu5D|s*1Z2@Wv9BrAo0c=o%c5c-n%|8$@v~Q*M-Z?5IyoR6U1_!xSA6WR!wrF6^pQ?uf=AwY zhT6=tXeF*KU!H_sQ5kWK72o8vz0vqYyxnRu*Uj*O(x+xnjcpbcBue@GMA57yEm4>v zl_rH1Or1f6*9}}e>PY`xi{H(upQjM2MQX5#Cq?T0I%^%YxS>OJ+hO%n8s!{fZuY7p;PVLXE~HDaYDuI ziD`pNUPgbBqxYGyqeoTBj5ak-RrQe|MLs@Zf?p9Ir|3Spe4=_SpJvwUFMYmCeSxxR zXpOtHxUOO>n@38Ill zt)J>`II&4%`%}G7Zs-DNPkhG2#)5U`I>>U~@`!VNq=xgYd(!>;?d{dcixK@}!)rO` zu5ob|FQ4U z_Zs6(w7T0t^HoNTx5;MW#}h*g1dlgC(t%in3y?IRB7*lNybMQJ+}+TG(}}Ub1IznYf-s+wLIB zqi8o*TEC69-Hf(>79FWO%~-7zHXlAm52Wz-t&gi1WlCYpU|?l|u;TI<+BBV~z7T!* zoyG9Ug>7*NU%F!o8xYtL8(yV5Ab1OeH1r&yFNaRUwIS(ImVZqbg&zIGT49w79?;Q7 zgO?sPrAU6Bdkr=&B2Gs!{Xd!3HB9S$zV&oh!HnB&ZT9)lx^-Ev*K5s9Rk#Zcc8nP{ z-<%7g7u*{ai}QWtrkxH?nGC@y9EyUjwnWY7c%r6zZeusw(ar7-3)l9-e>aUqOYZouziTE9c|j#Q)W~(D;!qUMk+}W zM6&0wNXqSMBbHmWRhOr&P)Cnn46zxS6>MdyBt5lC5bcQu!C$mB43uQtHC8ZDa2Q|| zh%_AWK^ys-={n7b;ox}oSJ}7X_e{&=gknhaTW(?JYNeP|ey_YU zkYdD&El!&uKv%nE$cRVJInU`&z3N}hpf+@s#CPv2{nSZjCGAPbRHpU0R26$~gw*Tq z9aIE-)$Z$p2t6;Y`wazWtL#Rjg=Dt88QbGle-8f$fB&a5#Mp0nF0XgWN1Fkjj_;qD z2TOYr3hAGRS_jh?gILbSvq^*5FGEiZ4wT)Ci=5mtaB4W=2djOPPUi(Y)LG#eR zzU5UBc%3D4dY;XUN-V~U9ySzy_K0SYZh6VrW;#zs)qUxnUagdxPG6r^=Ta|Sjj{TV z%Aw25=i@&=8?5rvRw4fZO_9tf-hgaCwhimLwnE{@DYO42;-n-g2tPf|Ur?zryjCPJ z-3dd2aQ3uj0j56XG108PL}#oGmrbt;Y==N1a&)k0x;F6jZI8FQff zz`w#920S7}M2loDh`%`y9!Z#bPJ3(R&#o16nSJH0%!+RqE^K+nuf)AUbtBEzuud`^ zJn_M!7wVnkGylA+^=W}5oAr+>baw}unu>CNR1{+}Zr&N(mJt{CR-VRWxVR#smp`n! zk=HR~)MLgYd;6y-wPZ)-!1&QY@h}}MzTw&Lr9&mZ-W-pfj-P5UywQC(kR}tR$z)cc zkhOjelqpR4Ti^egsE0B0L%qS*`BbBT${-0e#XbBW%DGs1u)io0l1LILselIuQ^~3w zJ!@SUOjhv#GnksT62d9sD)@rS28T-R0g?{dhQrh#QV-dohl8M{a5&{4oJzS&5$8%N z2T7uQ-!hm~;~zeU8D5iX$$Sn!m=1;N5Wr_BB^AiBrSuoR^S-+HDM8I);dPV z{|&Dqr>mGWrU7bUW^B)(mdtwxlBN3|)54VORj7Ri%qy zR`Z=Tx*o8|W>E3;)PDO9 zPw#a;L95IJ-4&xxr^WD7Xwa$7ZKPiKBz(h2dd~tuM8<^rj#>cT; - - - - Retrieving Files - - - - - - - -
- - - - - - -
- Retrieving Files -
-
-
-
- - - -
- - - Your HackTV Box is downloading updates from zefie's server. -

This may take a while. - -

- -

- - - -
- - diff --git a/hacktv_updsrv/ServiceVault/wtv-1800/LC2.tok b/hacktv_updsrv/ServiceVault/wtv-1800/LC2.tok deleted file mode 100644 index be9e10b6..00000000 --- a/hacktv_updsrv/ServiceVault/wtv-1800/LC2.tok +++ /dev/null @@ -1,32 +0,0 @@ -ANDY........z. -.`.6[......8(&.S.....}...lIa.;...b..c..d....e...f..g%.c*I.h..i!...j).k.B.lH.m.=C5*@.n -.1].oQ.t..Ip.().{..Isetdtr..(C.);.Idoelay..1>..z..1....rC...}M.q.(..r..R.lIs|...w(...P)e..P;..r..0.t0.u.,~..v.,lIw;..1.v.){.i(.!..D).b;..'.P='.D.o.i(.-.>....j....IUx..y[.za.A..N8.B.=..C.C -.UzN.D..A..y~..:...NC2<..y3.N....}.a....e{2.g.$. -...=.v.[.A{.D..d -(."M.A(.....r..a....f.u...ep.G...PQ...R.."E..F|.UG..H..F..F.....F.E%.r0.-.&.+ F..r-U.I.I.(lIJ..K.......j J|.J.w/C2 -.K.D..R,.%..H#LH"M.!.NM".!progr?esstex7 ....$..percen.tage..6...dGirt.".!')O...*IP.$Q.1*I.R..S -.TF0;?.0..<..U.04..#.."version>P0GC9.|.0. .#....!g..hon}es0tings..|@1n!T.EC8i.r.!...y.1?<.. -.0U..2..v1..3.)1..4.34.44..0.printf.(.STS: cou.ldn't .. .size of CROa..5....+i.z.3( -.9.)< -.R.!R .>@S).4.A.C1S..464?4W>45W5R..6=..F..A."..:f0^.8.. 15..w.9..8.I.;I.x...FON.E@%x, le?n=%d, ....+.,t.+w.,.!.... /Q.AP. ...@.....a.rF..Q>.Z!.. -P.-G.%+..$..e..2'.SV."W@P*I.X..Y... Z..a.a.CIba.[C.40.].aIfl.ush..send.s.QSATI3 -|.R!*SENT ....b..linf1Q.,WC3?..1.Q;.R.....8@.b}+fw .query go.t '%s'.,...i }efirmw.areb6. ..15..]mb..vb.`..c.m.`M.,SV1..001_WEBT.V-K56_DLB.0EDc8.!q..YE....;E.;.....b.?.....U S:.:..:i.sRockwel.l."..."..\....p|....+MR=0............CX. t.est retu.rned......O..`m....e...#S2.20.../..........._ x....+k1....0&.X#..s3&P..t6............Xt..... -Z....&.;2 -.c%a..d....e.C.......g. .O.A....2.p@....Ii...A;61.AcIj...0.#.k#.7#.l5.8.5.mv.^.G.9G.*.InQ0S1.aT.oZ..pb.Iq..r ..s..t..u..=.e.nablemod.em..tflow.controlN../S].baud^.>..pOeIv ...D2GV1E.0.3..3..T...P@..@..@.. -@...@.........d.[[ound v..@ .@jP, di9s..x. 56..]....p.....`.4....F..|!X....!a...+.+MS=11,.....[...,.,SS.51=3*.....R...@ss@.38=0S.30=180S9.5=36;.L3&.Q5&K.c. u ..qVP.5.I &(I...nec..with.videoa..)QN... B.M..e...... 5.S6=101X.r:...4XNr....0GC7o.. x.. ......#1.!....2"..6. .p1.8?.I..d.I.9}.....K.|....,.(./4.cw-.hack@...F.C.., .. S10=S%sS...,.A,.1.,.1,~1e.:.9....+....0$..0=S3...#...2.."./.1.....m......a.."A ...b..,.s.n..Z ......@..m9..1=@..P.'...(.(.1...( -. (.Q.6P...'. P.. .P.C..|..}5.&P.C..-.h.-.b..3..9.2.4.Cetw.indow....;0.~j.Iw.cx,pl.Iy~o~o~o~e..v..@Jc6dA.....bB..g2.cC.g3ndD.I..b8<....V.M..L.H..Y....-J...R.O...&!..g-Us..QLD pref.ix.+W.....S,..%..........5.5..KG9.9.9...!q..r.A.E..F......P.<=.....<...wa.itfo..H..p...),C7;.6....p.fig ....L.b..?: TIMEO.UT f.\qj. OWK (V.=..)=..I...x..G....C..... from .l.,..Y.d..S...T7.B.G..H..I -....statu..C.6F.J..C.B.....:...8.p..._.,S.lp*.*.%.orce.hook.....rt....K>.lIL.5.M|.N...R..=I.|._parser/esul_p@4.0.r5.b....@Ic9..e>.C..#T.NC4?255464...].V. -- %d /%s (..c...p...k....,..j#b{.&x...r..Up...oa -.....%`..: ...7.$..q%..q&.N.O CARRIE.R-.<-...- DI.ALTONE\.5x\.....BUSY...7..{@. ANSW.......G......L.C....C..ed!...e..*.&.*..-.C.p.b....E.E.~..0..2?..3G.b2..9.pm.2>.2.....34<.:<.<...)4...pd..4.......5.55.4....1c...|...i ->.p;#>.N..79>....?'..4s...83. .*5.M.....58....C.&.96.%:.........8.B. .A.jP.1R..9unknown..3..9|.<.<..?.>..6..O..PJ.J.J."J.QJ..@..R..J.uS..:..lIT..qU..0.<.*IV...W..X..\.h.....?,SISP-.R...1.+..,..C1?.u0...b .....e.*......ork..nu.mbeyq......=.IYKaA.....=I9E....,C2#......G....3..a..=.....+0C....>..d.!.&G.&...t....|b.....Z..s....P|...........A.TDP... -9...= v.R.......,:"....x.....Pb....k@P..D.....&.!<4.!b@...B r.c .W. r.r..., .ti.r...x..9B.,>.I.a.ler..SErr...!.: Your. recei.. .can.... to. WebTV. .Please{.t.a..Custom.0.Care at. 1-800-4.69-3288..J.. 3.i(e"...p.......6........ ........&.}.$g..c..#E. .3=..#;....%3L....0]...f.ancy....l..6.:.....S;G...6..Id - .A.O.IIir.G1.CuHlIew....Iw....... z..y......46.MC -...%w.0eL.N.<..D..w..lin...B.A&.@06..H.b.1...E.....U.. @.W...P....`..1eh.8kd...=..Iatoi..Dr...(.B.~)3A...i.@R..Bdela..PC;.S,Pf.12@..n..r.2c...g]0.odd...S..{.\.QNmU........Q..r.q......T.....E.IgoA=.5S.h -...s.dter{at.q, dc...prot..com.p.p.!..h!.......g/'.d.i.@!.l.j.8...9..r,l*I.kb.r..=X.V.T...Q!.P.....XQ.p,.X......al. g.../%sa.x.v...v....7dx..26...@.i.aP.failur.e,.$2...;.....| .s.....,`.....O.....l:.m,.nt....u7.nam.1.....pass#.d@vP*.........o.a.5.2.2..rtpp.4.T.u..Ap.P..)...=.AP/CHA?P auth..0..:0.0.PP ne.?0ia.AI.e_"r.C;0.........O..s.c..)<.....F.WARNING.@{S &. low.3..q6..R5q....rT"..Ys.#t.#u.#.c..[C3y.....0.`)U..8.Iii.>..NT%...,S.#..'....).08..I.1u.tefc.1^..v...V...k.:"p..M...sUs@1.. wi..".A/.D..l$r.". ..cv.dlIJ..J...system_>.`boxfe. ...la.. -.J..55G464b..2..IU.AJ..-a..-a..w........b...n."D.s.uppor.%.6.....u.h.......R..Ag........k.x..RlPyA.sPz..A -.uB..C.SlIDf.cEbUS#...tiyA.C76:7f1#.#....yea..gA:....dl`/.local...I.g.nCk.NC7.;2(.{../.z./._ 7_..../.. 6..c./.. 5 ..........Z.. ..7.........lIS:..L^.Premp<..to 6pl.......a$cVO.}.,=.c...[C8n...SD...%s .@........f.bf.f.f.f.A/.Nj.j...c.......WebTV...8....0.Wai.A...+.1...a.IS..n.swee.].=.\....-...M.....V -O.(..(...yI. ....v..4.4....*....rn...k@..L(..T..U...IV..r..Sw.tv_6......S.....base.ts.f .. 77 (.ANI=(E.et;))^Eani.X..0.P.E..ldIl.....k..W....5...'......O...#.*.vi.c..9=39==s33.` -.<32...n..Io.di.=SS ....[.`]...>a[.0...@j...)..6..8,.4G.66.V.o@J 7Y.../P,..Y.5w....... -....4..g.....:.*.V.P*...G...5.qh .J..h..4....=..d....;..$.69;....;.>J...Y...J. 1a.v.:A....._...q:.Q.6;..o.5.Y.Q...h.......?.a...<......Z.." h. "+..U..{.....l..,s?..r;..1C.47..7.... .\.. .zb~!..P.8.i..P.X)....Y......,*IZ@.*Ia9c. ..lIy.q...(.=S18006.13819..6.=;Sa .mis..6..@...:.:.:.H.8.w..BUGd.....a1.....`.....i.........,..B...c.\.b...c..d..$.fcJ..g0.h..=.@,.U@-.@..@/.@0...BW.A.*C64..+P.I1..`...o.U....u.... for~..%d:%02...........l..p..r.;.S.S1. |.D.@S.D...e...e.\.\.\..\.L.A.......>.".^...S-a*.-...,..(...\.....;. + + +Updating + + + + + + + + + +
+ + + + + +
+Updating now... +
+
+
+
+
+ + + + + + + + + + + +
+
+ + + +Your Internet Receiver is being
updated automagically. +

+This will take forever, and then
your WebTV will reboot.

+
+

+ + + + + +
    Receiving part `+flashrom_part+` of `+totalprts+`v`+flashrom_version+` (`+flashrom_type+`)    
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + +` \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-flashrom/lc2-download-failed.html b/hacktv_updsrv/ServiceVault/wtv-flashrom/lc2-download-failed.html new file mode 100644 index 00000000..19abc99a --- /dev/null +++ b/hacktv_updsrv/ServiceVault/wtv-flashrom/lc2-download-failed.html @@ -0,0 +1,50 @@ + + + +Updating failed + + + + + + + + + +
+ + + + + + + + +
+Updated failed +
+
+
+
+ +
+ + + + + + + + + + + +
+
+ + + +Update failed, gomennasai. + + \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-flashrom/lc2-download-failed.js b/hacktv_updsrv/ServiceVault/wtv-flashrom/lc2-download-failed.js new file mode 100644 index 00000000..de953f1f --- /dev/null +++ b/hacktv_updsrv/ServiceVault/wtv-flashrom/lc2-download-failed.js @@ -0,0 +1,53 @@ +headers = `200 OK +Content-type: text/html` + +data =` + + +Updating failed + + + + + + + + + +
+ + + + + + + + +
+Updated failed +
+
+
+
+ +
+ + + + + + + + + + + + +
+ + + +Update failed, gomennasai. + +` \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-flashrom/willie.js b/hacktv_updsrv/ServiceVault/wtv-flashrom/willie.js new file mode 100644 index 00000000..2e5eef92 --- /dev/null +++ b/hacktv_updsrv/ServiceVault/wtv-flashrom/willie.js @@ -0,0 +1,20 @@ +// willie is just a graphical frontend to a list of ROMs +// the rest of the scripts should work if you manually link to a ROM, and actually have it. + + +const options = new URL('http://wtv.zefie.com/willie.php?flash='+getSessionData(socket_session_data[socket.id].ssid, 'wtv-client-rom-type')) +var data_ready = false; +data = ''; +const req = http.request(options, res => { + console.log(`statusCode: ${res.statusCode}`) + + res.on('data', d => { + data += d; + }) + + res.on('end', function () { + data_ready = true; + }); +}); + +headers = "200 OK\nContent-type: text/html"; \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-head-waiter/finalize-security.js b/hacktv_updsrv/ServiceVault/wtv-head-waiter/finalize-security.js new file mode 100644 index 00000000..ec678b8c --- /dev/null +++ b/hacktv_updsrv/ServiceVault/wtv-head-waiter/finalize-security.js @@ -0,0 +1,24 @@ +var challenge_response, challenge_header = ''; +var gourl; + +if (socket_session_data[socket.id].ssid !== null) { + if (request_headers['wtv-ticket']) { + if (request_headers['wtv-ticket'].length > 8) { + DecodeTicket(request_headers['wtv-ticket']); + sec_session[socket_session_data[socket.id].ssid].ticket_b64 = request_headers['wtv-ticket']; + //socket_session_data[socket.id].secure == true; + } + } else if (sec_session[socket_session_data[socket.id].ssid].ticket_b64 == null) { + // TODO: client should have a ticket and send it back by now, if not we should handle this correctly + } +} + +headers = `200 OK +Connection: Keep-Alive +wtv-encrypted: true +wtv-ticket: `+sec_session[socket_session_data[socket.id].ssid].ticket_b64+` +wtv-expire-all: htv- +wtv-home-url: wtv-home:/home? +wtv-visit: wtv-home:/splash? +Content-Type: text/html +`; \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-head-waiter/login-stage-two.js b/hacktv_updsrv/ServiceVault/wtv-head-waiter/login-stage-two.js index e9f51832..5174ebae 100644 --- a/hacktv_updsrv/ServiceVault/wtv-head-waiter/login-stage-two.js +++ b/hacktv_updsrv/ServiceVault/wtv-head-waiter/login-stage-two.js @@ -1,17 +1,95 @@ -var ssid = initial_headers['wtv-client-serial-number'] || null; -var initialChallenge, challenge_response, challenge_header = ''; +var challenge_response, challenge_header = ''; +var gourl; -if (ssid !== null) { - if (sec_session[ssid].ticket) { - challenge_header = "wtv-ticket: "+sec_session[ssid].ticket; +if (socket_session_data[socket.id].ssid !== null) { + if (sec_session[socket_session_data[socket.id].ssid].ticket_b64 == null) { + if (request_headers['wtv-ticket']) { + if (request_headers['wtv-ticket'].length > 8) { + sec_session[socket_session_data[socket.id].ssid].DecodeTicket(request_headers['wtv-ticket']); + sec_session[socket_session_data[socket.id].ssid].ticket_b64 = request_headers['wtv-ticket']; + //socket_session_data[socket.id].secure = true; + } + } else { + challenge_response = sec_session[socket_session_data[socket.id].ssid].challenge_response; + 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)) { + if (challenge_response.toString(CryptoJS.enc.Base64) == client_challenge_response) { + console.log(" * wtv-challenge-response success for "+socket_session_data[socket.id].ssid); + sec_session[socket_session_data[socket.id].ssid].PrepareTicket(); + //socket_session_data[socket.id].secure = true; + } else { + console.log(" * wtv-challenge-response FAILED for " + socket_session_data[socket.id].ssid); + if (zdebug) console.log("Response Expected:", challenge_response.toString(CryptoJS.enc.Base64)); + if (zdebug) console.log("Response Received:", client_challenge_response) + gourl = "wtv-head-waiter:/login?reissue_challenge=true"; + } + } else { + gourl = "wtv-head-waiter:/login?no_response=true"; + } + } } } - - +if (gourl) { + headers = `200 OK +Connection: Keep-Alive +wtv-open-isp-disabled: false +wtv-visit: `+ gourl + ` +Content-type: text/html`; + data = ''; +} +else { + var namerand = Math.floor(Math.random() * 100000); + var nickname = 'HackTVUsr_' + namerand; + var userid = '1'+ Math.floor(Math.random() * 1000000000000000000); + var offline_user_list = CryptoJS.enc.Latin1.parse("\n\t\n").toString(CryptoJS.enc.Base64); -headers = `200 OK -wtv-ticket: `+sec_session[ssid].ticket+` + headers = `200 OK +Connection: Keep-Alive +wtv-encrypted: true +wtv-client-time-zone: GMT -0000 +wtv-client-date: `+ strftime("%a, %d %b %Y %H:%M:%S", new Date(new Date().toUTCString())) + ` GMT +wtv-country: US +wtv-language-header: en-US,en +wtv-visit: client:closeallpanels +wtv-expire-all: client:closeallpanels +wtv-offline-user-list: `+offline_user_list+` +wtv-bypass-proxy: true +wtv-ticket: `+ sec_session[socket_session_data[socket.id].ssid].ticket_b64 + ` +wtv-messagewatch-checktimeoffset: off +wtv-input-timeout: 14400 +wtv-connection-timeout: 90 +wtv-fader-timeout: 900 +wtv-ssl-log-url: wtv-log:/log +wtv-smartcard-inserted-message: Contacting service +user-id: `+userid+` +wtv-transition-override: off +wtv-allow-dsc: true +wtv-messenger-enable: 0 +wtv-noback-all: wtv- +wtv-service: reset +`+ getServiceString('all') + ` +wtv-boot-url: wtv-1800:/preregister?relogin=true +wtv-user-name: `+ nickname + ` +wtv-human-name: `+ nickname + ` +wtv-irc-nick: `+ nickname + ` +wtv-home-url: wtv-home:/home? +wtv-domain: wtv.zefie.com +wtv-inactive-timeout: 0 +wtv-connection-timeout: 90 +wtv-show-time-enabled: true +wtv-fader-timeout: 900 +wtv-tourist-enabled: true +wtv-connection-timeout: 180 +wtv-ssl-timeout: 240 +wtv-login-timeout: 7200 +wtv-open-isp-disabled: false +wtv-log-url: wtv-log:/log +wtv-demo-mode: 0 +wtv-wink-deferrer-retries: 3 +wtv-offline-mail-enable: false +wtv-name-server: 8.8.8.8 +wtv-visit: wtv-home:/splash? Content-Type: text/html`; - -data = sec_session[ssid].EncryptKey1('hehe! stage two! and its encrypted!'); \ No newline at end of file +} \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-head-waiter/login.js b/hacktv_updsrv/ServiceVault/wtv-head-waiter/login.js index bdee70b9..8c8ead24 100644 --- a/hacktv_updsrv/ServiceVault/wtv-head-waiter/login.js +++ b/hacktv_updsrv/ServiceVault/wtv-head-waiter/login.js @@ -1,57 +1,56 @@ -var ssid = initial_headers['wtv-client-serial-number'] || null; -var initialChallenge, challenge_response, challenge_header = ''; -var gourl = "wtv-head-waiter:/login?reissue_challenge=true"; +var challenge_response, challenge_header = ''; -if (query['reissue_challenge']) { - gourl = "client:activ"; -} -if (ssid !== null) { - if (sec_session[ssid].ticket_b64 == null) { - if (initial_headers['wtv-ticket']) { - DecodeTicket(initial_headers['wtv-ticket']); - sec_session[ssid].ticket_b64 = initial_headers['wtv-ticket']; - challenge_header = "wtv-ticket: "+initial_headers['wtv-ticket']; - } else { - challenge_response = sec_session[ssid].challenge_response; - var client_challenge_response = initial_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 "+ssid); - sec_session[ssid].PrepareTicket(); - challenge_header = "wtv-ticket: "+sec_session[ssid].ticket_b64; - var gourl = "wtv-head-waiter:/login-stage-two?"; - } else { - challenge_header = "wtv-whatever: meh"; - gourl = "wtv-1800:/preregister?"; - } - } else { - if (sec_session[ssid].challenge_b64 == null) { - challenge_header = "wtv-whatever: meh"; - gourl = "wtv-1800:/preregister?"; - } else { - challenge_header = "wtv-challenge: "+sec_session[ssid].challenge_b64; - } +if (socket_session_data[socket.id].ssid !== null) { + if (request_headers['wtv-ticket']) { + if (sec_session[socket_session_data[socket.id].ssid].ticket_b64 == null) { + if (request_headers['wtv-ticket'].length > 8) { + sec_session[socket_session_data[socket.id].ssid].DecodeTicket(request_headers['wtv-ticket']); + sec_session[socket_session_data[socket.id].ssid].ticket_b64 = request_headers['wtv-ticket']; } } } else { - challenge_header = "wtv-ticket: "+sec_session[ssid].ticket_b64; + challenge_response = sec_session[socket_session_data[socket.id].ssid].challenge_response; + 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_session_data[socket.id].ssid); + sec_session[socket_session_data[socket.id].ssid].PrepareTicket(); + } else { + challenge_header = "wtv-challenge: "+issueWTVChallenge(socket); + } + } else { + challenge_header = "wtv-challenge: "+issueWTVChallenge(socket); + } } } - +/* +if (request_headers) { + var cookiedata = {}; + Object.keys(request_headers).forEach(function (k) { + switch (k) { + case "wtv-capability-flags": + case "wtv-system-version": + case "wtv-client-rom-type": + case "wtv-client-bootrom-version": + case "wtv-system-chipversion": + case "wtv-system-sysconfig": + case "wtv-system-cpuspeed": + cookiedata[k] = request_headers[k]; + break; + } + }); +} +*/ headers = `200 OK Connection: Keep-Alive Expires: Wed, 09 Oct 1991 22:00:00 GMT wtv-expire-all: wtv-head-waiter: -wtv-service: name=wtv-log host=` + pubip + ` port=1615 connections=1 +`+getServiceString('wtv-log')+` wtv-log-url: wtv-log:/log `+challenge_header+` wtv-relogin-url: wtv-1800:/preregister?relogin=true wtv-reconnect-url: wtv-1800:/preregister?reconnect=true -wtv-visit: `+gourl+` -Content-length: 0 +wtv-visit: wtv-head-waiter:/login-stage-two? Content-type: text/html`; - data = ''; - - diff --git a/hacktv_updsrv/ServiceVault/wtv-head-waiter/test.js b/hacktv_updsrv/ServiceVault/wtv-head-waiter/test.js deleted file mode 100644 index 93abf3d0..00000000 --- a/hacktv_updsrv/ServiceVault/wtv-head-waiter/test.js +++ /dev/null @@ -1,2 +0,0 @@ -var wtvtest = new WTVNetworkSecurity(); -wtvtest.Test(); \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-home/home.js b/hacktv_updsrv/ServiceVault/wtv-home/home.js new file mode 100644 index 00000000..dfc5acae --- /dev/null +++ b/hacktv_updsrv/ServiceVault/wtv-home/home.js @@ -0,0 +1,46 @@ +headers =`200 OK +Connection: Keep-Alive +wtv-expire-all: wtv-home:/splash +Content-type: text/html` + +if (getSessionData(socket_session_data[socket.id].ssid, 'box-does-psuedo-encryption')) { + var cryptstatus = "Psuedo-encrypted"; +} else { + var cryptstatus = ((socket_session_data[socket.id].secure === true) ? "Encrypted" : "Not Encrypted") +} + + +data =` + +Home for minsrv + + + + +

Welcome to `+ z_title + `

+

Encryption Status: `+cryptstatus+`

` +if (socket_session_data[socket.id].secure) { + data += 'Encryption Key (Server): ' + sec_session[socket.id].session_key2.toString(CryptoJS.enc.Hex)+'
'; + data += 'Encryption Key (Client): ' + sec_session[socket.id].session_key1.toString(CryptoJS.enc.Hex)+'


'; +} +data += `

Working stuff

+client:relog (direct)
+Clear Cache
+ +

zefie's server only

+Music Collection
+ +

Test Stuff (probably broken)

+HackTV Updater Test
+Ultra Willies
+Disconnect and go to HackTV Home
+ + + +` \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-home/splash.txt b/hacktv_updsrv/ServiceVault/wtv-home/splash.txt new file mode 100644 index 00000000..123e8313 --- /dev/null +++ b/hacktv_updsrv/ServiceVault/wtv-home/splash.txt @@ -0,0 +1,25 @@ +200 OK +Connection: Keep-Alive +wtv-expire-all: htv- +Content-type: text/html + + +Engaging zefie... + + + + + + + +
+ +
+ +
+
+ + diff --git a/hacktv_updsrv/ServiceVault/wtv-log/log.js b/hacktv_updsrv/ServiceVault/wtv-log/log.js index ef504672..ec6b8c30 100644 --- a/hacktv_updsrv/ServiceVault/wtv-log/log.js +++ b/hacktv_updsrv/ServiceVault/wtv-log/log.js @@ -1,10 +1,17 @@ -console.log(initial_headers); +// write posted log data to disk. should be decrypted by this point (if it was encrypted) if the crypto stream didn't break + +if (request_headers['post_data']) { + var fullpath = __dirname + "/ServiceLogPost/" + Math.floor(new Date().getTime() / 1000) + "_" + query['type']; + if (socket_session_data[socket.id].ssid) fullpath += "_" + socket_session_data[socket.id].ssid; + + fullpath = fullpath.replace(/\\/g, "/"); + fs.writeFileSync(fullpath, request_headers['post_data'].toString(CryptoJS.enc.Hex), "Hex"); + console.log("Wrote POST log data from", socket_session_data[socket.id].ssid, "to", fullpath, "on", socket.id); +} headers = `200 OK Connection: Keep-Alive -Expires: `+strftime("%a, %d %b %Y %H:%M:%S", new Date((new Date().toUTCString()) + 10))+` GMT -Content-length: 0 -Content-type: text/html`; +Content-length: 0`; data = ''; diff --git a/hacktv_updsrv/ServiceVault/wtv-star/images/HackTVLogo.gif b/hacktv_updsrv/ServiceVault/wtv-star/images/HackTVLogo.gif new file mode 100644 index 0000000000000000000000000000000000000000..7df200353d74824c577df2a10f948bad8c60df38 GIT binary patch literal 16880 zcmb@tWmH_j(k?tR%)sF8?hb=H4DRk4+}#6&3_iFA2=4AK!5u>IKyX5U;0Yv1gfHj3 z-+O=D-*>OQdUtm{^;EAdt9MsdDXS`pirI_;UjgF)|2cpF016NQ0s&D_fDi}}4Hbxv z4#L0yVPk@DaKQL@U_t^2F%g861eJ^wm7E-viVBT}8jYSFo#EfffX>W>&cckr%7Veh ziowZ&$;FAu&4tCwgC)R^EhLB|B8)30iYpOe8~G3}bv8Vc(OdSC0`}5E_VN;r%2Lj%GR~R`uDU9&`WmjrTJEMg z?&b#WmIj`-W}ePg-tG=qPbciZH|+mq@%;Q30AN%BD80R`0f5*50MLKgmHwwBGa&d+ zKL7v)D3R&UzrDQrKep4Oq5qy60PsIZ;83JHncgA*04KANg!ugU2O~2wAv4?t*1X89 z0sPbbhs>;g0M;D+hYSE{pqK~NeEeUw|1tW%t^Wf4;V}Tve|R#Zuzvz^fSn=0!U5pt z2k_MdSoi~MGy(pe02>8>g&)AdAK>N<@CpK01OohF02mKI#0B64060GXR%@S;1b|z} z3=GH&EdFa6hs?aex%b~tG5(Le|GV<Hl*4yZ)E_`4IvDY=j*R(?5d$^*sZ) z{)70>Hvxb?1AtH}m6no`C@3L^#dJ&QSR5XsT7gPy*+e3lfa~^jYxz_voqPh7YFouj zCYyep#Y|h}Tn@}`wm`ML>V3Yb-`Vy|d-aE6coYV;T1U-Nxk@I7#+oC^{$4^c4ur7Hac$)^De;lWDKWB<4%9@m$S;bd+yyK1PUgN zMo-JZ7?P0FYQCrS^Hdt6dXYwN+n2dq0k_@x-u9CZCGv?hmcfl*S87!2agzHwzpk|~ z7Aqm(5s{D{QbFgNlJ4uhe!r70k9^_FmDbGaLd#!)S35)HGEkl{pbumcpU!w;=iKa5 zSE+YQ}?YlE6YxQIv?*M|kwaw}(%u7HO=Jg3A(EDqKJqY!zvd7~YfYCj}fWGgWU{YHAMSHRbZGL-fTTO1ygcN{W3@ znOxyHNosdrKsHJ+$2{5sF;J0vpXy1K&!>1$QAo|U(7dW)5GFTx3xqXJA~DuF%@XR~Ix%G`I4l;XT$drjO5+>>DPwdvho4DR-E4!3KpyU~5FjuEx3+QPLfa!{hS zYyC(q0yU)A>o6sey6m{Dp30*?-bJ>Fw!{TgFd}Y#jU~FDHa0DGVf`IPx}xFxEPHVn z|BP5Pm2cbp)tpz$%5JS=&Bw_7+eB*cj%*fssJc})j_4w+7mt<0$B{_Hns1WAZ#!}d zMn%a#&(nU7()Fv2@43aoQ!$t?ku!~IjegVFpnye#qa)zuyXvT(3}RX2TnFwWuW`#Duv`sJ6x7lUFa zORsVIPG!<)etxaVZ{+>7*i|%o?h-2=y4}eb%<(EH>KwMx0-_BA_GrEziFYw;6vAPt zrV_hTT(ls_7>)+Lv6k@8|66HX>a(va-&MSvc|sakHUH%_UyUJncV2W;=L zG1jQ}0OXk+fnPhVIig1M9C*_+V|j%{^B*NF!i!mgiNKZ(zC&qa> zEhh)Wh%zWa$u5b8YJGraXCD5jt7)UY+0UvzDnd=4kj3#$Pdr>PB{TFNy?x|*buIgO z=li6@AU$2Uw_pO*SLZ4GeS9B!0aMzT8)XoxZ(59`Jrk{}CYOp{dR9RsGv6avlOip% zsKAO%mKBWoh9J8($@Jc2bJjQ#_Qslvo_i`-+M=k{{735&CT-etht+rN+!3N#7~_5s z{*Oh|DZOJ{j%qP2hMSCK3nr4T76@-J5Q_{FMK%tLO$qTYC&zYC8oGfbnq`%(CfN(~ zzMNr}#*5S$pn^mJqThmS98L#p&r;UZ$b)aP85#(OtwkcuGL}$!6v(cqj--VbZjyn? zGjPnOh^Rrj(lCotJc_#LI63;Vq>36v`99s$a04s`Vs=%{Gf0-SUS*a&JCVgFgGD}?KeEPy)d%bmY^X61A|JnAu$326jY&+<~wJ8 z8IqAwEjD`waxo*AzhHW*gi#XIwur1(SYf8m0?7SIH|^OmtC1+6UZ_=d#>0_6LKEsq zIGhJ&BD?P?CHivoGeO^AR3qB~vjJ=SQ8pO0q2?~h+}6)jaPrWj*e$FMc*eh(tU=sv zxWxGfi!$ak%cqhG5jt^vBkI$ow5EXJ-hiWsYPydQiP90Rq#N+9ntr~pNa3QU zk@jnhIkB0Hny!v&R1)>dS3g&5&{f*shE^O#w>&(z<;Aony@K0O$^)m&7r&7OCxK{- z!P62{ZNNmySibV^^{+oG1I>I7)&SX)@A7giXD|3Cd{~_I)54Oo%b~1#Dk<2KAUb z@=M(?Dxt_I0S)UZM*;tkmF`^Q(f2B4Q3LJQ4^H$}2P6F65xy@@D(79L zfZg}5KzGTSB-YrqaONoYeQ}2^Ap9SI?=N5779`r7;N~WLkO27GqyHIF5D6L0Zg6K2 z2>FWT`BYv^<3fMBcBnt({YKzYzahx<{PX7!^mpOvEs4}Su7VP?OE@`K17g$k-kI%k zN^be`5gjZJ`eyTlg2L4GRU_{zOd+rJ?B(?`5xtB< zCsXI>fj_e-cQ6HnD0K^u17959Nf`Wj#x!~1^>J*stW6p7Qo{Nd`Tih!-#y#)*4Zxw z(xT0=pc_DGGI&5w^l=W&B&*tkR>5S4MSDZ>)nOO+#~g{xYLV*6SG&sO*Cbvp1Y9#6 zC_>fXoM^XLN19Y!iQmK)@=o3pf&Lixp;+DS+hCuOFaCc%2B#{!NaMXEBjp$IM%hI{ zS^WZ{KK7tv6*+K}SXcJ#we$U$?pqm0M(hmCi-`#Bh@h_Vq7?9y{rOQ9Qaxo_BNq^y` z%vHz?ej5dk_qV5mQoQ@-$KcIX{k&@3Z|ttT9?Bl@dNe0^{NDQa$!lWeDDGQ+rpzd> z8gZxFuowQ8T?!IKPSO2$a-V_%!#3hH& z!N=g<79x5h+8eCmo{hB7lc4nvh2vR(og&8r{iAb|28Ci%gyG7tG-X7rKu@gHK0i!9 z*?Zc?r!C;)4;$VLlR(kHIz87Altgs8#E>|^sfjXeOUmbuDKa-H`go~E8_aj7pr6Q8 z!+%r!Mku@U>&?4Vo(-_pvqBn#J<2tgKe;@ulq~^!#s@d=C4QbIp;+{1)D%+o6#VHp z^9XsmG6t9wC+@^nn-Ilh#ul~ZcVVbSXu!xtcWeymN2Wl zhpRF-fCG>ooWbf}lcnyG{?o_NX)0ZfKAQ@j-RhYAGdA12Mc1s>)&f1rN;MKe`Uc9H zDS&S582`rp)Y+{!^8;BjTs2wlW%8bUR_;fa5c22%QQshx+;Y}j<<>wFXVArIijp$DKN5r~BaM z3a0W3<~Iu#&G)xe$L9 z+b@uCrD8hz$Z21(jNan0uf;R91@m7EoF2U&?;}+g^E}X#XV7xU#!Dn>JgR4eZ^52d zO9)a|O300bd}}GiVkw0vm{uG@FJ8uUhR+hh#a0)CU@dT;C<8o|E!5^=E0qhIfs6CX zOY;h`%>>?@LkdyS73NoD9a}D`bKc$@pr|;lcIH}_$&Dj5??v-r?I`} zQ!SX>ECW7cl!N>7MA2o%UDAkAvp&Tqo1E~9+Zp&!1d_JEdgv=9BT!V@3} zag<03!f1@7Sn(v}Y;l5FLDE^}hp*nrMzKQTh5RP9CBe0owaJU!wcckyUyM3Tx;jbv z{B!mUMgcLDid>S3hQ?V!PM1nWJd3&7GV{I~%f12_MpZ%Yn*x<6%!Dd`Q%gDGin?i< z&*;F?1c1~*!x<8^K+q@$Yt+T7ybEcBr#A|CSME>*$In(yZ`QovD0d;RwR4p^?JGY! zE4i3uxl$`7$7{YdYlbXRUimQa1tn@eRgnA;1#l9(Od@4j>!}00C!OmLI7;*Yg?Vgg zMbGSNLO(JkU5}JA-9cB=Nxfs(qgeA01C%tW`r)@+r$>yf* zIj^Nht^Mg^{RswGe6HQ(q@5YuA?Mb}FH3pEm(2)>Vb4rV>d>VFb=uk#KZvRPdTi`| zTR-&0IVUR2Cod}ZiPJNKg>|`B4%3jYv3i_62snT`cCTM7jrI=A-{V0 z-Ug$o^_8n|jp+5T06cHRfvWmEeDwV+fS6SM{^mGHcVd5JY5#y5WYA3y#@RITtR6d- zSk9t90P`NG%^#5K8F)`=$|swcm)$G|6Dt6xT6v3Y{36qHOZ~?B#wcF`4=kfV-fU`M) zo+Jak8-JU_7@1JF**v+$#RN%Z=cougM_<31h#yMDr8+-cmrFw#N!ju&LE!Zp=re%g zSD+H0(Hk^C{_+AMGf?oV0Q?#Y9Fc?)wGE1C7?h2gZt9<=vuRFg0GR}c)r!w#Q&F(` zi%~1;g<(Mi)xZjXX-Pc($t{p)83XSq4NuZ6b?L14@~q;`thM!2>jinc1-SD!q`P3Q z|6=A{63P(OJR@wLTxVY8?JV^#z}KGHsSN(63-Iet^I5;=-#q|?)^tM)AO>)V>^69^ za&91LRAm4ZdqHyqoM5o&IKs-9kwiHim_KW%ySP{=TcZ3XiF#}C;lAL*$1t_ulCv%i zK;ZjH1-fQx1Te?)7KZ`e5U`nB-pH!0%N#M-enepfEoUv4b+80aovWv8o zAhbVS%-p@Kg&FLP%R+0*R)_*3?3GEOl}(EkF7FlUv=xseeDHf3hU7)2!a8ch)tM#A zoT$}lQx&NFl8_Mp&^!xkRrC&jPjl?6f_`Y8^rF}@P_pRo znR|l`aDOaE31Bbsvye_S6iTF9W~NUIn1Nxiq)9M-(SZn{X#YT<(3m{g@bBM zb3DU$%wl+~8-C24cDy%m+(nJ=Dcyfp5B`}y7WlkCeJp!yShBmBJS^Ne__cI9G6mrF z>v*ZZT2$vWu4p2@i7K(^BzgCv%FU@T-dAaXuOJ?L$#)eV^0OsuCH( zXTr}3TXeHEA!Es4A!7ao{w;dIBEkw^FX{5C_R@U#a;NEZj|cTY`szyx%E{l|uM11( zTKHXjN1k$A$>m!^BG-RLSoWJB9~Ue2y1!zx&WGF<2_DoA|LlXWC=YwM7rzMZ=BgG`<=E?Lds;lE9J4il zCu_oU^Z60;cxJ{sV?F%C5|{GD^-(#`PdMxge(`slmhaG3N)u|(knKeq4TL1-)Mtp| z-BK~b2i3lU%|U69tUQgN7hX8+N5ltEq|CXM^+TLCMSOEj%=m-C{=*W^BQ@Ql$`Ib3 z)bd-D>+iddEvvr-DRRJc15q?ijcZ4>p01f%28iF$W9+l)q|;S#cNndr2_BhYXKoyqt>Rdcj5 zS!{XyU*<@2=?bM|C=AaG>I@sLemE~D=CJ9eVBn8Np<$7+>mdL(BatX*s8|}?o3~Dj zrJ@NmntdJYMuV^Z{Dn}N+*kw5dP59BMqH-t&TDM}=J?g0@aPR{a{0<@@ELVV+&A?q zpf<~un#D?m;v5s?vMz}VqB^1iXBPTjtkKY%{ z#Nm(uBl+w!q+gb0RI2C7O8Ectn1(3s5p#e=C>dinK5J>1wGvqV4SV`=DWH*7^7P|E zCBfILG@4*A6CU}SW40OoR!j6ChIE|57RmA!ri#TE(#I>0EpmhhTk6@D!(bmIV2Gol zvWJQ0hsnc$5Gm_LStxS_3=@;@0;WtIbhK24D^JDON}wG^KY?pxP{Ppd&!{roH~cmY zg9A)ZtIXLv?yH;&_VtisK(eK9rAO)~0#UOB5vn)^?jy`>`DqzyL~RxAS`x)u1W7#k z5BwTrlfO&m1=xKP8?m1G@npdyCUj?UOc|$ji9F+d?Rx6Gf9hE=H6t6LGQ5l{Ab}-8 zB3(uD&N*F`^0X{HjTbROMyZ0tQTnV3zYJn@lsldIF(doA1Zczdu_U-VZZwP>avX%q z{%EP8$J+?>b1lh-eo}3Ntb$0|$z!>H#@l6jbXoZ2y&_@Gt|}}w!*6;;x3x9XPFcoE^(k1DhOE zyu#Vx=>aU{n!V40*6mBmm05xU72U^uf|XL7qU~wQZ-N-QtD3~u>T9P%Vw?72`AimuXUVXz2@%rKMSE9s7q^m`d$`_@lnOo|e7l48 zA!uT!ER)pzMwW)5V9^0KPdON}kv-XDJ*lVT1G3^ZqnSK*N(w*y%Go0QYQFW_YvZ#2 z+3F>!u2p+9YYfs?4fa!S=(&64U3PUK9Sf0vsv?<~Y39X87ODYutzT{t&rH)ofJ0Zr zYmWVN7VqKbM50+>oZ4y`#YCP;Kq(ucLg~D7XEkpgRFRb~ErK8oA2;&GfKgBmT{~Bf z2IL-Ncte11VZuZfSOP~|MmF~`bJ>yuC9dPOaVwphuD#Kbnt;T3>(LT220li$-+;a0 zFXOCmp9Cj+BjO+a6I{pEiHeekSVDS5afnE29Qe9W*h=^1WVNQpC(>U}MyZ6WY)I-1U)yUFYzcJOFC9O2HcEkC6G5csX!=54HM zC&cWT8{H(|fIp{K6I)2YXZjcPXnaFq*hSV`ib6qrEgpT|My~M8A0R>vVlX#NL!fG8 zD35<_a4#ouLsalejBs3aYQq&F05ICKEK3qy1r1!DU!BODED`VP;TcEzwJk z=2hZ_;or%*NatQUR|!#XYvR}GN7wjhdxY7M($3(Q3-i_rW?1P5+^t3~2v+OZ0LWMS z)>WMs>fEXHjFQ>LQr-DIWTB(F6%{#9aiMaZh|^S|msrVbhQ)%#hdKbwb*EMh(i6W{AmYZ#R)a|QI%Z}JiKw-F(WNrYaAphl$&&|^+HYalJ z1d5|oDnzDqIox&Ub{|w1W_`Fm2pU4sV0S zL)mXFsMT6!Sz6qTaOIZX*@!ecJwavt?AN|~2EC&MUBru8uQxcJv_EG`c}L!tgFzzS zl}?vz`3D@NH?2N*eg5Pj8s0xhuv4hcIV-MQW zGLYgg_dtygX_456@&+&9hI#|C=r$MDp>6Gy2~XZ1`x}_egNsL(S1K2Rs88@r#rD7F zV0JhYh`n6xlZ--h-3hFc?Ed$H7sOEGv%DC04DMOjez zb0shCnrNkj;x&PFQPk6*LD|cJZ{G*S6mXuO*wv%IHNXBXH@^Fvwsqcn@n-0^>~2wH zQUi6XN8^W+9FnK;PCfrhuQrGCxXl3$V7^&m$SiFHIuX+)bA%XLt}>wpW&|SE{^ogK=o+ECL0AeB&lE7CIF1G#sM?&f@(RlEqQc|`mv(CAh!MpR4#5B}Cph%OlUh$5QcjY!Fmjoy%oZjp-s z0pm@^5}|TJdJ;pDNW}1Dh#Ej7h@$py_*;n}qTPuy^8X^fMoobRu zbwTLsav`%Yq*e!#NTmy_2Krf|fxaM>7NhLY8!sJ?gC!Hga31To?*yEyJz<|4KM4bG zS}_KoY-Bz@ffCK%&=w5?1QJf#tV$;7Oom%4A*~Uh4qT^ILFX`_OG7+1hw_R%6JBQe z36S%)v}l-fAiiayK361eL&)m_`odmBxdQrZ+W}pe<4LfN3u;K!_$=&|*k1hrOD9vQ z%qWVQPxH=#66ws;n8?PJbegOp)i0#r2$i4<$;1|fy?I1DQu*k78fQ_M>#b>&4g_u}`1XW05-5`;C~^BAD-V zel;LZFVNzKwI7!8nCe>}`w9m|b(7U~*G-pt4Rnyfy8c;9{t8e?jc(dLci`u~WDbU6rq^w3mX_F#l>%&jm}&g!U?{u)@!QL@F{b=EsM? z8jYbJ5{{Pak946bU9AJSMRnCop*76q+BG^W7}olxAuFPdsbU^THcjMPqMF-GRhi`R z8j}yY0Sg85&IS_JX1&BK?erdydXvJmI%aW$_G&o}Y7}*| zYMTtL(=d8a7zivt^86S-*+$s6FJSc=iAVt7ZWuL~j27>Yed6eRJ-g~#sn0LDk)El# zQ$7;q{1F)~^;p3EJj`fd@E%F0*nso!u5>GHg#bT(g&|?3Zt&qFi)1!yQj?7R(rpFO zPw{=8p0TQ%NtB7KmBG61tIeSVgV;1pl6$Na=bqRU)>T zNcVSQ16P95B3L{A%Y*qGeD-PIqBKSI6qR zr%3G8oux09(b;+tW*aw`+@?edD`3m$2LxpW@=GIB!K1aSY#k@Qm7G%78-#Tcpnv(r z>TzQyM)ad)qD(@G8sJnaKO2eJGXo;AEc`J;!Z?wFROS!v58X+7@+fAMT%o-)c6n+O z@7FN;8u_&>_1O^VH}NT9dUH?{c~DrpQVFG0*ar#kA15J$?*M6{^8mM2>`q+$4!(zj z{rY`PyzndnhJ&m37JiqO(JiusO2%fN%>dRSA6_9t^AGYm$ML|U4-oYAH8GNDe7Zq- zY`K+Z9GXQR{>3{En`_8Ei!_wep%ch56r68cZ(tIS)SY77V@E|u71dIyXvDVfr`#-& zoTq7U);c#BzQ)2jX3+7SYu?Kh2Ar!qNPRDzPazV`g2rr#%HnpK=rUSz~oSk^h;ZE099d-SM zFw$0w6)jst1{GmlHT051%vsuKxBVd2du`vW{(>Kl6t&mc#`8%LEyFS`r@|7iGk6yH z!zUh|Vijl-j0zx~d`H~zFO+SI{fiSxpbAeQ6w-3MpO0*z5_MU_E8o(Z*7y_`n2U_% zhXMGX13nW@Is;4&nkm6>5*L>uJvh|G?(cRUXtkYrI5Ji4 z{<=5Pb4P}a$6pGxpofacTEbNobGIR8N!)*dAmLELG!afEctc7KLRtJIFJp;&-(SMC1~D1N%vCV`z%t+ z$Swcl9zK{;o!oUI;1F9l`P*(!g4p%l8?ShiYY?Yyo-lQWKTW0}tw!PXa}_kd1@B|- z8s;Z{WghIU9k00OvY*2pyDq#!Y4D0% z>r<=tCvR+jO5C7tF#w;Q<&Q35t_(k|#qH=Kl1E8TzC}4}_|j}HvmH|5UPeI1X->Y; z^3M7ieNq-i2=XkdUXe1L_*__+_m63ICtD07?1kR=)>iuBc7LCo@O^$4Yq1JoB%*H3 zv_FBxc`w9U_Lo|Ys`xQm`bD|>iJ*ClURRQ*`R!=jZN2C@qLq5Sc4~cr-F3~V ziH)SW6Mi*UrEsUvjYB?X?bLU@+~Ue0V~ekKs8-Ek=3*ej{#lbXS*x3ci3VF&+e^=j zO<5{HSsDAVi2JiJ2{)UzvGTRa`Vp-d-mxlkeSt=)P-gL9>?LL$_W5 z-OPcnUADvSSDn>G@FR(7jYEf+rBAfr%E{qgC9kK3`3Qp@7#^Pc^Ziy%*Kt{VWfZPr zS(#(a{FgAVxV3+P7qJtj=$9sg&6giEa(0$N2aiv`vwfJ%h^zQrk)>w#4swUB(g%%1H+nQ{kX{(QWURfPW_=UwILi^>!F7{^l0IV1Cc zl$!gx+Pz(p?hy9TCr(#-tu14Mpumybl$(c?4x4yww12*x$kt*8ijs&%mBuw+AZc3s zH8k}bBBd)8(T&#L^CG*qIkf+pe&FLTx`WUm5#TUss$A2{4)zGe(qtR4NJcVkJe%J% zWxpDS&zUxGs7^zJ&{AhpQ!fb&5DD z3txc|-oi2cSXKIhlG$$m{;f?pf}?+%`ZWi~#2QARIwNj*lkd=w7w;+`i*fqjX^ns%jG-MY!-)c29*FRCJC!n3e~rRC{%1> z4piIW#S+;F5LcY90)kF18i!gV*LewqmO>|+#g@(xgGovUNBUl#{oveav7O2wHZ6@L z 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 literal 0 HcmV?d00001 diff --git a/hacktv_updsrv/ServiceVault/wtv-star/images/HackTVLogoJewel.gif b/hacktv_updsrv/ServiceVault/wtv-star/images/HackTVLogoJewel.gif new file mode 100644 index 0000000000000000000000000000000000000000..07a0f4b89f69c09aeab54c2d11da99fef40b5ca7 GIT binary patch literal 5845 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 XA&c5qT{hU11bMt+0g}mu259~tK^*wd literal 0 HcmV?d00001 diff --git a/hacktv_updsrv/ServiceVault/wtv-tricks/blastcache.txt b/hacktv_updsrv/ServiceVault/wtv-tricks/blastcache.txt new file mode 100644 index 00000000..a26fd7cd --- /dev/null +++ b/hacktv_updsrv/ServiceVault/wtv-tricks/blastcache.txt @@ -0,0 +1,17 @@ +200 OK +wtv-noback-all: wtv- +wtv-expire-all: wtv- +Content-type: text/html + + + + + +Successfully expired service URL cache
+Any previously cached pages should be reloaded from the network.

+Go Home + + \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/wtv-tricks/go-offline.js b/hacktv_updsrv/ServiceVault/wtv-tricks/go-offline.js new file mode 100644 index 00000000..f43dad67 --- /dev/null +++ b/hacktv_updsrv/ServiceVault/wtv-tricks/go-offline.js @@ -0,0 +1,42 @@ +headers = `200 OK +wtv-noback-all: wtv- +wtv-expire-all: wtv- +Content-type: text/html +wtv-service: reset +`+getServiceString('wtv-1800'); + + +// HackTV Homepage is default +var url="file://Disk/Browser/Games/Games.html"; + +if (query['url']) { + url = query['url']; +} + +data = ` + +Going offline... + + + +

+` +if (query['title']) { + data += "Going offline and loading "+decodeURI(query['title'])+", please wait!"; +} else { + data += "Please wait a moment."; +} + +data += "\n"; diff --git a/hacktv_updsrv/ServiceVault/wtv-update/content/diskmaps/htvupdate.txt b/hacktv_updsrv/ServiceVault/wtv-update/content/diskmaps/htvupdate.txt new file mode 100644 index 00000000..d2d97268 --- /dev/null +++ b/hacktv_updsrv/ServiceVault/wtv-update/content/diskmaps/htvupdate.txt @@ -0,0 +1,10 @@ +GROUP name=Browser version=!VERS! root=file://Disk/Browser/Games/ + display Updating HackTV Files... + sync Games.html content/htvupdate/Games/Games.html + sync cSetup.html content/htvupdate/Games/cSetup.html +END-GROUP + +GROUP name=Browser version=!VERS! root=file://Disk/Browser/MattMan/ + display Updating HackTV Files... + sync Tricks/tricks.html content/htvupdate/MattMan/Tricks/tricks.html +END-GROUP \ No newline at end of file diff --git a/hacktv_updsrv/ServiceVault/htv-update/upd/Games.html b/hacktv_updsrv/ServiceVault/wtv-update/content/htvupdate/Games/Games.html similarity index 95% rename from hacktv_updsrv/ServiceVault/htv-update/upd/Games.html rename to hacktv_updsrv/ServiceVault/wtv-update/content/htvupdate/Games/Games.html index 1acd2e95..a76fca83 100644 --- a/hacktv_updsrv/ServiceVault/htv-update/upd/Games.html +++ b/hacktv_updsrv/ServiceVault/wtv-update/content/htvupdate/Games/Games.html @@ -81,7 +81,7 @@ if (document.images) {
  • HTML Viewer
  • HackTV Tricks
  • Connect Setup -
  • Test +
  • NEW! Check for Updates
  • diff --git a/hacktv_updsrv/ServiceVault/htv-update/upd/cSetup.html b/hacktv_updsrv/ServiceVault/wtv-update/content/htvupdate/Games/cSetup.html similarity index 100% rename from hacktv_updsrv/ServiceVault/htv-update/upd/cSetup.html rename to hacktv_updsrv/ServiceVault/wtv-update/content/htvupdate/Games/cSetup.html diff --git a/hacktv_updsrv/ServiceVault/htv-update/upd/tricks.html b/hacktv_updsrv/ServiceVault/wtv-update/content/htvupdate/MattMan/Tricks/tricks.html similarity index 100% rename from hacktv_updsrv/ServiceVault/htv-update/upd/tricks.html rename to hacktv_updsrv/ServiceVault/wtv-update/content/htvupdate/MattMan/Tricks/tricks.html diff --git a/hacktv_updsrv/ServiceVault/wtv-update/sync.js b/hacktv_updsrv/ServiceVault/wtv-update/sync.js new file mode 100644 index 00000000..8be14f6b --- /dev/null +++ b/hacktv_updsrv/ServiceVault/wtv-update/sync.js @@ -0,0 +1,39 @@ +var content_dir = service_dir + '/content/'; +var diskmap_dir = content_dir + '/diskmaps/'; + +if (initial_headers['post_data']) { + console.log(initial_headers['post_data'].toString('CryptoJS.enc.Latin1')) +} + +if (query['diskmap']) { + if (fs.lstatSync(diskmap_dir + query['diskmap'] + ".txt")) { + var diskmap_data = fs.readFileSync(diskmap_dir + query['diskmap'] + ".txt").toString(); + // try to parse diskmap and get an accurate timestamp for webtv versioning + // check all files in the diskmap and return the timestamp of the most recently modified + + data = ''; + var latest_file_ts = 0; + diskmap_data.split("\n").forEach(function (v) { + if (v.indexOf(" sync ") != -1) { + v = v.trim(); + var vcon = v.substring(v.indexOf("content/")); + vcon = vcon.replace("content/", content_dir) + var vconstat = Math.floor(fs.lstatSync(vcon).mtimeMs / 1000); + if (vconstat > latest_file_ts) { + latest_file_ts = vconstat + } + // todo read client post and only give whats needed + // instead of all that is available + // vconstat has the mtime of each file, we need to parse the post_data + data += v + "\n"; + } else { + data += v + "\n"; + } + }); + //data = diskmap_data.replace("!VERS!", latest_file_ts); + } +} + +headers = `200 OK +Content-type: text/download-list` + diff --git a/hacktv_updsrv/ServiceVault/htv-update/update.html b/hacktv_updsrv/ServiceVault/wtv-update/update.html similarity index 69% rename from hacktv_updsrv/ServiceVault/htv-update/update.html rename to hacktv_updsrv/ServiceVault/wtv-update/update.html index 11a29cd0..7c2cf193 100644 --- a/hacktv_updsrv/ServiceVault/htv-update/update.html +++ b/hacktv_updsrv/ServiceVault/wtv-update/update.html @@ -2,10 +2,10 @@ - - Retrieving Files + + HackTV Updater @@ -18,7 +18,7 @@
    - Retrieving Files + Download HackTV Updates
    @@ -31,7 +31,7 @@ @@ -40,7 +40,7 @@

    - Your HackTV Box is downloading updates from zefie's server. + Your HackTV Unit is downloading updates.

    This may take a while.

    diff --git a/hacktv_updsrv/ServiceVault/htv-update/updatesuccess.txt b/hacktv_updsrv/ServiceVault/wtv-update/updatesuccess.txt similarity index 76% rename from hacktv_updsrv/ServiceVault/htv-update/updatesuccess.txt rename to hacktv_updsrv/ServiceVault/wtv-update/updatesuccess.txt index 5d3cf0cf..9655cb3d 100644 --- a/hacktv_updsrv/ServiceVault/htv-update/updatesuccess.txt +++ b/hacktv_updsrv/ServiceVault/wtv-update/updatesuccess.txt @@ -1,3 +1,4 @@ +200 OK Content-Type: text/url client:ShowAlert?message=HackTV%20Update%20was%20successful%21&buttonlabel2=Go%20to%20HackTV&action2=file%3A%2F%2FDisk%2FBrowser%2FGames%2FGames.html&buttonlabel1=Okay&buttonaction1=client:goback&image=file://disk/browser/Games/hacktv2.gif&noback=true \ No newline at end of file diff --git a/hacktv_updsrv/app.js b/hacktv_updsrv/app.js index fdeefb09..b85c1d27 100644 --- a/hacktv_updsrv/app.js +++ b/hacktv_updsrv/app.js @@ -7,76 +7,105 @@ const strftime = require('strftime'); const net = require('net'); const CryptoJS = require('crypto-js'); const mime = require('mime-types'); -var WTVNetworkSecurity = require('./wtvsec.js'); +const crc16 = require('node-crc16'); +var WTVSec = require('./wtvsec.js'); var zdebug = true; -var pubip = "192.168.11.8"; -var port = 1615; +var ports = []; +var service_vault_dir = __dirname + "/ServiceVault"; + +function getServiceString(service) { + if (service === "all") { + var out = ""; + Object.keys(services_configured.services).forEach(function (k) { + out += services_configured.services[k].toString() + "\n"; + }); + return out; + } else { + if (!services_configured.services[service]) { + throw ("SERVICE ERROR: Attempted to provision unconfigured service: " + service) + } else { + return services_configured.services[service].toString(); + } + } +} + +var ssid_data = new Array(); var sec_session = new Array(); +var socket_buffer = new Array(); +var socket_session_data = new Array(); -function getWTVIncarnation(headers, ssid = null) { - var incarnation = null; - headers.some(function (v) { - if (v.substring(0, 15) === "wtv-incarnation") { - incarnation = v.split(': ')[1].replace("\r", ""); - return incarnation != null; - } - }); - if (ssid != null && incarnation != null) { - if (sec_session[ssid] != null) { - sec_session[ssid].set_incarnation(incarnation); - if (zdebug) console.log(" * Updated wtv-incarnation for " + ssid + " to " + incarnation + " ..."); - } - } - return incarnation; +var script_processing_timeout = 10; // seconds + +var overrides = new Array(); +//overrides['initial_key'] = "CC5rWmRUE0o="; +//overrides['challenge'] = "0kjyqIYAu0ziFBbSERN6DGaZ6S0fT+DBUCtpHCJ4lpuM7CbXdAm+x83BIDoJYztd1Z+5KFZ7ghmb3LJCT/6mhWUYkqqKOyfPRW8ZIdbICK/CV+Kxm8EUjRXZSk/97tsmFpH3hcCJ7C2TBw+TX38uQQ=="; + +function getSessionData(ssid, key = null) { + if (typeof (ssid_data[ssid]) === 'undefined') return null; + if (key == null) return ssid_data[ssid]; + else if (ssid_data[ssid][key]) return ssid_data[ssid][key]; + else return null; } -function getWTVROMType(headers, ssid = null) { - var romtype = null; - headers.some(function (v) { - if (v.substring(0, 19) === "wtv-client-rom-type") { - romtype = v.split(': ')[1].replace("\r", ""); - return romtype != null; - } - }); - return romtype; +function setSessionData(ssid, key, value) { + if (typeof (ssid_data[ssid]) === 'undefined') ssid_data[ssid] = new Array(); + ssid_data[ssid][key] = value; } - - -function getPublicIP() { - var options = { - host: 'www.planeptune.org', - path: '/ip.php' +function getFile(path, deps = false) { + var dir = null; + if (deps) dir = __dirname + "/ServiceDeps/"; + else dir = __dirname + "/ServiceVault/"; + if (fs.lstatSync(dir + path).isFile()) { + return fs.readFileSync(dir + path, { + encoding: null, + flags: 'r' + }); + } + return null; +} + + +function issueWTVInitialKey(socket) { + if (overrides['initial_key']) { + sec_session[socket_session_data[socket.id].ssid].initial_shared_key = CryptoJS.enc.Base64.parse(overrides['initial_key']); + sec_session[socket_session_data[socket.id].ssid].current_shared_key = CryptoJS.enc.Base64.parse(overrides['initial_key']); + sec_session[socket_session_data[socket.id].ssid].challenge_key = CryptoJS.enc.Base64.parse(overrides['initial_key']); + return overrides['initial_key']; + } else { + return sec_session[socket_session_data[socket.id].ssid].challenge_key.toString(CryptoJS.enc.Base64); + } +} + +function issueWTVChallenge(socket) { + if (overrides['challenge']) { + sec_session[socket_session_data[socket.id].ssid].challenge_response = sec_session[socket_session_data[socket.id].ssid].ProcessChallenge(overrides['challenge']); + return overrides['challenge']; + } else { + return sec_session[socket_session_data[socket.id].ssid].IssueChallenge(); } - var request = https.get(options, function (res) { - var data = ''; - res.on('data', function (chunk) { - data += chunk; - }); - res.on('end', function () { - return data; - }); - }); } function doErrorPage(code) { var headers, data = null; switch (code) { case 404: - data = "The resource you requested could not be found."; - headers = "HTTP/1.1 404 Not Found\r\n"; + data = "The service could not find the requested page."; + headers = "404 "+data+"\r\n"; headers += "Content-Type: text/html\r\n"; break; - case 500: + case 400: data = "An internal server error has occured."; - headers = "HTTP/1.1 500 HackTV has ran into a technical problem.\r\n"; + headers = "400 HackTV ran into a technical problem.\r\n"; headers += "Content-Type: text/html\r\n"; break; default: + // what we send when we did not detect a wtv-url. + // e.g. when a pc browser connects data = "Hello, stranger!"; headers = "HTTP/1.1 200 OK\r\n"; headers += "Content-Type: text/html\r\n"; @@ -85,9 +114,18 @@ function doErrorPage(code) { return new Array(headers, data); } -function processPath(path, initial_headers = new Array(), query = new Array()) { +function getConType(path) { + // custom contype for flashrom + if (path.indexOf("wtv-flashrom") && (path.substring(path.length - 4, path.length) == ".rom" || path.substring(path.length - 5, path.length) == ".brom")) { + return "binary/x-wtv-flashblock"; + } + return mime.lookup(path); +} + +async function processPath(socket, path, request_headers = new Array(), query = new Array(), service_name) { var headers, data = null; var request_is_direct_file = false; + path = path.replace(/\\/g, "/"); try { try { // try to see if the exact request exists @@ -100,29 +138,42 @@ function processPath(path, initial_headers = new Array(), query = new Array()) { if (request_is_direct_file) { // file exists, read it and return it - console.log(" * Found " + path + " to handle request"); - var contype = mime.lookup(path); - data = fs.readFileSync(path); - headers = "200 OK\r\n" + console.log(" * Found " + path + " to handle request (Direct File Mode) [Socket " + socket.id +"]"); + var contype = getConType(path); + data = new Uint8Array(fs.readFileSync(path)).buffer; + headers = "200 OK\n" headers += "Content-Type: " + contype; } else if (fs.existsSync(path + ".txt")) { // raw text format, entire payload expected (headers and content) - console.log(" * Found " + path + ".txt to handle request"); - var fdat = fs.readFileSync(path + ".txt").toString(); - headers = fdat.split("\r\n\r\n")[0]; - data = fdat.split("\r\n\r\n")[1]; + console.log(" * Found " + path + ".txt to handle request (Raw TXT Mode) [Socket " + socket.id +"]"); + var file_raw = fs.readFileSync(path + ".txt").toString(); + if (file_raw.indexOf("\n\n") > 0) { + var file_raw_split = file_raw.split("\n\n"); + headers = file_raw_split[0]; + file_raw_split.shift(); + data = file_raw_split.join("\n"); + } else if (file_raw.indexOf("\r\n\r\n") > 0) { + var file_raw_split = file_raw.split("\r\n\r\n"); + headers = file_raw_split[0].replace(/\r/g, ""); + file_raw_split.shift(); + data = file_raw_split.join("\r\n"); + } else { + headers = fdat; + } } else if (fs.existsSync(path + ".js")) { // js scripting, process with vars, must set 'headers' and 'data' appropriately. // loaded script will have r/w access to any JavaScript vars this function does. // any query args are in an array named 'query' - console.log(" * Found " + path + ".js to handle request"); - var fdat = fs.readFileSync(path + ".js").toString(); - eval(fdat); + console.log(" * Found " + path + ".js to handle request (JS Interpreter mode) [Socket " + socket.id + "]"); + var service_dir = service_vault_dir.replace(/\\/g,"/") + "/" + service_name; + socket_session_data[socket.id].starttime = Math.floor(new Date().getTime() / 1000); + var jscript_eval = fs.readFileSync(path + ".js").toString(); + eval(jscript_eval); } else if (fs.existsSync(path + ".html")) { // Standard HTML with no headers, WTV Style - console.log(" * Found " + path + ".html to handle request"); + console.log(" * Found " + path + ".html to handle request (HTML Mode) [Socket " + socket.id +"]"); data = fs.readFileSync(path + ".html").toString(); - headers = "200 OK\r\n" + headers = "200 OK\n" headers += "Content-Type: text/html" } else { var errpage = doErrorPage(404); @@ -137,128 +188,508 @@ function processPath(path, initial_headers = new Array(), query = new Array()) { if (typeof headers !== "string") { headers = headers.toString(); } - if (headers.indexOf("\r") === -1) { - headers = headers.replace("\n", "\r\n"); - } } else { - var errpage = doErrorPage(500); + var errpage = doErrorPage(400); headers = errpage[0]; data = errpage[1]; + console.log(" * Scripting or Data error: Headers were not defined. (headers,data) as follows:") + console.log(headers,data) } if (data === null) { data = ''; } - if (typeof data !== "string") { - data = data.toString(); - } } catch (e) { - var errpage = doErrorPage(500); + var errpage = doErrorPage(400); headers = errpage[0]; - data = errpage[1] + "

    " + e.toString() + "
    "; + data = errpage[1] + "

    The interpreter said:
    " + e.toString() + "
    "; console.log(e); } - if (headers.toLowerCase().indexOf("content-length") === -1) { - headers += "\r\nContent-Length: " + data.length; - } return new Array(headers, data); } -function processURL(initial_headers, socket) { +async function processURL(socket, request_headers) { + if (request_headers === null) { + return; + } var shortURL, headers, data = ""; var query = new Array(); - if (initial_headers['request_url'].indexOf('?') >= 0) { - shortURL = initial_headers['request_url'].split('?')[0]; - var qraw = initial_headers['request_url'].split('?')[1]; - if (qraw.length > 0) { - qraw = qraw.split("&"); - for (let i = 0; i < qraw.length; i++) { - query[qraw[i].split("=")[0]] = qraw[i].split("=")[1]; - } - if (zdebug) { - console.log("URL Request has query arguments:") - console.log(query); - } - } - } else { - shortURL = initial_headers['request_url']; - } + if (request_headers['request_url']) { + if (request_headers['request_url'].indexOf('?') >= 0) { + shortURL = request_headers['request_url'].split('?')[0]; + var qraw = request_headers['request_url'].split('?')[1]; + if (qraw.length > 0) { + qraw = qraw.split("&"); + for (let i = 0; i < qraw.length; i++) { + var k = qraw[i].split("=")[0]; + if (k) { + query[k] = qraw[i].split("=")[1]; + } + } - if (shortURL.indexOf(':/') >= 0) { - var ssid = initial_headers['wtv-client-serial-number']; - if (ssid != null) { - console.log(" * Request for " + initial_headers['request_url'] + " from WebTV SSID " + ssid); + console.log(" * Request query:", query); + } } else { - console.log(" * Request for " + initial_headers['request_url']); + shortURL = request_headers['request_url']; } - // assume webtv since there is a :/ in the GET - var urlToPath = __dirname + "/ServiceVault/" + shortURL.split(':/')[0] + "/" + shortURL.split(':/')[1]; - if (zdebug) console.log(initial_headers); - var result = processPath(urlToPath, initial_headers, query); - if (result[0] == null) { - var errpage = doErrorPage(404); - headers = errpage[0]; - data = errpage[1]; - } else { - headers = result[0]; - data = result[1]; - } - } else { - switch (shortURL) { - default: - var errpage = doErrorPage(200); + if (shortURL.indexOf(':/') >= 0) { + var ssid = socket_session_data[socket.id].ssid; + if (ssid == null) { + ssid = request_headers['wtv-client-serial-number']; + } + var reqverb = "Request"; + if (request_headers['encrypted'] || request_headers['secure']) { + reqverb = "Encrypted " + reqverb; + } + if (request_headers['psuedo-encryption']) { + reqverb = "Psuedo-encrypted " + reqverb; + } + if (ssid != null) { + console.log(" * "+reqverb+" for " + request_headers['request_url'] + " from WebTV SSID " + ssid, 'on', socket.id); + } else { + console.log(" * "+reqverb+" for " + request_headers['request_url'], 'on', socket.id); + } + // assume webtv since there is a :/ in the GET + var service_name = shortURL.split(':/')[0]; + var urlToPath = service_vault_dir.replace(/\\/g, "/") + "/" + service_name + "/" + shortURL.split(':/')[1]; + console.log(request_headers); + var result = await processPath(socket, urlToPath, request_headers, query, service_name); + + if (result[0] == null) { + // error processing path + var errpage = doErrorPage(404); headers = errpage[0]; data = errpage[1]; - break; + } else { + headers = result[0]; + data = result[1]; + } + } else { + switch (shortURL) { + default: + var errpage = doErrorPage(200); + headers = errpage[0]; + data = errpage[1]; + break; + } + } + } else { + // error reading headers (no request_url provided) + var errpage = doErrorPage(400); + headers = errpage[0]; + data = errpage[1] + socket_session_data[socket.id].close_me = true; + } + + // headers to object + if (typeof headers != 'object') { + var headers_obj = {}; + var inc_headers = 1; + headers.split('\n').forEach(function (d) { + if (d.length > 0) { + if (d.indexOf(":") > 0 && !/^([0-9]{3} )/.test(d.substring(0, 4))) { + var d = d.split(':'); + var header_name = d[0]; + d.shift(); + if (headers_obj[header_name] != null) { + header_name = header_name + "_" + inc_headers; + inc_headers++; + } + headers_obj[header_name] = d.join(':').replace("\r", ""); + if (headers_obj[header_name].substring(0, 1) == " ") { + headers_obj[header_name] = headers_obj[header_name].substring(1); + } + } else if (/^([0-9]{3} )/.test(d.substring(0, 4))) { + headers_obj['http_response'] = d.replace("\r", ""); + } + } + }); + } else { + header_obj = headers; + } + + if (!headers_obj['Connection']) { + headers_obj['Connection'] = "Keep-Alive"; + headers_obj = moveObjectElement('Connection','http_response', headers_obj); + } + + if (request_headers['psuedo-encryption'] || getSessionData(socket_session_data[socket.id].ssid, 'box-does-psuedo-encryption')) { + request_headers['psuedo-encryption'] = true; + headers_obj['wtv-encrypted'] = true; + headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj); + } + + // set wtv-encrypted and put it near the top of the headers (unknown if needed) + if (socket_session_data[socket.id].secure == true) { + var clen = null; + if (typeof data.length !== 'undefined') { + clen = data.length; + } else if (typeof data.byteLength !== 'undefined') { + clen = data.byteLength; + } + headers_obj['wtv-encrypted'] = true; + headers_obj = moveObjectElement('wtv-encrypted', 'Connection', headers_obj); + if (clen > 0) { + console.log(" * Encrypting response to client ...") + var data_type = typeof (data); + if (typeof (data) === 'string') { + data = CryptoJS.enc.Utf8.parse(data); + } + if (data.constructor === ArrayBuffer) { + data = CryptoJS.lib.WordArray.create(data); + } + var enc_data = sec_session[socket.id].Encrypt(1,data); + data = enc_data; } } + if (!headers_obj["Content-length"] && !headers_obj["Content-length"]) { + if (typeof data.length !== 'undefined') { + headers_obj['Content-Length'] = data.length; + } else if (typeof data.byteLength !== 'undefined') { + headers_obj['Content-Length'] = data.byteLength; + } + } - var toClient = headers + "\r\n\r\n" + data; - console.log(headers); - socket.write(toClient); - socket.destroy(); + headers = ""; + console.log(headers_obj); + Object.keys(headers_obj).forEach(function (k) { + if (k == "http_response") { + headers += headers_obj[k] + "\r\n"; + } else { + if (k.indexOf('_') >= 0) { + var j = k.split('_')[0]; + headers += j + ": " + headers_obj[k] + "\n"; + } else { + headers += k + ": " + headers_obj[k] + "\n"; + } + } + }); + var toClient = null; + if (typeof data == 'string') { + toClient = headers + "\n" + data; + socket.write(toClient); + } else if (typeof data == 'object') { + if (socket_session_data[socket.id].secure_headers == true) { + var enc_headers = sec_session[socket.id].Encrypt(1,headers+"\n"); + socket.write(new Uint8Array(concatArrayBuffer(enc_headers, data))); + } else { + socket.write(new Uint8Array(concatArrayBuffer(Buffer.from(headers + "\n"), data))); + } + } + if (headers_obj['Connection']) { + if (headers_obj['Connection'].toLowerCase() == "close") { + socket.destroy(); + } + } + } +function concatArrayBuffer(buffer1, buffer2) { + var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); + tmp.set(new Uint8Array(buffer1), 0); + tmp.set(new Uint8Array(buffer2), buffer1.byteLength); + return tmp.buffer; +} -var server = net.createServer(function (socket) { - socket.setEncoding("utf8"); //set data encoding (either 'ascii', 'utf8', or 'base64') +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; +} - socket.on('data', function (data) { - var url = ""; - var headers = new Array(); - if (typeof data === "string") { - data.split('\n').forEach(function (d) { - if (d != "") { - if (d == "SECURE ON") { - headers['secure'] = true; +function headersAreStandard(string, verbose) { + // the test will see the binary compressed/enrypted data as ASCII, so a generic "isAscii" + // is not suffuicent. This checks for characters expected in unecrypted headers, and returns + // true only if every character in the string matches the regex. Once we know the string is binary + // we can better process it with the raw base64 data in processHeaders() below. + var test = /^([A-Za-z0-9\+\/\=\-\.\,\ \;\:\?\&\r\n\(\)\%\<\>\_]{8,})$/.test(string); + if (verbose) { + if (zdebug) console.log(" # Request is ascii: " + test); + if (zdebug) console.log(" # Request is SECURE ON: " + /^SECURE ON/.test(string)); + } + return test; + } + +async function processHeaders(socket, data_hex, returnHeadersBeforeSecure = false, encryptedRequest = false) { + var url = ""; + var data = CryptoJS.enc.Latin1.stringify(CryptoJS.enc.Hex.parse(data_hex)); + + var headers = new Array(); + if (typeof data === "string") { + if (data.length > 1) { + if (data.indexOf("\r\n\r\n") != -1) { + data = data.split("\r\n\r\n")[0]; + } else { + data = data.split("\n\n")[0]; + } + if (headersAreStandard(data, (!returnHeadersBeforeSecure && !encryptedRequest))) { + data.split('\n').forEach(function (d) { + if (d.length > 0) { + if (/^SECURE ON/.test(d)) { + headers['secure'] = true; + //socket_session_data[socket.id].secure_headers = true; + } + if (d.indexOf(":") > 0 && d.indexOf(":/") == -1) { + headers[d.split(':')[0]] = (d.split(':')[1]).replace("\r", ""); + if (headers[d.split(':')[0]].substring(0, 1) == " ") { + headers[d.split(':')[0]] = headers[d.split(':')[0]].substring(1); + } + } else if (/^(GET |PUT |POST)$/.test(d.substring(0, 4))) { + headers['request'] = d.replace("\r", ""); + headers['request_url'] = (d.split(' ')[1]).replace("\r", ""); + } } - if (d.indexOf(": ") > 0) { - headers[d.split(': ')[0]] = (d.split(': ')[1]).replace("\r",""); - } else if (/^(GET |PUT |POST)$/.test(d.substring(0, 4))) { - headers['request'] = d.replace("\r", ""); - headers['request_url'] = (d.split(' ')[1]).replace("\r", ""); + }); + } else if (!returnHeadersBeforeSecure) { + // if its a POST request, assume its a binary blob and not encrypted (dangerous) + if (!encryptedRequest) { + // its not a POST and it 1failed the headersAreStandard test, so we think this is an encrypted blob + if (socket_session_data[socket.id].secure != true) { + // first time so reroll sessions + sec_session[socket.id] = new WTVSec(); + sec_session[socket.id].IssueChallenge(); + if (zdebug) console.log(" # [ UNEXPECTED BINARY BLOCK ] First sign of encryption, re-creating RC4 sessions for socket id",socket.id); + sec_session[socket.id].SecureOn(); + socket_session_data[socket.id].secure = true; + } + var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2)); + if (enc_data.sigBytes > 0) { + var dec_data = CryptoJS.lib.WordArray.create(sec_session[socket.id].Decrypt(0,enc_data)); + var secure_headers = await processHeaders(socket, dec_data.toString(CryptoJS.enc.Hex), true, true); + headers['encrypted'] = true; + Object.keys(secure_headers).forEach(function (k, v) { + headers[k] = secure_headers[k]; + }); } } - }); - console.log(headers); - if (headers['secure'] === true) { - // assume we have an ssid if we are this far - sec_session[headers['wtv-client-serial-number']].SecureOn(); - if (!headers['request_url']) { - headers['request_url'] = "wtv-head-waiter:/login-stage-two?"; - } } - processURL(headers,this); + if (headers['wtv-client-serial-number'] != null) { + socket_session_data[socket.id].ssid = headers['wtv-client-serial-number']; + } + if (headers['wtv-client-rom-type'] != null) { + if (socket_session_data[socket.id].ssid) { + setSessionData(socket_session_data[socket.id].ssid, 'wtv-client-rom-type', headers['wtv-client-rom-type']); + } + } + if (headers['wtv-incarnation'] != null) { + if (sec_session[socket.id]) { + sec_session[socket.id].set_incarnation(headers['wtv-incarnation']); + } else { + setSessionData(socket_session_data[socket.id].ssid, 'incarnation', headers['wtv-incarnation']) + } + } + + if (returnHeadersBeforeSecure) { + headers = await checkForPostData(socket, headers, data, data_hex, returnHeadersBeforeSecure); + return headers; + } + + if (headers['secure'] === true) { + if (!sec_session[socket.id]) { + console.log(" * Starting new WTVSec instance on socket", socket.id); + sec_session[socket.id] = new WTVSec(); + sec_session[socket.id].DecodeTicket(headers['wtv-ticket']); + sec_session[socket.id].ticket_b64 = headers['wtv-ticket']; + if (getSessionData(socket_session_data[socket.id].ssid, 'incarnation')) { + sec_session[socket.id].incarnation = getSessionData(socket_session_data[socket.id].ssid, 'incarnation'); + } + sec_session[socket.id].SecureOn(); + } + if (socket_session_data[socket.id].secure != true) { + // first time so reroll sessions + if (zdebug) console.log(" # [ SECURE ON BLOCK ("+socket.id+")]"); + socket_session_data[socket.id].secure = true; + } + if (!headers['request_url']) { + + if (data_hex.indexOf("0d0a0d0a")) { + // \r\n\r\n + var header_length = data.length + 4; + } else if (data_hex.indexOf("0a0a")) { + // \n\n + var header_length = data.length + 2; + } + var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2)); + if (enc_data.sigBytes > 0) { + if (headersAreStandard(enc_data.toString(CryptoJS.enc.Latin1), (!returnHeadersBeforeSecure && !encryptedRequest))) { + // some builds (like our targeted 3833), send SECURE ON but then unencrypted headers + if (zdebug) console.log(" # Psuedo-encrypted Request (SECURE ON)", "on", socket.id); + // don't actually encrypt output + headers['psuedo-encryption'] = true; + setSessionData(socket_session_data[socket.id].ssid, 'box-does-psuedo-encryption', true); + socket_session_data[socket.id].secure = false; + var secure_headers = await processHeaders(socket, enc_data.toString(CryptoJS.enc.Hex), true); + } else { + // SECURE ON and detected encrypted data + setSessionData(socket_session_data[socket.id].ssid, 'box-does-psuedo-encryption', false); + var dec_data = CryptoJS.lib.WordArray.create(sec_session[socket.id].Decrypt(0, enc_data)) + var secure_headers = await processHeaders(socket, dec_data.toString(CryptoJS.enc.Hex), true); + if (zdebug) console.log(" # Encrypted Request (SECURE ON)", "on", socket.id); + } + // Merge new headers into existing headers object + Object.keys(secure_headers).forEach(function (k, v) { + headers[k] = secure_headers[k]; + }); + } + } + } + headers = await checkForPostData(socket, headers, data, data_hex); + return headers; + } else { + // socket error, terminate it. + socket.destroy(); + } + } + return null; +} + +async function checkForPostData(socket, headers, data, data_hex) { + if (headers['request']) { + if (headers['request'].substring(0, 4) == "POST") { + if (data_hex.indexOf("0d0a0d0a") != -1) { + // \r\n\r\n + var header_length = data.length + 4; + } else if (data_hex.indexOf("0a0a") != -1) { + // \n\n + var header_length = data.length + 2; + } + if (socket_session_data[socket.id].secure == true) { + var enc_data = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2)); + if (enc_data.sigBytes > 0) { + if (headersAreStandard(enc_data.toString(CryptoJS.enc.Latin1))) { + // some builds (like our targeted 3833), send SECURE ON but then unencrypted headers + if (zdebug) console.log(" # Psuedo-encrypted POST Content (SECURE ON)", "on", socket.id); + // don't actually encrypt output + headers['psuedo-encryption'] = true; + setSessionData(socket_session_data[socket.id].ssid, 'box-does-psuedo-encryption', true); + socket_session_data[socket.id].secure = false; + headers['post_data'] = await processHeaders(socket, enc_data.toString(CryptoJS.enc.Hex), true); + } else { + // SECURE ON and detected encrypted data + setSessionData(socket_session_data[socket.id].ssid, 'box-does-psuedo-encryption', false); + headers['post_data'] = CryptoJS.lib.WordArray.create(sec_session[socket.id].Decrypt(0, enc_data)) + if (zdebug) console.log(" # Encrypted POST Content (SECURE ON)", "on", socket.id); + } + } + } else { + if (zdebug) console.log(" # Unencrypted POST Content", "on", socket.id); + headers['post_data'] = CryptoJS.enc.Hex.parse(data_hex.substring(header_length * 2)); + } + } + } + return headers; +} + +async function cleanupSocket(socket) { + try { + console.log(" * Destroying old WTVSec instance on disconnected socket", socket.id); + delete socket_buffer[socket.id]; + delete socket_session_data[socket.id]; + delete sec_session[socket.id]; + socket.end(); + } catch (e) { + console.log(" # Could not clean up socket data for socket ID", socket.id, e); + } +}; + + +async function handleSocket(socket) { + // create unique socket id with client address and port + socket.id = parseInt(crc16.checkSum(Buffer.from(String(socket.remoteAddress) + String(socket.remotePort), "utf8")).toString("hex"),16); + socket_session_data[socket.id] = []; + socket.setEncoding('hex'); //set data encoding (either 'ascii', 'utf8', or 'base64') + socket.on('data', function (data_hex) { + socket.setTimeout(300); + if (socket_buffer[socket.id]) { + socket_buffer[socket.id].concat(CryptoJS.enc.Hex.parse(data_hex)); + } else { + socket_buffer[socket.id] = CryptoJS.enc.Hex.parse(data_hex); } }); + socket.on('timeout', async function () { + socket.setTimeout(0); + var phead = await processHeaders(this, socket_buffer[socket.id].toString(CryptoJS.enc.Hex)); + processURL(this, phead); + if (socket_session_data[socket.id].close_me) socket.end(); + socket_buffer[socket.id] = null; + }); + + socket.on('error', (err) => { + socket.end(); + }); + + socket.on('end', function () { + cleanupSocket(socket); + }); +} + +var z_title = "zefie's wtv minisrv v" + require('./package.json').version; +console.log("**** Welcome to " + z_title + " ****"); +console.log(" *** Reading service configuration..."); +try { + var services_configured = JSON.parse(fs.readFileSync(__dirname + "/services.json")); +} catch (e) { + throw("ERROR: Could not read services.json", e); +} +var service_ip = services_configured.config.service_ip; +Object.keys(services_configured.services).forEach(function (k) { + services_configured.services[k].name = k; + if (!services_configured.services[k].host) { + services_configured.services[k].host = service_ip; + } + if (services_configured.services[k].port) { + ports.push(services_configured.services[k].port); + } + services_configured.services[k].toString = function () { + var outstr = "wtv-service: name=" + this.name + " host=" + this.host + " port=" + this.port; + if (this.flags) outstr += " flags=" + this.flags; + if (this.connections) outstr += " flags=" + this.connections; + if (k == "wtv-star") { + outstr += "\nwtv-service: name=wtv-* host=" + this.host + " port=" + this.port; + if (this.flags) outstr += " flags=" + this.flags; + if (this.connections) outstr += " flags=" + this.connections; + } + return outstr; + } + console.log(" * Configured Service", k, "on port", services_configured.services[k].port); +}) + +var initstring = ''; +ports.sort(); + +// de-duplicate ports in case user configured multiple services on same port +const bind_ports = [...new Set(ports)] + +bind_ports.forEach(function (v) { + try { + var server = net.createServer(handleSocket); + server.listen(v, '0.0.0.0'); + initstring += v + ", "; + } catch (e) { + throw ("Could not bind to port", v, e.toString()); + } }); +initstring = initstring.substring(0, initstring.length - 2); -server.listen(port, '0.0.0.0'); -process.stdout.write("Looking up public IP address... "); -//pubip = getPublicIP(); -console.log(pubip + " ..."); +console.log(" * Started server on ports " + initstring + "... Service IP is " + service_ip); -console.log('Listening on port ' + port + ' for WebTV Units in Scriptless Mode'); \ No newline at end of file diff --git a/hacktv_updsrv/hacktv_updsrv.njsproj b/hacktv_updsrv/hacktv_updsrv.njsproj index 5758b1e2..44cc8b5b 100644 --- a/hacktv_updsrv/hacktv_updsrv.njsproj +++ b/hacktv_updsrv/hacktv_updsrv.njsproj @@ -28,12 +28,59 @@ true + + + Code + + + + + + + + + + + + + + + + Code + + + + + + + + + + + Code - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hacktv_updsrv/package-lock.json b/hacktv_updsrv/package-lock.json index ec3f2423..29ba1225 100644 --- a/hacktv_updsrv/package-lock.json +++ b/hacktv_updsrv/package-lock.json @@ -1,26 +1,23 @@ { "name": "hacktv_updsrv", - "version": "0.0.0", + "version": "0.5.2", "lockfileVersion": 1, "requires": true, "dependencies": { - "arc4": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/arc4/-/arc4-3.4.0.tgz", - "integrity": "sha512-zFQmSbTwSTrICYV8kldrD3YreCtlLIKEZk+lmlNSlpUKU/cF9o746WFEy9eNqLrqSyUgAAjB3gnD9UXdK23beA==", - "requires": { - "lodash": "4.17.4" - } + "buffer-factory": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/buffer-factory/-/buffer-factory-1.0.8.tgz", + "integrity": "sha512-EkUcaWsg7Vw+bfpGrpqzDIV4u3FksbHy0I0x9IZogqtCh9rZ5IHPTs/1QtZNNm/8BOeznUKTXIA72sVXEmFREQ==" }, "crypto-js": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz", "integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==" }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + "endianness": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/endianness/-/endianness-8.0.2.tgz", + "integrity": "sha512-IU+77+jJ7lpw2qZ3NUuqBZFy3GuioNgXUdsL1L9tooDNTaw0TgOnwNuc+8Ns+haDaTifK97QLzmOANJtI/rGvw==" }, "mime-db": { "version": "1.48.0", @@ -35,6 +32,20 @@ "mime-db": "1.48.0" } }, + "node-addon-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz", + "integrity": "sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg==" + }, + "node-crc16": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/node-crc16/-/node-crc16-2.0.7.tgz", + "integrity": "sha512-dbLudH39wvydMXsT5E/jdyEP0t/kO3EOFQawVeBk3cJP23+jL4feoCWF2kMThEvijrEt2isFx2XzYjLkf0h8+g==", + "requires": { + "buffer-factory": "1.0.8", + "node-addon-api": "3.0.0" + } + }, "strftime": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/strftime/-/strftime-0.10.0.tgz", diff --git a/hacktv_updsrv/package.json b/hacktv_updsrv/package.json index 70fdcb52..3be989a9 100644 --- a/hacktv_updsrv/package.json +++ b/hacktv_updsrv/package.json @@ -1,15 +1,16 @@ { "name": "hacktv_updsrv", - "version": "0.0.0", + "version": "0.6.1", "description": "hacktv_updsrv", "main": "app.js", "author": { "name": "" }, "dependencies": { - "arc4": "^3.4.0", "crypto-js": "^4.0.0", + "endianness": "^8.0.2", "mime-types": "^2.1.31", + "node-crc16": "^2.0.7", "strftime": "^0.10.0" } } diff --git a/hacktv_updsrv/services.json b/hacktv_updsrv/services.json new file mode 100644 index 00000000..e2b3db09 --- /dev/null +++ b/hacktv_updsrv/services.json @@ -0,0 +1,47 @@ +{ + "config": { + "service_ip": "192.168.11.8" + }, + "services": { + + "wtv-1800": { + "port": 1615, + "connections": 1 + }, + "wtv-star": { + "port": 1603, + "flags": "0x00000007" + }, + "wtv-head-waiter": { + "port": 1601, + "flags": "0x00000001", + "connections": 1 + }, + "wtv-update": { + "port": 1619, + "flags": "0x04", + "connections": 3 + }, + "wtv-log": { + "port": 1609, + "connections": 1 + }, + "wtv-home": { + "port": 1612, + "flags": "0x00000010" + }, + "wtv-tricks": { + "port": 1602, + "flags": "0x00000004" + }, + "wtv-flashrom": { + "port": 1618, + "flags": "0x00000040" + }, + "wtv-music": { + "port": 1656, + "flags": "0x04", + "connections": 3 + } + } +} diff --git a/hacktv_updsrv/wtvsec.js b/hacktv_updsrv/wtvsec.js index 9df6d79d..485b1b2e 100644 --- a/hacktv_updsrv/wtvsec.js +++ b/hacktv_updsrv/wtvsec.js @@ -1,60 +1,77 @@ const CryptoJS = require('crypto-js'); -const rc4 = require('arc4'); +const endianness = require('endianness'); +var crypto = require('crypto'); -class WTVNetworkSecurity { +class WTVSec { + //initial_shared_key = CryptoJS.lib.WordArray.random(8); + initial_shared_key_b64 = "CC5rWmRUE0o="; // You can change this but it doesn't mean much for security. Just make sure its static. 8 bytes base64 encoded. initial_shared_key = null; current_shared_key = null; challenge_key = null; + challenge_signed_key = null; + challenge_raw = null; challenge_response = null; - challenge_b64 = null; ticket_b64 = null; - incarnation = 1; + incarnation = 0; session_key1 = null; session_key2 = null; hRC4_Key1 = null; hRC4_Key2 = null; + RC4Session = new Array(); + zdebug = false; - constructor(wtv_initial_key = CryptoJS.lib.WordArray.random(8), wtv_incarnation = 1) { - var initial_key = wtv_initial_key; - + constructor(wtv_incarnation = 1) { this.zdebug = true; + this.initial_shared_key = CryptoJS.enc.Base64.parse(this.initial_shared_key_b64); - if (initial_key.sigBytes === 8) { + if (this.initial_shared_key.sigBytes === 8) { this.incarnation = wtv_incarnation; - this.initial_shared_key = initial_key; - this.current_shared_key = initial_key; + this.current_shared_key = this.initial_shared_key; } else { throw ("Invalid initial key length"); } } set_incarnation(wtv_incarnation) { - this.incarnation = wtv_incarnation; + if (this.incarnation != wtv_incarnation) { + this.incarnation = wtv_incarnation; + this.SecureOn(); + } } increment_incarnation() { - this.incarnation = this.incarnation + 1; + this.set_incarnation(parseInt(this.incarnation) + 1); + } + + DuplicateWordArray(wa) { + return CryptoJS.lib.WordArray.create(this.wordArrayToUint8Array(wa).buffer); } PrepareTicket() { // store last challenge response in ticket - var ticket_data = this.challenge_response; + var ticket_data = this.challenge_raw; try { var ticket_data_enc = CryptoJS.DES.encrypt(ticket_data, this.current_shared_key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); - this.ticket_b64 = this.current_shared_key.concat(ticket_data_enc.ciphertext.toString(CryptoJS.enc.Base64)); + // create a copy of WordArray since concat modifies the original + var current_shared_key = this.DuplicateWordArray(this.current_shared_key); + var challenge_signed_key = this.DuplicateWordArray(this.challenge_signed_key); + this.ticket_b64 = current_shared_key.concat(challenge_signed_key.concat(ticket_data_enc.ciphertext)).toString(CryptoJS.enc.Base64); } catch (e) { console.log("Error encrypting ticket: " + e.toString()); return null; } + return this.ticket_b64; } DecodeTicket(ticket_b64) { - var ticket_hex = CryptoJS.enc.Base64.parse(ticket_b64); - var ticket_key = CryptoJS.enc.Hex.parse(ticket_hex.substring(0, this.current_shared_key.sigBytes)); + var ticket_hex = CryptoJS.enc.Base64.parse(ticket_b64).toString(CryptoJS.enc.Hex); + var ticket_key = CryptoJS.enc.Hex.parse(ticket_hex.substring(0,16)); + var challenge_key = CryptoJS.enc.Hex.parse(ticket_hex.substring(16, 32)); + var challenge_enc = CryptoJS.enc.Hex.parse(ticket_hex.substring(32)); var ticket_dec = CryptoJS.DES.decrypt( { ciphertext: challenge_enc @@ -62,38 +79,39 @@ class WTVNetworkSecurity { ticket_key, { mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.ZeroPadding + padding: CryptoJS.pad.NoPadding } ); - this.ProcessChallenge(ticket_dec); + this.ProcessChallenge(ticket_dec.toString(CryptoJS.enc.Base64), challenge_key); + console.log(" * Decoded session from wtv-ticket"); } - ProcessChallenge(wtv_challenge) { + ProcessChallenge(wtv_challenge, key = this.current_shared_key) { var challenge_raw = CryptoJS.enc.Base64.parse(wtv_challenge); if (challenge_raw.sigBytes > 8) { var challenge_raw_hex = challenge_raw.toString(CryptoJS.enc.Hex); + var challenge_id_hex = challenge_raw_hex.substring(0, (8 * 2)); var challenge_enc_hex = challenge_raw_hex.substring((8*2)); var challenge_enc = CryptoJS.enc.Hex.parse(challenge_enc_hex); - - var challenge_decrypted = CryptoJS.DES.decrypt( { ciphertext: challenge_enc }, - this.current_shared_key, + key, { mode: CryptoJS.mode.ECB, - padding: CryptoJS.pad.ZeroPadding + padding: CryptoJS.pad.NoPadding } ); var challenge_dec_hex = challenge_decrypted.toString(CryptoJS.enc.Hex); var challenge_md5_challenge = CryptoJS.MD5(CryptoJS.enc.Hex.parse(challenge_dec_hex.substring(0, (80 * 2)))); - - if (challenge_dec_hex.substring((80 * 2), (96 * 2)) == challenge_md5_challenge.toString(CryptoJS.enc.Hex)) { + var test = challenge_dec_hex.substring((80 * 2), (96 * 2)); + var test2 = challenge_md5_challenge.toString(CryptoJS.enc.Hex); + if (test == test2) { this.current_shared_key = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((72*2), (80*2))); var challenge_echo = CryptoJS.enc.Hex.parse(challenge_dec_hex.substr(0, (40*2))); @@ -101,15 +119,15 @@ class WTVNetworkSecurity { this.session_key1 = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((40*2), (56*2))); this.session_key2 = CryptoJS.enc.Hex.parse(challenge_dec_hex.substring((56*2), (72*2))); - var echo_encrypted = CryptoJS.DES.encrypt(CryptoJS.MD5(challenge_echo).concat(challenge_echo), this.current_shared_key, { + var echo_encrypted = CryptoJS.DES.encrypt(CryptoJS.MD5(challenge_echo).concat(challenge_echo).concat(CryptoJS.enc.Utf8.parse("\x08".repeat(8))), this.current_shared_key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); // Last bytes is just extra padding - var challenge_response = CryptoJS.enc.Hex.parse(challenge_raw_hex.substr(0, (8 * 2))).concat(echo_encrypted.ciphertext.concat(CryptoJS.enc.Utf8.parse("\x00".repeat(8)))); - - + this.challenge_raw = challenge_raw; + this.challenge_key = this.current_shared_key; + var challenge_response = CryptoJS.enc.Hex.parse(challenge_raw_hex.substr(0, (8 * 2))).concat(echo_encrypted.ciphertext); return challenge_response; } else { throw ("Couldn't solve challenge"); @@ -133,16 +151,19 @@ class WTVNetworkSecurity { */ - var random_id_question_mark = CryptoJS.lib.WordArray.random(8); + var challenge_id = CryptoJS.lib.WordArray.random(8); var echo_me = CryptoJS.lib.WordArray.random(40); this.session_key1 = CryptoJS.lib.WordArray.random(16); this.session_key2 = CryptoJS.lib.WordArray.random(16); var new_shared_key = CryptoJS.lib.WordArray.random(8); - - var challenge_puzzle = echo_me.concat(this.session_key1.concat(this.session_key2.concat(new_shared_key))); - var challenge_secret = challenge_puzzle.concat(CryptoJS.MD5(challenge_puzzle).concat(CryptoJS.enc.Hex.parse("\x00".repeat(8)))); + var session_key1 = this.DuplicateWordArray(this.session_key1); + var session_key2 = this.DuplicateWordArray(this.session_key2); + + var challenge_puzzle = echo_me.concat(session_key1.concat(session_key2.concat(new_shared_key))); + var challenge_secret = challenge_puzzle.concat(CryptoJS.MD5(challenge_puzzle).concat(CryptoJS.enc.Hex.parse("\x08".repeat(8)))); + // Shhhh!! var challenge_secreted = CryptoJS.DES.encrypt(challenge_secret, this.current_shared_key, { mode: CryptoJS.mode.ECB, @@ -150,64 +171,119 @@ class WTVNetworkSecurity { }); - var challenge = random_id_question_mark.concat(challenge_secreted.ciphertext); + var challenge = challenge_id.concat(challenge_secreted.ciphertext); var challenge_b64 = challenge.toString(CryptoJS.enc.Base64); - // get the expected response for when client sends it + this.challenge_signed_key = this.current_shared_key; this.challenge_response = this.ProcessChallenge(challenge_b64); - this.challenge_key = this.current_shared_key; - this.challenge_b64 = challenge_b64; - - this.current_shared_key = new_shared_key; return challenge_b64; } - SecureOn() { - var buf = Buffer.allocUnsafe(4); - buf.writeUIntLE(this.incarnation, 0, 4); - var bigbuf = buf.readUIntBE(0, 4); - var md5_digest_key1 = CryptoJS.MD5(this.session_key1.concat(CryptoJS.lib.WordArray.create(bigbuf).concat(this.session_key1))); + wordToByteArray(word, length) { + var ba = [], + i, + xFF = 0xFF; + if (length > 0) + ba.push(word >>> 24); + if (length > 1) + ba.push((word >>> 16) & xFF); + if (length > 2) + ba.push((word >>> 8) & xFF); + if (length > 3) + ba.push(word & xFF); - buf = Buffer.allocUnsafe(4); - buf.writeUIntLE(this.incarnation, 0, 4); - bigbuf = buf.readUIntBE(0, 4); - var md5_digest_key2 = CryptoJS.MD5(this.session_key2.concat(CryptoJS.lib.WordArray.create(bigbuf).concat(this.session_key2))); - - - this.hRC4_Key1 = md5_digest_key1; - this.hRC4_Key2 = md5_digest_key2; + return ba; } - EncryptKey1(data) { - return this.Encrypt(this.hRC4_Key1, data); + wordArrayToUint8Array(wordArray, length = 0) { + if (wordArray.hasOwnProperty("sigBytes") && wordArray.hasOwnProperty("words")) { + length = wordArray.sigBytes; + wordArray = wordArray.words; + } + + var result = [], + bytes, + i = 0; + while (length > 0) { + bytes = this.wordToByteArray(wordArray[i], Math.min(4, length)); + length -= bytes.length; + result.push(bytes); + i++; + } + return new Uint8Array([].concat.apply([], result)); } - EncryptKey2(data) { - return this.Encrypt(this.hRC4_Key2, data); - } - Encrypt(context, data) { - if (key != null) { - return CryptoJS.RC4.encrypt(data, key); - } else { - throw ("Invalid RC4 encryption key"); + SecureOn(rc4session = null) { + if (this.zdebug) console.log(" # Generating RC4 sessions with wtv-incarnation: " + this.incarnation); + + var buf = new Uint8Array([0xff & this.incarnation, 0xff & (this.incarnation >> 8), 0xff & (this.incarnation >> 16), 0xff & (this.incarnation >> 24)]); + endianness(buf, 4); + this.hRC4_Key1 = CryptoJS.MD5(this.DuplicateWordArray(this.session_key1).concat(CryptoJS.lib.WordArray.create(buf).concat(this.DuplicateWordArray(this.session_key1)))); + this.hRC4_Key2 = CryptoJS.MD5(this.DuplicateWordArray(this.session_key2).concat(CryptoJS.lib.WordArray.create(buf).concat(this.DuplicateWordArray(this.session_key2)))); + switch (rc4session) { + case 0: + this.RC4Session[0] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)),''); + break; + case 1: + this.RC4Session[1] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)),''); + break; + case 2: + this.RC4Session[2] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)),''); + break; + case 3: + this.RC4Session[3] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)),''); + break; + default: + this.RC4Session[0] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)), ''); + this.RC4Session[1] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key1)), ''); + this.RC4Session[2] = crypto.createCipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)), ''); + this.RC4Session[3] = crypto.createDecipheriv('rc4', Buffer.from(this.wordArrayToUint8Array(this.hRC4_Key2)), ''); + break; } } - DecryptKey1(data) { - return this.Decrypt(this.hRC4_Key1, data); + + NewRC4Session(num) { + this.SecureOn(num); } - DecryptKey2(data) { - return this.Decrypt(this.hRC4_Key2, data); - } - - Decrypt(key, data) { - if (key != null) { - return CryptoJS.RC4.decrypt(data, key); - } else { - throw ("Invalid RC4 encryption key"); + Encrypt(keynum, data) { + var session_id; + switch (keynum) { + case 0: + session_id = 0; + break; + case 1: + session_id = 2 + break; + default: + throw ("Invalid key option (0 or 1 only)"); + break; } + if (!this.RC4Session[session_id]) { + this.NewRC4Session(session_id); + } + return this.RC4Session[session_id].update(Buffer.from(this.wordArrayToUint8Array(data))); + } + + Decrypt(keynum, data) { + var session_id; + switch (keynum) { + case 0: + session_id = 1; + break; + case 1: + session_id = 3; + break; + default: + throw ("Invalid key option (0 or 1 only)"); + break; + } + if (!this.RC4Session[session_id]) { + this.NewRC4Session(session_id); + } + return this.RC4Session[session_id].update(Buffer.from(this.wordArrayToUint8Array(data))); } Test() { @@ -221,4 +297,4 @@ class WTVNetworkSecurity { } } -module.exports = WTVNetworkSecurity; \ No newline at end of file +module.exports = WTVSec; \ No newline at end of file