added prettier properly

This commit is contained in:
QuiteAFancyEmerald 2024-08-08 17:25:45 -07:00
parent 995183d239
commit bdc83ba579
No known key found for this signature in database
GPG key ID: 2C9730062CD48870
45 changed files with 3796 additions and 3134 deletions

1
.prettierignore Normal file
View file

@ -0,0 +1 @@
/lib

221
README.md
View file

@ -1,4 +1,5 @@
<img align="left" width="70px" src="https://raw.githubusercontent.com/titaniumnetwork-dev/Holy-Unblocker/master/views/assets/img/icon.png"></img>
# Holy Unblocker LTS (v6.x.x)
Holy Unblocker LTS, an experimental web proxy service, can bypass web filters or 'blockers' regardless of whether the method of censorship is client-side or network-based. This includes the potential ability to bypass content blockers overseas, Chrome extensions, localized client firewalls, and network-related filters.
@ -9,6 +10,7 @@ Works with a large number of sites, including YouTube, Discord, and more!
Also has a good amount of locally hosted games featured on the site.
#### Supports
- Youtube.com
- Discord.com
- Google.com
@ -17,6 +19,7 @@ Also has a good amount of locally hosted games featured on the site.
- And more sites!
#### Features:
- Tab customization using the Options menu for improved stealth
- Considerable variety with the open selection of proxy types
- Game library with moderately decent titles
@ -44,23 +47,24 @@ Read below for information if the official site is blocked or for obtaining more
[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/new/template?template=https%3A%2F%2Fgithub.com%2FQuiteAFancyEmerald%2FHoly-Unblocker)
[![Deploy to Koyeb](https://www.koyeb.com/static/images/deploy/button.svg)](https://app.koyeb.com/deploy?type=git&repository=github.com/QuiteAFancyEmerald/Holy-Unblocker-Old&branch=master&name=HolyUnblocker&run_command=npm%start)
</details>
## Table of contents:
- [Setup](#how-to-setup)
- [Structure](#structure)
- [Structure Information](#structure-information)
- [Static Files](#details-of-views)
- [Scripts](#scripts-located-in-viewsassetsjs)
- [Future Additions](#future-additions)
- [Beginner's Explanation](#vauge-explanation-for-beginners-with-external-proxies-and-hosting)
- [Hosting Providers](#list-of-some-good-hosting-options)
- [Domain Setup](#freenomdomain-steps)
- [Cloudflare Setup](#cloudflare-steps)
- [Workspace Configurations](#workspace-configurations)
- [Detailed FAQ](#detailed-faq)
- [More Information](#more-information)
- [Structure](#structure)
- [Structure Information](#structure-information)
- [Static Files](#details-of-views)
- [Scripts](#scripts-located-in-viewsassetsjs)
- [Future Additions](#future-additions)
- [Beginner's Explanation](#vauge-explanation-for-beginners-with-external-proxies-and-hosting)
- [Hosting Providers](#list-of-some-good-hosting-options)
- [Domain Setup](#freenomdomain-steps)
- [Cloudflare Setup](#cloudflare-steps)
- [Workspace Configurations](#workspace-configurations)
- [Detailed FAQ](#detailed-faq)
- [More Information](#more-information)
## How to Setup
@ -81,8 +85,8 @@ The default place for the proxy when its started is `http://localhost:8080`, but
This website is hosted locally with Ultraviolet and Rammerhead built-in.
## Structure
<details><summary>Web Pages</summary>
- `index.html`: The homepage of the site.
@ -109,15 +113,18 @@ This website is hosted locally with Ultraviolet and Rammerhead built-in.
</details>
### Structure Information
- `/views/`: The physical site base of Holy Unblocker goes here where static assets are served.
- `/src/`: For future implementation of obfuscation and keyword removing features.
#### Details of `/views/`
- `/archive/` is used for game pages and vibeOS.
- `/pages/` is used for the HTML for the site.
- `/assets/` is used for storing various CSS, JS, image, and JSON files.
#### Scripts located in `/views/assets/js/`
- `bareTransport.js` is a locally installed version of the bare transport module which allows Ultraviolet to function.
- `card.js` adds a fancy visual effect to the box cards displayed on the welcome screen.
- `common.js` is used on all pages and allows commonly used features to function.
@ -126,109 +133,114 @@ This website is hosted locally with Ultraviolet and Rammerhead built-in.
- `register-sw.js` creates and manages service workers that allow Ultraviolet to function, and also uses bare transport.
## Future Additions
This will be our nonexhaustive todo list for Holy Unblocker LTS v6.x.x and above.
## Code Cleanup
- [ ] Remove all current obfuscation in the source code. It needs to be dynamically obfuscated if anything, or not obfuscated at all. This option will be a config option on the server side before rendering with Express for a performance focus. Meta elements will have an additonal attribute indicating if they should be moved. This is to ensure a SEO source can be served by config or a source focused on pure censorship evasion.
- [ ] Optimize the stylesheets and the HTML layout. Add more proper commenting and redivide the code so that it's less hard on the eyes.
- [ ] Optimize the JS. This time it won't be in one line and will be somewhat thoroughly commented.
- [ ] Restructure navigation scripts to ensure updated proxy functionality is sanitized and effective
- [x] Particles.js automatically adjusting per display size - done
- [x] Fix routes.mjs throwing with incorrect paths - done
- [x] Create test script - done
- [x] XSS and fingerprinting protection (may need updates) - done
- [x] Update games navigation JS and page/change to JSON object system - done
- [ ] Ensure all the original submodules get added back to HU-Archive
- [x] Mobile support - (welcome screen only, partial/needs work)
- [ ] SEO overhaul adapted from the v2 SEO Guide format
- [ ] Randomize the __uv$config global, and optionally randomize the UV prefix and URL encoding via cookies
- [ ] Remove all current obfuscation in the source code. It needs to be dynamically obfuscated if anything, or not obfuscated at all. This option will be a config option on the server side before rendering with Express for a performance focus. Meta elements will have an additonal attribute indicating if they should be moved. This is to ensure a SEO source can be served by config or a source focused on pure censorship evasion.
- [ ] Optimize the stylesheets and the HTML layout. Add more proper commenting and redivide the code so that it's less hard on the eyes.
- [ ] Optimize the JS. This time it won't be in one line and will be somewhat thoroughly commented.
- [ ] Restructure navigation scripts to ensure updated proxy functionality is sanitized and effective
- [x] Particles.js automatically adjusting per display size - done
- [x] Fix routes.mjs throwing with incorrect paths - done
- [x] Create test script - done
- [x] XSS and fingerprinting protection (may need updates) - done
- [x] Update games navigation JS and page/change to JSON object system - done
- [ ] Ensure all the original submodules get added back to HU-Archive
- [x] Mobile support - (welcome screen only, partial/needs work)
- [ ] SEO overhaul adapted from the v2 SEO Guide format
- [ ] Randomize the \_\_uv$config global, and optionally randomize the UV prefix and URL encoding via cookies
## Proxy/Site Functionality
- [x] Ensure Ultraviolet is updated to support bare-mux and wisp - done
- [x] Add Rammerhead support - done
- [x] Fix slow Ultraviolet speeds despite being local; something on the backend?? - done
- [x] Fix Ultraviolet on Firefox - (partial/needs work)
- [ ] Adapt Applications page to use either Rammerhead or UV (for Reddit, YouTube, Discord)
- [x] libcurl, epoxy and all that fun stuff - done
- [x] socks5/tor routing option that can be configured (enabled) via either a cookie or pathname as a settings meny option - done
- [ ] Update games page content
- [ ] Update settings menu again to make more room for more features
- [x] Update csel.js (after Setting menu redesign) to support custom transports, icon swap, routing - done
- [x] Update csel.js to support network based adblocking (partial/needs work)
- [ ] Add a "website self-destruct" button to the settings menu
- [ ] Flesh out and rework the UV / bare client error page
- [ ] Update sw.js to support workerware (https://github.com/MercuryWorkshop/workerware)
- [ ] Omnibox autoupdate script (for the Google/Bing style auto suggest feature)
- [ ] Games library will feature 10000 items; 5000 flash games and 5000 other game types
- [x] Ensure Ultraviolet is updated to support bare-mux and wisp - done
- [x] Add Rammerhead support - done
- [x] Fix slow Ultraviolet speeds despite being local; something on the backend?? - done
- [x] Fix Ultraviolet on Firefox - (partial/needs work)
- [ ] Adapt Applications page to use either Rammerhead or UV (for Reddit, YouTube, Discord)
- [x] libcurl, epoxy and all that fun stuff - done
- [x] socks5/tor routing option that can be configured (enabled) via either a cookie or pathname as a settings meny option - done
- [ ] Update games page content
- [ ] Update settings menu again to make more room for more features
- [x] Update csel.js (after Setting menu redesign) to support custom transports, icon swap, routing - done
- [x] Update csel.js to support network based adblocking (partial/needs work)
- [ ] Add a "website self-destruct" button to the settings menu
- [ ] Flesh out and rework the UV / bare client error page
- [ ] Update sw.js to support workerware (https://github.com/MercuryWorkshop/workerware)
- [ ] Omnibox autoupdate script (for the Google/Bing style auto suggest feature)
- [ ] Games library will feature 10000 items; 5000 flash games and 5000 other game types
## Site Redesign
- [x] Landing Cards - done
- [x] Change fonts to cleaner look
- [ ] Add more AOS interactions on scroll or hover
- [ ] Add subtle noise to background elements
- [ ] Update colors + add themes
- [ ] Toggle elements
- [ ] Other card options
- [ ] Radial blur elements
- [ ] Code standard examples
- [ ] Horizontal/general movement on scroll with AOS
- [ ] Showcase dev dependencies
- [ ] Update icons
- [x] Landing Page - (partial/needs work)
- [x] Settings Menu - (partial/needs work)
- [ ] More Dropdown Menu
- [ ] Web Proxies page
- [ ] Application page
- [ ] Hosting page
- [ ] Resources page
- [ ] Games Library page
- [ ] Emulators Library page
- [ ] Emu Library page
- [ ] Web Games page
- [ ] Flash Games page
- [ ] Documentation page
- [ ] FAQ page
- [ ] Credits page
- [ ] TOS page
- [x] Footer Design - (partial/needs work)
- [x] Header Design - (partial/needs work)
- [x] Landing Cards - done
- [x] Change fonts to cleaner look
- [ ] Add more AOS interactions on scroll or hover
- [ ] Add subtle noise to background elements
- [ ] Update colors + add themes
- [ ] Toggle elements
- [ ] Other card options
- [ ] Radial blur elements
- [ ] Code standard examples
- [ ] Horizontal/general movement on scroll with AOS
- [ ] Showcase dev dependencies
- [ ] Update icons
- [x] Landing Page - (partial/needs work)
- [x] Settings Menu - (partial/needs work)
- [ ] More Dropdown Menu
- [ ] Web Proxies page
- [ ] Application page
- [ ] Hosting page
- [ ] Resources page
- [ ] Games Library page
- [ ] Emulators Library page
- [ ] Emu Library page
- [ ] Web Games page
- [ ] Flash Games page
- [ ] Documentation page
- [ ] FAQ page
- [ ] Credits page
- [ ] TOS page
- [x] Footer Design - (partial/needs work)
- [x] Header Design - (partial/needs work)
## Community Requests
- [ ] Add [Quake WASM](https://github.com/GMH-Code/Quake-WASM)
- [ ] Celeste WASM
- [ ] Doom WASM
- [ ] Add [Quake WASM](https://github.com/GMH-Code/Quake-WASM)
- [ ] Celeste WASM
- [ ] Doom WASM
## Changelog
- Added wisp support
- Fixed AD config setting being opt-out; ads are not implemented in the project however
- Added Rammerhead support (locally)
- Drastically updated visuals across the service and refactored stylesheets
- Bumped games page functionality
- Updated randomization scripts to ES6 syntax and implemented the alternative to RegEx string replacement
- Helmet for express implemented into backend
- Improved component handling via templates.mjs along with deletion of obsolete files that previously handled this standard in a poor format
- Fixed oddly slow speeds with Ultraviolet (as well as a general version bump to support epoxy-tls and bare-mux)
- Implemented testing scripts for an improved GitHub actions workflow by doing a quick test on proxy + site functionality
- Greatly optimized client-side scripts across the site with a new standard, and generally reworked to no longer leave global variables
- Changes to server.mjs with path logic and error handling
- Updated standards for common scripts
- libcurl and bare-as-module support added
- Deleted 5 JS scripts and moved lots of data into JSON files. Big reorganization. Games menu core scripts now nested inside of common.js utilizing a JSON system
- Massive updates to the Settings menu visually and functionality wise; added Bare-Mux support for swapping transports to work with Ultraviolet, default icons and selective adblocking + Tor on any proxy instances
- CSS Has been partially restructured for mobile support, and is now properly arranged into clearly labeled sections (for the most part)
- Incorporated makeshift domain blacklisting functionality into Ultraviolet, currently used for blocking ads if ads are disabled in settings
- Fleshed out the SEO with more descriptions and better labeling
- Switched to Fastify for serving content from the backend; a separate Express backend file is kept in case it's still needed
- Rammerhead is now locally built into the HU LTS repository
- Simplified the HU LTS setup process and added more default npm commands
- Added wisp support
- Fixed AD config setting being opt-out; ads are not implemented in the project however
- Added Rammerhead support (locally)
- Drastically updated visuals across the service and refactored stylesheets
- Bumped games page functionality
- Updated randomization scripts to ES6 syntax and implemented the alternative to RegEx string replacement
- Helmet for express implemented into backend
- Improved component handling via templates.mjs along with deletion of obsolete files that previously handled this standard in a poor format
- Fixed oddly slow speeds with Ultraviolet (as well as a general version bump to support epoxy-tls and bare-mux)
- Implemented testing scripts for an improved GitHub actions workflow by doing a quick test on proxy + site functionality
- Greatly optimized client-side scripts across the site with a new standard, and generally reworked to no longer leave global variables
- Changes to server.mjs with path logic and error handling
- Updated standards for common scripts
- libcurl and bare-as-module support added
- Deleted 5 JS scripts and moved lots of data into JSON files. Big reorganization. Games menu core scripts now nested inside of common.js utilizing a JSON system
- Massive updates to the Settings menu visually and functionality wise; added Bare-Mux support for swapping transports to work with Ultraviolet, default icons and selective adblocking + Tor on any proxy instances
- CSS Has been partially restructured for mobile support, and is now properly arranged into clearly labeled sections (for the most part)
- Incorporated makeshift domain blacklisting functionality into Ultraviolet, currently used for blocking ads if ads are disabled in settings
- Fleshed out the SEO with more descriptions and better labeling
- Switched to Fastify for serving content from the backend; a separate Express backend file is kept in case it's still needed
- Rammerhead is now locally built into the HU LTS repository
- Simplified the HU LTS setup process and added more default npm commands
## Vague Explanation for Beginners With External Proxies and Hosting
You will first want to host your proxies locally or externally. OUTDATED
#### List of some good hosting options:
- <a href="#">Oracle Cloud</a> (Free, Paid, Dedicated)
- <a href="https://repl.it">Repl.it</a> (Free)
- <a href="https://azure.microsoft.com">Azure</a> (Free and Paid)
@ -248,13 +260,15 @@ This is an example of DNS records involving Heroku. Self-hosting will require `A
As stated previously, Holy Unblocker is hosted locally with Ultraviolet.
#### Freenom/Domain Steps
For beginners, Freenom is a good provider for obtaining domains for free. However, Freenom only provides their TLDs (`.cf`, `.ml`, `.gq`, `.ga`, and `.tk`) for free, which can be easily blocked.
- Get some Freenom domains then add them to your Heroku instance (Personal > [App Name] > Settings > Domains)
Add a domain for both `www.example.cf` and `example.cf` with .cf being interchangeable with other Freenom domain names.
Add a domain for both `www.example.cf` and `example.cf` with .cf being interchangeable with other Freenom domain names.
- If you prefer to obtain premium domains (TLDs) then use <a href="https://porkbun.com">Porkbun</a>, which offers domains for amazing prices. Literally a `.net` domain normally costs around $10. On Porkbun for the first year it costs $3 so its definitely a deal.
#### Cloudflare Steps
- Use Cloudflare (make an account), add your site (Freenom Domain or other) and then add your various DNS targets to Cloudflare. Make sure you add Cloudflare's Nameservers which will be given later when you are adding your site.
Make sure they are CNAME although A records also work and try to follow this structure:
@ -268,11 +282,10 @@ Make sure they are CNAME although A records also work and try to follow this str
`CNAME | a | your-womginx-instance-here.herokudns.com`
Make sure HTTPS is forced and have SSL set to Flexible for some services. Otherwise you can have SSL set to Full.
#### Workspace Configurations
Preferably if you have your own device use Visual Studio Code. Pretty much the best option you can get but obviously this is an opinion. Also make sure you have <a href="https://nodejs.org/">Node.JS</a> installed on your machine.
Not going to go too in depth with this part but first fork this repository. The clone it locally through a Terminal of some sort depending on what OS you are on. Make sure you navigate to the folder you want to set this up in.
@ -294,16 +307,19 @@ node_modules
Now you have your following workspace environment setup. To deploy the following workspace you just created you will need to look up depending on your hosting provider.
For an online IDE that you can use on your school computer and/or chromebook use GitPod. Basically the equivalent of Visual Studio Code but with in-browser support.
- Make an account: `https://gitpod.io/`
- Fork this repo and enter in this URL to setup your workspace: `https://gitpod.io#https://github.com/YourNameHere/Holy-Unblocker/`
Use the same steps above by running `npm install` in your repository and adding a `.gitignore` in your root directory specifying to exclude `node_modules`.
## Detailed FAQ
<details>
<summary>Quick FAQ</summary>
#### Where can I find the games for this repo? (404 errors, etc.)
Due to piracy concerns, size, etc. this has been moved over <a href="https://github.com/QuiteAFancyEmerald/HU-Archive">here</a>. EmuLibrary is not featured in the public version.
**Why is the site I am on not working correctly or having CAPTCHA errors?**
@ -319,6 +335,7 @@ If you still have any questions feel free to ask them in the discord linked here
</details>
### Why are official domains now numbered? Is this project maintained again?
Yes, this project is active again for LTS support! However, the approach is now much simpler to ensure functionality: traffic will be focused on a single domain. More than ever, this project serves as a proof of concept for the brave souls willing to innovate in the web proxy service space.
<details><summary>Former Closing Message (Original - 2022)</summary>
@ -338,8 +355,8 @@ Emerald :HuTaoHype:
</details>
## More Information
This project is maintained by the Holy Unblocker LTS team and is an official flagship Titanium Network web proxy site.
- <a href="https://github.com/titaniumnetwork-dev/">https://github.com/titaniumnetwork-dev/</a>
@ -348,6 +365,7 @@ This project is maintained by the Holy Unblocker LTS team and is an official fla
View the official website for more detail and credits.
### Web Proxy Sources:
This project currently uses Ultraviolet, Wisp, Womginx, and Rammerhead, linked below.
- <a href="https://github.com/titaniumnetwork-dev/Ultraviolet">Ultraviolet</a>
@ -357,7 +375,6 @@ This project currently uses Ultraviolet, Wisp, Womginx, and Rammerhead, linked b
- <a href="https://github.com/MercuryWorkshop/bare-mux">Bare-Mux</a>
- <a href="https://github.com/tomphttp/bare-server-node">TOMP Bare Server</a>
### Other Dependencies:
- <a href="https://github.com/tsparticles/tsparticles">tsparticles</a>

170
TODO.md
View file

@ -2,97 +2,99 @@ This will be our nonexhaustive todo list for Holy Unblocker LTS v6.x.x and above
## Code Cleanup
- [ ] Remove all current obfuscation in the source code. It needs to be dynamically obfuscated if anything, or not obfuscated at all. This option will be a config option on the server side before rendering with Express for a performance focus. Meta elements will have an additonal attribute indicating if they should be moved. This is to ensure a SEO source can be served by config or a source focused on pure censorship evasion.
- [ ] Optimize the stylesheets and the HTML layout. Add more proper commenting and redivide the code so that it's less hard on the eyes.
- [ ] Optimize the JS. This time it won't be in one line and will be somewhat thoroughly commented.
- [ ] Restructure navigation scripts to ensure updated proxy functionality is sanitized and effective
- [x] Particles.js automatically adjusting per display size - done
- [x] Fix routes.mjs throwing with incorrect paths - done
- [x] Create test script - done
- [x] XSS and fingerprinting protection (may need updates) - done
- [x] Update games navigation JS and page/change to JSON object system - done
- [ ] Ensure all the original submodules get added back to HU-Archive
- [x] Mobile support - (welcome screen only, partial/needs work)
- [ ] SEO overhaul adapted from the v2 SEO Guide format
- [ ] Randomize the __uv$config global, and optionally randomize the UV prefix and URL encoding via cookies
- [ ] Remove all current obfuscation in the source code. It needs to be dynamically obfuscated if anything, or not obfuscated at all. This option will be a config option on the server side before rendering with Express for a performance focus. Meta elements will have an additonal attribute indicating if they should be moved. This is to ensure a SEO source can be served by config or a source focused on pure censorship evasion.
- [ ] Optimize the stylesheets and the HTML layout. Add more proper commenting and redivide the code so that it's less hard on the eyes.
- [ ] Optimize the JS. This time it won't be in one line and will be somewhat thoroughly commented.
- [ ] Restructure navigation scripts to ensure updated proxy functionality is sanitized and effective
- [x] Particles.js automatically adjusting per display size - done
- [x] Fix routes.mjs throwing with incorrect paths - done
- [x] Create test script - done
- [x] XSS and fingerprinting protection (may need updates) - done
- [x] Update games navigation JS and page/change to JSON object system - done
- [ ] Ensure all the original submodules get added back to HU-Archive
- [x] Mobile support - (welcome screen only, partial/needs work)
- [ ] SEO overhaul adapted from the v2 SEO Guide format
- [ ] Randomize the \_\_uv$config global, and optionally randomize the UV prefix and URL encoding via cookies
## Proxy/Site Functionality
- [x] Ensure Ultraviolet is updated to support bare-mux and wisp - done
- [x] Add Rammerhead support - done
- [x] Fix slow Ultraviolet speeds despite being local; something on the backend?? - done
- [x] Fix Ultraviolet on Firefox - (partial/needs work)
- [ ] Adapt Applications page to use either Rammerhead or UV (for Reddit, YouTube, Discord)
- [x] libcurl, epoxy and all that fun stuff - done
- [x] socks5/tor routing option that can be configured (enabled) via either a cookie or pathname as a settings meny option - done
- [ ] Update games page content
- [ ] Update settings menu again to make more room for more features
- [x] Update csel.js (after Setting menu redesign) to support custom transports, icon swap, routing - done
- [x] Update csel.js to support network based adblocking (partial/needs work)
- [ ] Add a "website self-destruct" button to the settings menu
- [ ] Flesh out and rework the UV / bare client error page
- [ ] Update sw.js to support workerware (https://github.com/MercuryWorkshop/workerware)
- [ ] Omnibox autoupdate script (for the Google/Bing style auto suggest feature)
- [ ] Games library will feature 10000 items; 5000 flash games and 5000 other game types
- [x] Ensure Ultraviolet is updated to support bare-mux and wisp - done
- [x] Add Rammerhead support - done
- [x] Fix slow Ultraviolet speeds despite being local; something on the backend?? - done
- [x] Fix Ultraviolet on Firefox - (partial/needs work)
- [ ] Adapt Applications page to use either Rammerhead or UV (for Reddit, YouTube, Discord)
- [x] libcurl, epoxy and all that fun stuff - done
- [x] socks5/tor routing option that can be configured (enabled) via either a cookie or pathname as a settings meny option - done
- [ ] Update games page content
- [ ] Update settings menu again to make more room for more features
- [x] Update csel.js (after Setting menu redesign) to support custom transports, icon swap, routing - done
- [x] Update csel.js to support network based adblocking (partial/needs work)
- [ ] Add a "website self-destruct" button to the settings menu
- [ ] Flesh out and rework the UV / bare client error page
- [ ] Update sw.js to support workerware (https://github.com/MercuryWorkshop/workerware)
- [ ] Omnibox autoupdate script (for the Google/Bing style auto suggest feature)
- [ ] Games library will feature 10000 items; 5000 flash games and 5000 other game types
## Site Redesign
- [x] Landing Cards - done
- [x] Change fonts to cleaner look
- [ ] Add more AOS interactions on scroll or hover
- [ ] Add subtle noise to background elements
- [ ] Update colors + add themes
- [ ] Toggle elements
- [ ] Other card options
- [ ] Radial blur elements
- [ ] Code standard examples
- [ ] Horizontal/general movement on scroll with AOS
- [ ] Showcase dev dependencies
- [ ] Update icons
- [x] Landing Page - (partial/needs work)
- [x] Settings Menu - (partial/needs work)
- [ ] More Dropdown Menu
- [ ] Web Proxies page
- [ ] Application page
- [ ] Hosting page
- [ ] Resources page
- [ ] Games Library page
- [ ] Emulators Library page
- [ ] Emu Library page
- [ ] Web Games page
- [ ] Flash Games page
- [ ] Documentation page
- [ ] FAQ page
- [ ] Credits page
- [ ] TOS page
- [x] Footer Design - (partial/needs work)
- [x] Header Design - (partial/needs work)
- [x] Landing Cards - done
- [x] Change fonts to cleaner look
- [ ] Add more AOS interactions on scroll or hover
- [ ] Add subtle noise to background elements
- [ ] Update colors + add themes
- [ ] Toggle elements
- [ ] Other card options
- [ ] Radial blur elements
- [ ] Code standard examples
- [ ] Horizontal/general movement on scroll with AOS
- [ ] Showcase dev dependencies
- [ ] Update icons
- [x] Landing Page - (partial/needs work)
- [x] Settings Menu - (partial/needs work)
- [ ] More Dropdown Menu
- [ ] Web Proxies page
- [ ] Application page
- [ ] Hosting page
- [ ] Resources page
- [ ] Games Library page
- [ ] Emulators Library page
- [ ] Emu Library page
- [ ] Web Games page
- [ ] Flash Games page
- [ ] Documentation page
- [ ] FAQ page
- [ ] Credits page
- [ ] TOS page
- [x] Footer Design - (partial/needs work)
- [x] Header Design - (partial/needs work)
## Community Requests
- [ ] Add [Quake WASM](https://github.com/GMH-Code/Quake-WASM)
- [ ] Celeste WASM
- [ ] Doom WASM
- [ ] Add [Quake WASM](https://github.com/GMH-Code/Quake-WASM)
- [ ] Celeste WASM
- [ ] Doom WASM
## Changelog
- Added wisp support
- Fixed AD config setting being opt-out; ads are not implemented in the project however
- Added Rammerhead support (locally)
- Drastically updated visuals across the service and refactored stylesheets
- Bumped games page functionality
- Updated randomization scripts to ES6 syntax and implemented the alternative to RegEx string replacement
- Helmet for express implemented into backend
- Improved component handling via templates.mjs along with deletion of obsolete files that previously handled this standard in a poor format
- Fixed oddly slow speeds with Ultraviolet (as well as a general version bump to support epoxy-tls and bare-mux)
- Implemented testing scripts for an improved GitHub actions workflow by doing a quick test on proxy + site functionality
- Greatly optimized client-side scripts across the site with a new standard, and generally reworked to no longer leave global variables
- Changes to server.mjs with path logic and error handling
- Updated standards for common scripts
- libcurl and bare-as-module support added
- Deleted 5 JS scripts and moved lots of data into JSON files. Big reorganization. Games menu core scripts now nested inside of common.js utilizing a JSON system
- Massive updates to the Settings menu visually and functionality wise; added Bare-Mux support for swapping transports to work with Ultraviolet, default icons and selective adblocking + Tor on any proxy instances
- CSS Has been partially restructured for mobile support, and is now properly arranged into clearly labeled sections (for the most part)
- Incorporated makeshift domain blacklisting functionality into Ultraviolet, currently used for blocking ads if ads are disabled in settings
- Fleshed out the SEO with more descriptions and better labeling
- Switched to Fastify for serving content from the backend; a separate Express backend file is kept in case it's still needed
- Rammerhead is now locally built into the HU LTS repository
- Simplified the HU LTS setup process and added more default npm commands
- Added wisp support
- Fixed AD config setting being opt-out; ads are not implemented in the project however
- Added Rammerhead support (locally)
- Drastically updated visuals across the service and refactored stylesheets
- Bumped games page functionality
- Updated randomization scripts to ES6 syntax and implemented the alternative to RegEx string replacement
- Helmet for express implemented into backend
- Improved component handling via templates.mjs along with deletion of obsolete files that previously handled this standard in a poor format
- Fixed oddly slow speeds with Ultraviolet (as well as a general version bump to support epoxy-tls and bare-mux)
- Implemented testing scripts for an improved GitHub actions workflow by doing a quick test on proxy + site functionality
- Greatly optimized client-side scripts across the site with a new standard, and generally reworked to no longer leave global variables
- Changes to server.mjs with path logic and error handling
- Updated standards for common scripts
- libcurl and bare-as-module support added
- Deleted 5 JS scripts and moved lots of data into JSON files. Big reorganization. Games menu core scripts now nested inside of common.js utilizing a JSON system
- Massive updates to the Settings menu visually and functionality wise; added Bare-Mux support for swapping transports to work with Ultraviolet, default icons and selective adblocking + Tor on any proxy instances
- CSS Has been partially restructured for mobile support, and is now properly arranged into clearly labeled sections (for the most part)
- Incorporated makeshift domain blacklisting functionality into Ultraviolet, currently used for blocking ads if ads are disabled in settings
- Fleshed out the SEO with more descriptions and better labeling
- Switched to Fastify for serving content from the backend; a separate Express backend file is kept in case it's still needed
- Rammerhead is now locally built into the HU LTS repository
- Simplified the HU LTS setup process and added more default npm commands

View file

@ -1,3 +1,3 @@
(async () => {
await import("./src/server.mjs");
await import('./src/server.mjs');
})();

View file

@ -1,22 +1,22 @@
module.exports = {
apps: [
{
name: "HolyUB",
script: "./backend.js",
name: 'HolyUB',
script: './backend.js',
env: {
PORT: 8080,
NODE_ENV: "development",
NODE_ENV: 'development',
},
env_production: {
PORT: 8080,
NODE_ENV: "production",
NODE_ENV: 'production',
},
instances: "1",
exec_interpreter: "babel-node",
exec_mode: "fork",
instances: '1',
exec_interpreter: 'babel-node',
exec_mode: 'fork',
autorestart: true,
exp_backoff_restart_delay: 100,
cron_restart: "*/10 * * * *",
cron_restart: '*/10 * * * *',
kill_timeout: 3000,
watch: false,
},

16
prettier.config.js Normal file
View file

@ -0,0 +1,16 @@
module.exports = {
printWidth: 80, // Wrap lines at 80 characters
tabWidth: 2, // Use 2 spaces per indentation level
useTabs: false, // Use spaces instead of tabs
semi: true, // Add a semicolon at the end of every statement
singleQuote: true, // Use single quotes instead of double quotes
quoteProps: 'as-needed', // Only add quotes around object properties where required
jsxSingleQuote: false, // Use double quotes in JSX
trailingComma: 'es5', // Add trailing commas where valid in ES5 (objects, arrays, etc.)
bracketSpacing: true, // Print spaces between brackets in object literals
jsxBracketSameLine: false, // Put the `>` of a multi-line JSX element at the end of the last line
arrowParens: 'always', // Always include parentheses around arrow function arguments
htmlWhitespaceSensitivity: 'css', // Respect the default value of CSS display property
endOfLine: 'lf', // Use line feed only (\n) for newlines
embeddedLanguageFormatting: 'auto', // Format embedded code if Prettier can automatically identify it
};

View file

@ -1,10 +1,10 @@
// This file is solely used for the automatically run GitHub job, which checks to
// see if all HU LTS code is working properly (at least on an Ubuntu machine).
const axios = require("axios");
const puppeteer = require("puppeteer");
const axios = require('axios');
const puppeteer = require('puppeteer');
const testEndpoint = async url => {
const testEndpoint = async (url) => {
try {
const response = await axios.get(url);
return response.status === 200;
@ -29,58 +29,58 @@ const testGeneratedUrl = async (url, headers) => {
const testServerResponse = async () => {
const endpoints = [
"http://localhost:8080/",
"http://localhost:8080/test-404",
"http://localhost:8080/browsing",
"http://localhost:8080/rammerhead",
"http://localhost:8080/ultraviolet",
"http://localhost:8080/documentation",
"http://localhost:8080/questions",
"http://localhost:8080/s",
"http://localhost:8080/credits",
"http://localhost:8080/bookmarklets",
"http://localhost:8080/terms",
"http://localhost:8080/games",
"http://localhost:8080/web-games",
"http://localhost:8080/emulators",
"http://localhost:8080/flash-games",
"http://localhost:8080/retro-games",
"http://localhost:8080/youtube",
"http://localhost:8080/apps",
"http://localhost:8080/flash",
"http://localhost:8080/webretro",
"http://localhost:8080/vibe-os",
"http://localhost:8080/assets/js/particlesjs/particles.js",
"http://localhost:8080/assets/js/bareTransport.js",
"http://localhost:8080/assets/js/card.js",
"http://localhost:8080/assets/js/common-16451543478.js",
"http://localhost:8080/assets/js/csel.js",
"http://localhost:8080/assets/js/register-sw.js",
"http://localhost:8080/assets/json/emu-nav.json",
"http://localhost:8080/assets/json/blacklist.json",
"http://localhost:8080/assets/json/emulib-nav.json",
"http://localhost:8080/assets/json/flash-nav.json",
"http://localhost:8080/assets/json/h5-nav.json",
"http://localhost:8080/assets/json/links.json",
"http://localhost:8080/baremux/index.js",
"http://localhost:8080/baremux/worker.js",
"http://localhost:8080/epoxy/index.mjs",
"http://localhost:8080/uv/uv.bundle.js",
"http://localhost:8080/uv/sw.js",
"http://localhost:8080/uv/uv.config.js",
"http://localhost:8080/uv/workerware.js",
"http://localhost:8080/uv/WWError.js"
'http://localhost:8080/',
'http://localhost:8080/test-404',
'http://localhost:8080/browsing',
'http://localhost:8080/rammerhead',
'http://localhost:8080/ultraviolet',
'http://localhost:8080/documentation',
'http://localhost:8080/questions',
'http://localhost:8080/s',
'http://localhost:8080/credits',
'http://localhost:8080/bookmarklets',
'http://localhost:8080/terms',
'http://localhost:8080/games',
'http://localhost:8080/web-games',
'http://localhost:8080/emulators',
'http://localhost:8080/flash-games',
'http://localhost:8080/retro-games',
'http://localhost:8080/youtube',
'http://localhost:8080/apps',
'http://localhost:8080/flash',
'http://localhost:8080/webretro',
'http://localhost:8080/vibe-os',
'http://localhost:8080/assets/js/particlesjs/particles.js',
'http://localhost:8080/assets/js/bareTransport.js',
'http://localhost:8080/assets/js/card.js',
'http://localhost:8080/assets/js/common-16451543478.js',
'http://localhost:8080/assets/js/csel.js',
'http://localhost:8080/assets/js/register-sw.js',
'http://localhost:8080/assets/json/emu-nav.json',
'http://localhost:8080/assets/json/blacklist.json',
'http://localhost:8080/assets/json/emulib-nav.json',
'http://localhost:8080/assets/json/flash-nav.json',
'http://localhost:8080/assets/json/h5-nav.json',
'http://localhost:8080/assets/json/links.json',
'http://localhost:8080/baremux/index.js',
'http://localhost:8080/baremux/worker.js',
'http://localhost:8080/epoxy/index.mjs',
'http://localhost:8080/uv/uv.bundle.js',
'http://localhost:8080/uv/sw.js',
'http://localhost:8080/uv/uv.config.js',
'http://localhost:8080/uv/workerware.js',
'http://localhost:8080/uv/WWError.js',
];
const results = await Promise.all(endpoints.map(testEndpoint));
const allPassed = results.every((result) => result);
if (allPassed) {
console.log("All endpoints responded with status code 200. Test passed.");
console.log('All endpoints responded with status code 200. Test passed.');
await testCommonJSOnPage();
} else {
console.error(
"One or more endpoints failed to respond with status code 200. Test failed."
'One or more endpoints failed to respond with status code 200. Test failed.'
);
process.exitCode = 1;
}
@ -89,9 +89,9 @@ const testServerResponse = async () => {
const testCommonJSOnPage = async () => {
const browser = await puppeteer.launch({
args: [
"--enable-features=NetworkService",
"--enable-features=ServiceWorker",
"--enable-features=InsecureOrigins",
'--enable-features=NetworkService',
'--enable-features=ServiceWorker',
'--enable-features=InsecureOrigins',
],
headless: true,
ignoreHTTPSErrors: true,
@ -102,73 +102,75 @@ const testCommonJSOnPage = async () => {
const getHeaders = async () => {
const headers = {};
headers["User-Agent"] = await page.evaluate(() => navigator.userAgent);
headers["Referer"] = await page.evaluate(() => window.location.href);
headers['User-Agent'] = await page.evaluate(() => navigator.userAgent);
headers['Referer'] = await page.evaluate(() => window.location.href);
return headers;
};
const testRammerhead = async () => {
await page.goto("http://localhost:8080/rammerhead");
await page.goto('http://localhost:8080/rammerhead');
const testResults = await page.evaluate(async () => {
const results = {};
await new Promise((resolve) => {
if (document.readyState === "complete") {
if (document.readyState === 'complete') {
resolve();
} else {
window.addEventListener("load", resolve);
window.addEventListener('load', resolve);
}
});
// Locate the omnibox element on the Rammerhead page.
let omnibox = document.getElementById("pr-rh");
omnibox = omnibox && omnibox.querySelector("input[type=text]");
// Locate the omnibox element on the Rammerhead page.
let omnibox = document.getElementById('pr-rh');
omnibox = omnibox && omnibox.querySelector('input[type=text]');
if (omnibox) {
try {
// Send an artificial input to the omnibox. The omnibox will create
// a proxy URL and leave it as the input value in response.
const urlPath = "example.com";
// Send an artificial input to the omnibox. The omnibox will create
// a proxy URL and leave it as the input value in response.
const urlPath = 'example.com';
omnibox.value = urlPath;
await omnibox.dispatchEvent(
new KeyboardEvent("keydown", {code: "Validator Test"})
new KeyboardEvent('keydown', { code: 'Validator Test' })
);
// Wait up to 5 seconds for the omnibox to finish updating.
const loadUrl = new Promise(resolve => {
if (omnibox.value !== urlPath) resolve(omnibox.value);
else omnibox.addEventListener("change", () => resolve(omnibox.value));
}),
timeout = new Promise(resolve => {
setTimeout(() => resolve(omnibox.value), 40000);
}),
// Record the proxy URL that the omnibox left here.
rammerheadUrl = await Promise.race([loadUrl, timeout]);
console.log("Generated Rammerhead URL:", rammerheadUrl);
results.rammerhead = rammerheadUrl ? rammerheadUrl : "failure";
// Wait up to 5 seconds for the omnibox to finish updating.
const loadUrl = new Promise((resolve) => {
if (omnibox.value !== urlPath) resolve(omnibox.value);
else
omnibox.addEventListener('change', () =>
resolve(omnibox.value)
);
}),
timeout = new Promise((resolve) => {
setTimeout(() => resolve(omnibox.value), 40000);
}),
// Record the proxy URL that the omnibox left here.
rammerheadUrl = await Promise.race([loadUrl, timeout]);
console.log('Generated Rammerhead URL:', rammerheadUrl);
results.rammerhead = rammerheadUrl ? rammerheadUrl : 'failure';
} catch (e) {
results.rammerhead = "failure: " + e.message;
results.rammerhead = 'failure: ' + e.message;
}
} else {
results.goProx = "not defined";
results.goProx = 'not defined';
}
return results;
});
console.log("Rammerhead test results:", testResults);
console.log('Rammerhead test results:', testResults);
const headers = await getHeaders();
const rammerheadTestPassed =
testResults.rammerhead !== "failure" &&
testResults.rammerhead !== 'failure' &&
(await testGeneratedUrl(testResults.rammerhead, headers));
console.log(
`Rammerhead test result: ${
rammerheadTestPassed ? "success" : "failure"
rammerheadTestPassed ? 'success' : 'failure'
}`
);
@ -211,90 +213,96 @@ xx xx
*/
const testUltraviolet = async () => {
await page.goto("http://localhost:8080/ultraviolet");
await page.goto('http://localhost:8080/ultraviolet');
const testResults = await page.evaluate(async () => {
const results = [{}, {}];
await new Promise((resolve) => {
const waitForDocument = () =>
document.readyState === 'complete'
? resolve()
: window.addEventListener('load', resolve);
const waitForDocument = () => document.readyState === "complete"
? resolve()
: window.addEventListener("load", resolve);
// Wait until a service worker is registered before continuing.
// Also make sure the document is loaded.
const waitForWorker = async () => setTimeout(async () => {
(await navigator.serviceWorker.getRegistrations()).length >= 1
? waitForDocument()
: waitForWorker()
}, 1000);
// Wait until a service worker is registered before continuing.
// Also make sure the document is loaded.
const waitForWorker = async () =>
setTimeout(async () => {
(await navigator.serviceWorker.getRegistrations()).length >= 1
? waitForDocument()
: waitForWorker();
}, 1000);
waitForWorker();
});
// Locate the omnibox element on the Ultraviolet page.
let omnibox = document.getElementById("pr-uv");
omnibox = omnibox && omnibox.querySelector("input[type=text]");
// Locate the omnibox element on the Ultraviolet page.
let omnibox = document.getElementById('pr-uv');
omnibox = omnibox && omnibox.querySelector('input[type=text]');
if (omnibox) {
// For the hacky URL test, use the URL page's EXACT title.
// For the hacky URL test, use the URL page's EXACT title.
const website = {
path: "example.com",
title: "Example Domain"
path: 'example.com',
title: 'Example Domain',
};
try {
// Send an artificial input to the omnibox. The omnibox will create
// a proxy URL and leave it as the input value in response.
// Send an artificial input to the omnibox. The omnibox will create
// a proxy URL and leave it as the input value in response.
omnibox.value = website.path;
await omnibox.dispatchEvent(
new KeyboardEvent("keydown", {code: "Validator Test"})
new KeyboardEvent('keydown', { code: 'Validator Test' })
);
// Record the proxy URL that the omnibox left here.
// Record the proxy URL that the omnibox left here.
const generatedUrl = omnibox.value;
console.log("Generated Ultraviolet URL:", generatedUrl);
results[0].ultraviolet = generatedUrl ? generatedUrl : "failure";
console.log('Generated Ultraviolet URL:', generatedUrl);
results[0].ultraviolet = generatedUrl ? generatedUrl : 'failure';
// Test to see if the document title for example.com has loaded,
// by appending an IFrame to the document and grabbing its content.
// Test to see if the document title for example.com has loaded,
// by appending an IFrame to the document and grabbing its content.
const testGeneratedUrlHacky = async (url) => {
let result = false;
const exampleIFrame = document.createElement("iframe");
const waitForDocument = new Promise(resolve => {
const exampleIFrame = document.createElement('iframe');
const waitForDocument = new Promise((resolve) => {
document.documentElement.appendChild(exampleIFrame);
exampleIFrame.addEventListener("load", () => {
result = exampleIFrame.contentWindow.document.title === website.title;
exampleIFrame.addEventListener('load', () => {
result =
exampleIFrame.contentWindow.document.title ===
website.title;
resolve();
});
});
exampleIFrame.src = url;
exampleIFrame.style.display = "none";
exampleIFrame.style.display = 'none';
await waitForDocument;
return result;
};
results[1].uvTestPassed = await testGeneratedUrlHacky(results[0].ultraviolet);
results[1].uvTestPassed = await testGeneratedUrlHacky(
results[0].ultraviolet
);
} catch (e) {
results[0].ultraviolet = "failure: " + e.message;
results[0].ultraviolet = 'failure: ' + e.message;
}
} else {
results[0].goProx = "not defined";
results[0].goProx = 'not defined';
}
return results;
});
console.log("Ultraviolet test results:", testResults[0]);
console.log('Ultraviolet test results:', testResults[0]);
if (testResults[0].ultraviolet && testResults[0].ultraviolet !== "failure") {
if (
testResults[0].ultraviolet &&
testResults[0].ultraviolet !== 'failure'
) {
const uvTestPassed = testResults[1].uvTestPassed;
console.log(
`Ultraviolet test result: ${uvTestPassed ? "success" : "failure"}`
`Ultraviolet test result: ${uvTestPassed ? 'success' : 'failure'}`
);
return uvTestPassed;
} else {
@ -308,14 +316,14 @@ xx xx
const ultravioletPassed = await testUltraviolet();
if (rammerheadPassed && ultravioletPassed) {
console.log("Both tests passed.");
console.log('Both tests passed.');
process.exitCode = 0;
} else {
console.error("Tests failed.");
console.error('Tests failed.');
process.exitCode = 1;
}
} catch (error) {
console.error("Error in testCommonJSOnPage:", error.message);
console.error('Error in testCommonJSOnPage:', error.message);
process.exitCode = 1;
} finally {
await browser.close();

View file

@ -7,129 +7,136 @@ import ecosystem from './ecosystem.config.js';
// Some necessary constants are copied over from /src/server.mjs.
const config = Object.freeze(
JSON.parse(await readFile(new URL("./src/config.json", import.meta.url)))
JSON.parse(await readFile(new URL('./src/config.json', import.meta.url)))
),
ecosystemConfig = Object.freeze(
ecosystem.apps.find(app => app.name === "HolyUB") || ecosystem.apps[0]
ecosystem.apps.find((app) => app.name === 'HolyUB') || ecosystem.apps[0]
);
const serverUrl = (base => {
const serverUrl = ((base) => {
try {
base = new URL(config.host);
} catch (e) {
base = new URL("http://a");
base = new URL('http://a');
base.host = config.host;
}
base.port = ecosystemConfig[ config.production ? "env_production" : "env" ].PORT;
base.port =
ecosystemConfig[config.production ? 'env_production' : 'env'].PORT;
return Object.freeze(base);
})();
const shutdown = fileURLToPath(new URL("./src/.shutdown", import.meta.url));
const shutdown = fileURLToPath(new URL('./src/.shutdown', import.meta.url));
// Run each command line argument passed after node run-command.mjs.
// Commands are defined in the switch case statement below.
for (let i = 2; i < process.argv.length; i++)
switch (process.argv[i]) {
// Commmand to boot up the server. Use PM2 to run if production is true in the
// config file.
case "start":
// Commmand to boot up the server. Use PM2 to run if production is true in the
// config file.
case 'start':
if (config.production)
exec("npx pm2 start ecosystem.config.js --env production",
exec(
'npx pm2 start ecosystem.config.js --env production',
(error, stdout) => {
if (error) throw error;
console.log(stdout);
}
);
// Handle setup on Windows differently from platforms with POSIX-compliant shells.
// This should run the server as a background process.
else if (process.platform === "win32")
// Handle setup on Windows differently from platforms with POSIX-compliant shells.
// This should run the server as a background process.
else if (process.platform === 'win32')
exec('START /MIN "" node backend.js', (error, stdout) => {
if (error) throw error;
console.log(stdout);
});
// The following approach (and similar approaches) will not work on Windows,
// because exiting this program will also terminate backend.js on Windows.
// The following approach (and similar approaches) will not work on Windows,
// because exiting this program will also terminate backend.js on Windows.
else {
const server = fork(
fileURLToPath(new URL("./backend.js", import.meta.url)),
{detached: true}
fileURLToPath(new URL('./backend.js', import.meta.url)),
{ detached: true }
);
server.unref();
server.disconnect();
}
break;
// Stop the server. Make a temporary file that the server will check for if told
// to shut down. This is done by sending a GET request to the server.
case "stop": {
await writeFile(shutdown, "");
// Stop the server. Make a temporary file that the server will check for if told
// to shut down. This is done by sending a GET request to the server.
case 'stop': {
await writeFile(shutdown, '');
let timeoutId = undefined;
try {
// Give the server 5 seconds to respond, otherwise cancel this and throw an
// error to the console. The fetch request will also throw an error immediately
// if checking the server on localhost and the port is unused.
// Give the server 5 seconds to respond, otherwise cancel this and throw an
// error to the console. The fetch request will also throw an error immediately
// if checking the server on localhost and the port is unused.
const response = await Promise.race([
fetch(new URL("/test-shutdown", serverUrl)),
new Promise(resolve => {
timeoutId = setTimeout(() => {
resolve("Error");
}, 5000);
})
fetch(new URL('/test-shutdown', serverUrl)),
new Promise((resolve) => {
timeoutId = setTimeout(() => {
resolve('Error');
}, 5000);
}),
]);
clearTimeout(timeoutId);
if (response === "Error") throw new Error("Server is unresponsive.");
if (response === 'Error') throw new Error('Server is unresponsive.');
} catch (e) {
// Check if this is the error thrown by the fetch request for an unused port.
// Don't print the unused port error, since nothing has actually broken.
// Check if this is the error thrown by the fetch request for an unused port.
// Don't print the unused port error, since nothing has actually broken.
if (e instanceof TypeError) clearTimeout(timeoutId);
else console.error(e);
await unlink(shutdown);
}
// Do not run this if Node will be killed later in this script. It will fail.
if (config.production && !process.argv.slice(i + 1).includes("kill"))
exec("npx pm2 stop ecosystem.config.js", (error, stdout) => {
// Do not run this if Node will be killed later in this script. It will fail.
if (config.production && !process.argv.slice(i + 1).includes('kill'))
exec('npx pm2 stop ecosystem.config.js', (error, stdout) => {
if (error) throw error;
console.log(stdout);
});
break;
}
case "build": {
const dist = fileURLToPath(new URL("./views/dist", import.meta.url));
await rm(dist, {force: true, recursive: true});
case 'build': {
const dist = fileURLToPath(new URL('./views/dist', import.meta.url));
await rm(dist, { force: true, recursive: true });
await mkdir(dist);
await build({
entryPoints: [
"./views/uv/**/*.js",
"./views/assets/js/**/*.js",
"./views/assets/css/**/*.css"
'./views/uv/**/*.js',
'./views/assets/js/**/*.js',
'./views/assets/css/**/*.css',
],
platform: "browser",
platform: 'browser',
sourcemap: true,
bundle: true,
minify: true,
external: ["*.png", "*.jpg", "*.jpeg", "*.webp", "*.svg"],
outdir: dist
external: ['*.png', '*.jpg', '*.jpeg', '*.webp', '*.svg'],
outdir: dist,
});
break;
}
// Kill all node processes and fully reset PM2. To be used for debugging.
// Using npx pm2 monit, or npx pm2 list in the terminal will also bring up
// more PM2 debugging tools.
case "kill":
if (process.platform === "win32")
exec("( npx pm2 delete ecosystem.config.js ) ; taskkill /F /IM node*",
(error, stdout) => {console.log(stdout)}
// Kill all node processes and fully reset PM2. To be used for debugging.
// Using npx pm2 monit, or npx pm2 list in the terminal will also bring up
// more PM2 debugging tools.
case 'kill':
if (process.platform === 'win32')
exec(
'( npx pm2 delete ecosystem.config.js ) ; taskkill /F /IM node*',
(error, stdout) => {
console.log(stdout);
}
);
else exec("npx pm2 delete ecosystem.config.js; pkill node",
(error, stdout) => {console.log(stdout)}
else
exec(
'npx pm2 delete ecosystem.config.js; pkill node',
(error, stdout) => {
console.log(stdout);
}
);
break;
// No default case.
// No default case.
}
process.exitCode = 0;

View file

@ -18,7 +18,5 @@
"splash": [
"This version is the public LTS build of the web proxy service project and may be hosted unofficially. Check your domain or jo&#173;in the <a id='tnlink' target='_blank'>T&#173;N Dis&#173;co&#173;rd</a> for official pr&#173;ivate site lin&#173;ks for your safety."
],
"version": [
"6.3.7"
]
"version": ["6.3.7"]
}

View file

@ -1,89 +1,85 @@
import { paintSource, tryReadFile } from "./randomization.mjs";
import loadTemplates from "./templates.mjs";
import pkg from "./routes.mjs";
import { readFile } from "fs/promises";
import path from "path";
import express from "express";
import helmet from "helmet";
import http from "http";
import createRammerhead from "rammerhead/src/server/index.js";
import wisp from "wisp-server-node";
import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
import { libcurlPath } from "@mercuryworkshop/libcurl-transport";
import { bareModulePath } from "@mercuryworkshop/bare-as-module3";
import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
import { paintSource, tryReadFile } from './randomization.mjs';
import loadTemplates from './templates.mjs';
import pkg from './routes.mjs';
import { readFile } from 'fs/promises';
import path from 'path';
import express from 'express';
import helmet from 'helmet';
import http from 'http';
import createRammerhead from 'rammerhead/src/server/index.js';
import wisp from 'wisp-server-node';
import { epoxyPath } from '@mercuryworkshop/epoxy-transport';
import { libcurlPath } from '@mercuryworkshop/libcurl-transport';
import { bareModulePath } from '@mercuryworkshop/bare-as-module3';
import { baremuxPath } from '@mercuryworkshop/bare-mux/node';
import { uvPath } from '@titaniumnetwork-dev/ultraviolet';
// import { createBareServer } from "@tomphttp/bare-server-node";
const config = JSON.parse(
await readFile(new URL("./config.json", import.meta.url))
),
{ pages, text404 } = pkg,
__dirname = path.resolve(),
port = process.env.PORT || config.port,
app = express(),
router = express.Router(),
// bare = createBareServer("/bare/"),
rh = createRammerhead();
await readFile(new URL('./config.json', import.meta.url))
),
{ pages, text404 } = pkg,
__dirname = path.resolve(),
port = process.env.PORT || config.port,
app = express(),
router = express.Router(),
// bare = createBareServer("/bare/"),
rh = createRammerhead();
const rammerheadScopes = [
"/rammerhead.js",
"/hammerhead.js",
"/transport-worker.js",
"/task.js",
"/iframe-task.js",
"/worker-hammerhead.js",
"/messaging",
"/sessionexists",
"/deletesession",
"/newsession",
"/editsession",
"/needpassword",
"/syncLocalStorage",
"/api/shuffleDict",
"/mainport",
'/rammerhead.js',
'/hammerhead.js',
'/transport-worker.js',
'/task.js',
'/iframe-task.js',
'/worker-hammerhead.js',
'/messaging',
'/sessionexists',
'/deletesession',
'/newsession',
'/editsession',
'/needpassword',
'/syncLocalStorage',
'/api/shuffleDict',
'/mainport',
];
const rammerheadSession = /^\/[a-z0-9]{32}/,
shouldRouteRh = req => {
const url = new URL(req.url, "http://0.0.0.0");
return (
rammerheadScopes.includes(url.pathname) ||
rammerheadSession.test(url.pathname)
);
},
routeRhRequest = (req, res) => {
rh.emit("request", req, res);
},
routeRhUpgrade = (req, socket, head) => {
rh.emit("upgrade", req, socket, head);
},
server = http.createServer((req, res) => {
/*
shouldRouteRh = (req) => {
const url = new URL(req.url, 'http://0.0.0.0');
return (
rammerheadScopes.includes(url.pathname) ||
rammerheadSession.test(url.pathname)
);
},
routeRhRequest = (req, res) => {
rh.emit('request', req, res);
},
routeRhUpgrade = (req, socket, head) => {
rh.emit('upgrade', req, socket, head);
},
server = http.createServer((req, res) => {
/*
if (bare.shouldRoute(req)) {
bare.routeRequest(req, res);
} else
*/
if (shouldRouteRh(req)) {
routeRhRequest(req, res);
} else {
app(req, res);
}
});
if (shouldRouteRh(req)) {
routeRhRequest(req, res);
} else {
app(req, res);
}
});
server.on("upgrade", (req, socket, head) => {
/*
server.on('upgrade', (req, socket, head) => {
/*
if (bare.shouldRoute(req)) {
bare.routeUpgrade(req, socket, head);
} else
*/
if (shouldRouteRh(req)) {
routeRhUpgrade(req, socket, head);
} else if (req.url.endsWith("/wisp/")) {
} else if (req.url.endsWith('/wisp/')) {
wisp.routeRequest(req, socket, head);
}
});
@ -99,33 +95,35 @@ app.use(
// This takes one of those files and displays it for a site visitor.
// Query strings like /?j are converted into paths like /views/hidden.html
// back here. Which query string converts to what is defined in routes.mjs.
router.get("/", async (req, res) =>
res.send(
paintSource(
loadTemplates(
tryReadFile(
path.join(__dirname,
"views",
// Return the error page if the query is not found in
// routes.mjs. Also set index as the default page.
"/?".indexOf(req.url) ? pages[Object.keys(req.query)[0]] || "error.html" : pages.index
)
)
)
router.get('/', async (req, res) =>
res.send(
paintSource(
loadTemplates(
tryReadFile(
path.join(
__dirname,
'views',
// Return the error page if the query is not found in
// routes.mjs. Also set index as the default page.
'/?'.indexOf(req.url)
? pages[Object.keys(req.query)[0]] || 'error.html'
: pages.index
)
)
)
)
)
);
app.use(router);
app.use(express.static(path.join(__dirname, "views")));
app.use("/uv/", express.static(uvPath));
app.use("/epoxy/", express.static(epoxyPath));
app.use("/libcurl/", express.static(libcurlPath));
app.use("/bareasmodule/", express.static(bareModulePath));
app.use("/baremux/", express.static(baremuxPath));
app.use(express.static(path.join(__dirname, 'views')));
app.use('/uv/', express.static(uvPath));
app.use('/epoxy/', express.static(epoxyPath));
app.use('/libcurl/', express.static(libcurlPath));
app.use('/bareasmodule/', express.static(bareModulePath));
app.use('/baremux/', express.static(baremuxPath));
app.disable("x-powered-by");
app.disable('x-powered-by');
// Redundant code since 404 is handled elsewhere; left here as insurance.
app.use((req, res) => {
@ -133,4 +131,4 @@ app.use((req, res) => {
});
server.listen(port);
console.log("Holy Unblocker is listening on port " + port + ".");
console.log('Holy Unblocker is listening on port ' + port + '.');

View file

@ -1,15 +1,15 @@
import pkg from "./routes.mjs";
import { existsSync, readFileSync } from "fs";
import pkg from './routes.mjs';
import { existsSync, readFileSync } from 'fs';
export { paintSource, preloaded404, tryReadFile };
const {
cookingInserts,
vegetables,
charRandom,
splashRandom,
cacheBustList,
VersionValue,
text404,
} = pkg;
cookingInserts,
vegetables,
charRandom,
splashRandom,
cacheBustList,
VersionValue,
text404,
} = pkg;
// Below are lots of function definitions used to obfuscate the website.
// This makes the website harder to properly categorize, as its source code
@ -19,29 +19,29 @@ const randomListItem = (lis) => () => lis[(Math.random() * lis.length) | 0],
getRandomChar = randomListItem(charRandom),
insertCharset = (str) => str.replace(charset, getRandomChar),
getRandomSplash = randomListItem(splashRandom),
hutaoInsert = (str) => str.replaceAll("<!--HUTAOWOA-->", getRandomSplash),
versionInsert = (str) => str.replaceAll("<!-- VERSION -->", VersionValue),
hutaoInsert = (str) => str.replaceAll('<!--HUTAOWOA-->', getRandomSplash),
versionInsert = (str) => str.replaceAll('<!-- VERSION -->', VersionValue),
getCookingText = () =>
`<span style="display:none" data-fact="${randomListItem(vegetables)()}">${randomListItem(cookingInserts)()}</span>`,
insertCooking = (str) =>
str.replaceAll(
"<!-- IMPORTANT-HUTAOCOOKINGINSERT-DONOTDELETE -->",
'<!-- IMPORTANT-HUTAOCOOKINGINSERT-DONOTDELETE -->',
getCookingText
),
// This one isn't for obfuscation; it's just for dealing with cache issues.
// This one isn't for obfuscation; it's just for dealing with cache issues.
cacheBusting = (str) => {
for (let item of Object.entries(cacheBustList))
str = str.replaceAll(item[0], item[1]);
return str;
},
// Apply the final obfuscation changes to an entire file.
// Apply the final obfuscation changes to an entire file.
paintSource = (str) =>
insertCharset(hutaoInsert(versionInsert(insertCooking(cacheBusting(str))))),
// Use this instead of text404 for a preloaded error page.
// Use this instead of text404 for a preloaded error page.
preloaded404 = paintSource(text404),
// Grab the text content of a file. Ensure the file is a string.
// Grab the text content of a file. Ensure the file is a string.
tryReadFile = (file) =>
existsSync(file + "") ? readFileSync(file + "", "utf8") : preloaded404;
existsSync(file + '') ? readFileSync(file + '', 'utf8') : preloaded404;
/*
// All of this is now old code.

View file

@ -1,75 +1,75 @@
import { readFileSync } from "fs";
import path from "path";
import { readFile } from "fs/promises";
import { readFileSync } from 'fs';
import path from 'path';
import { readFile } from 'fs/promises';
const insert = JSON.parse(
await readFile(new URL("./data.json", import.meta.url))
await readFile(new URL('./data.json', import.meta.url))
);
const __dirname = path.resolve();
const text404 = readFileSync(
path.normalize(__dirname + "/views/error.html"),
"utf8"
path.normalize(__dirname + '/views/error.html'),
'utf8'
);
const pages = {
index: "index.html",
"manifest.json": "manifest.json",
"test-404": "error.html",
index: 'index.html',
'manifest.json': 'manifest.json',
'test-404': 'error.html',
/* Main */
documentation: "docs.html",
questions: "faq.html",
s: "pages/frame.html",
browsing: "pages/surf.html",
credits: "pages/nav/credits.html",
bookmarklets: "pages/nav/bookmarklets.html",
terms: "pages/nav/terms.html",
documentation: 'docs.html',
questions: 'faq.html',
s: 'pages/frame.html',
browsing: 'pages/surf.html',
credits: 'pages/nav/credits.html',
bookmarklets: 'pages/nav/bookmarklets.html',
terms: 'pages/nav/terms.html',
/* Games */
games: "pages/nav/gtools.html",
"web-games": "pages/nav/games5.html",
emulators: "pages/nav/emulators.html",
"flash-games": "pages/nav/flash.html",
"retro-games": "pages/nav/emulibrary.html",
games: 'pages/nav/gtools.html',
'web-games': 'pages/nav/games5.html',
emulators: 'pages/nav/emulators.html',
'flash-games': 'pages/nav/flash.html',
'retro-games': 'pages/nav/emulibrary.html',
/* Proxies */
ultraviolet: "pages/proxnav/ultraviolet.html",
rammerhead: "pages/proxnav/rammerhead.html",
ultraviolet: 'pages/proxnav/ultraviolet.html',
rammerhead: 'pages/proxnav/rammerhead.html',
/* Proxy Presets */
youtube: "pages/proxnav/preset/youtube.html",
apps: "pages/proxnav/preset/applications.html",
youtube: 'pages/proxnav/preset/youtube.html',
apps: 'pages/proxnav/preset/applications.html',
/* Misc */
flash: "archive/gfiles/flash/index.html",
webretro: "archive/gfiles/rarch/index.html",
"vibe-os": "archive/vibeOS/index.html",
flash: 'archive/gfiles/flash/index.html',
webretro: 'archive/gfiles/rarch/index.html',
'vibe-os': 'archive/vibeOS/index.html',
};
const externalPages = {
github: {
default: "https://github.com/QuiteAFancyEmerald/Holy-Unblocker",
aos: "https://github.com/michalsnik/aos",
"bare-module": "https://github.com/motortruck1221/bare-as-module3",
"bare-mux": "https://github.com/MercuryWorkshop/bare-mux",
epoxy: "https://github.com/MercuryWorkshop/epoxy-tls",
fastify: "https://github.com/fastify/fastify",
"font-awesome": "https://github.com/FortAwesome/Font-Awesome",
"libcurl-js": "https://github.com/ading2210/libcurl.js",
"nord-theme": "https://github.com/nordtheme",
ultraviolet: "https://github.com/titaniumnetwork-dev/Ultraviolet",
wisp: "https://github.com/MercuryWorkshop/wisp-protocol"
default: 'https://github.com/QuiteAFancyEmerald/Holy-Unblocker',
aos: 'https://github.com/michalsnik/aos',
'bare-module': 'https://github.com/motortruck1221/bare-as-module3',
'bare-mux': 'https://github.com/MercuryWorkshop/bare-mux',
epoxy: 'https://github.com/MercuryWorkshop/epoxy-tls',
fastify: 'https://github.com/fastify/fastify',
'font-awesome': 'https://github.com/FortAwesome/Font-Awesome',
'libcurl-js': 'https://github.com/ading2210/libcurl.js',
'nord-theme': 'https://github.com/nordtheme',
ultraviolet: 'https://github.com/titaniumnetwork-dev/Ultraviolet',
wisp: 'https://github.com/MercuryWorkshop/wisp-protocol',
},
"titaniumnetwork-documentation": "https://docs.titaniumnetwork.org",
"rammerhead-discord": "https://discord.gg/VNT4E7gN5Y"
'titaniumnetwork-documentation': 'https://docs.titaniumnetwork.org',
'rammerhead-discord': 'https://discord.gg/VNT4E7gN5Y',
};
const cookingInserts = insert.content,
vegetables = insert.keywords,
charRandom = insert.chars,
splashRandom = insert.splash,
VersionValue = insert.version,
cacheBustList = {
"styles.css": "styles-1644738239.css",
"common.js": "common-16451543478.js",
};
vegetables = insert.keywords,
charRandom = insert.chars,
splashRandom = insert.splash,
VersionValue = insert.version,
cacheBustList = {
'styles.css': 'styles-1644738239.css',
'common.js': 'common-16451543478.js',
};
export default {
pages,

View file

@ -1,15 +1,15 @@
import Fastify from 'fastify';
import { createServer } from 'node:http';
import wisp from 'wisp-server-node';
import createRammerhead from "../lib/rammerhead/src/server/index.js";
import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
import { libcurlPath } from "@mercuryworkshop/libcurl-transport";
import { bareModulePath } from "@mercuryworkshop/bare-as-module3";
import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
import createRammerhead from '../lib/rammerhead/src/server/index.js';
import { epoxyPath } from '@mercuryworkshop/epoxy-transport';
import { libcurlPath } from '@mercuryworkshop/libcurl-transport';
import { bareModulePath } from '@mercuryworkshop/bare-as-module3';
import { baremuxPath } from '@mercuryworkshop/bare-mux/node';
import { uvPath } from '@titaniumnetwork-dev/ultraviolet';
import fastifyHelmet from '@fastify/helmet';
import fastifyStatic from '@fastify/static';
import pageRoutes from "./routes.mjs";
import pageRoutes from './routes.mjs';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
import { paintSource, preloaded404, tryReadFile } from './randomization.mjs';
@ -19,10 +19,10 @@ import { existsSync, unlinkSync } from 'node:fs';
import ecosystem from '../ecosystem.config.js';
const config = Object.freeze(
JSON.parse(await readFile(new URL("./config.json", import.meta.url)))
JSON.parse(await readFile(new URL('./config.json', import.meta.url)))
),
ecosystemConfig = Object.freeze(
ecosystem.apps.find(app => app.name === "HolyUB") || ecosystem.apps[0]
ecosystem.apps.find((app) => app.name === 'HolyUB') || ecosystem.apps[0]
),
{ pages, externalPages } = pageRoutes,
__dirname = path.resolve();
@ -30,71 +30,71 @@ const config = Object.freeze(
// Record the server's location as a URL object, including its host and port.
// The host can be modified at /src/config.json, whereas the ports can be modified
// at /ecosystem.config.js.
const serverUrl = (base => {
const serverUrl = ((base) => {
try {
base = new URL(config.host);
} catch (e) {
base = new URL("http://a");
base = new URL('http://a');
base.host = config.host;
}
base.port = ecosystemConfig[ config.production ? "env_production" : "env" ].PORT;
base.port =
ecosystemConfig[config.production ? 'env_production' : 'env'].PORT;
return Object.freeze(base);
})();
console.log(serverUrl);
// The server will check for the existence of this file when a shutdown is requested.
// The shutdown script in run-command.js will temporarily produce this file.
const shutdown = fileURLToPath(new URL("./.shutdown", import.meta.url));
const shutdown = fileURLToPath(new URL('./.shutdown', import.meta.url));
const rh = createRammerhead();
const rammerheadScopes = [
"/rammerhead.js",
"/hammerhead.js",
"/transport-worker.js",
"/task.js",
"/iframe-task.js",
"/worker-hammerhead.js",
"/messaging",
"/sessionexists",
"/deletesession",
"/newsession",
"/editsession",
"/needpassword",
"/syncLocalStorage",
"/api/shuffleDict",
"/mainport",
'/rammerhead.js',
'/hammerhead.js',
'/transport-worker.js',
'/task.js',
'/iframe-task.js',
'/worker-hammerhead.js',
'/messaging',
'/sessionexists',
'/deletesession',
'/newsession',
'/editsession',
'/needpassword',
'/syncLocalStorage',
'/api/shuffleDict',
'/mainport',
];
const rammerheadSession = /^\/[a-z0-9]{32}/,
shouldRouteRh = req => {
shouldRouteRh = (req) => {
try {
const url = new URL(req.url, serverUrl);
return (
rammerheadScopes.includes(url.pathname) ||
rammerheadSession.test(url.pathname)
);
} catch (e) {return false}
} catch (e) {
return false;
}
},
routeRhRequest = (req, res) => {
rh.emit("request", req, res);
rh.emit('request', req, res);
},
routeRhUpgrade = (req, socket, head) => {
rh.emit("upgrade", req, socket, head);
rh.emit('upgrade', req, socket, head);
};
// Create a server factory for RH, and wisp (and bare if you please).
const serverFactory = (handler) => {
return createServer()
.on('request', (req, res) => {
if (shouldRouteRh(req))
routeRhRequest(req, res);
if (shouldRouteRh(req)) routeRhRequest(req, res);
else handler(req, res);
})
.on('upgrade', (req, socket, head) => {
if (shouldRouteRh(req))
routeRhUpgrade(req, socket, head);
else if (req.url.endsWith('/wisp/'))
wisp.routeRequest(req, socket, head);
if (shouldRouteRh(req)) routeRhUpgrade(req, socket, head);
else if (req.url.endsWith('/wisp/')) wisp.routeRequest(req, socket, head);
});
};
@ -103,145 +103,150 @@ const app = Fastify({
ignoreDuplicateSlashes: true,
ignoreTrailingSlash: true,
logger: false,
serverFactory: serverFactory
serverFactory: serverFactory,
});
// Apply Helmet middleware for security
app.register(fastifyHelmet, {
contentSecurityPolicy: false, // Disable CSP
xPoweredBy: false
xPoweredBy: false,
});
// Assign server file paths to different paths, for serving content on the website.
app.register(fastifyStatic, {
root: fileURLToPath(new URL("../views/pages", import.meta.url)),
decorateReply: false
root: fileURLToPath(new URL('../views/pages', import.meta.url)),
decorateReply: false,
});
app.register(fastifyStatic, {
root: fileURLToPath(new URL("../views/assets", import.meta.url)),
prefix: "/assets/",
decorateReply: false
root: fileURLToPath(new URL('../views/assets', import.meta.url)),
prefix: '/assets/',
decorateReply: false,
});
app.register(fastifyStatic, {
root: fileURLToPath(new URL("../views/archive", import.meta.url)),
prefix: "/arcade/",
decorateReply: false
root: fileURLToPath(new URL('../views/archive', import.meta.url)),
prefix: '/arcade/',
decorateReply: false,
});
app.register(fastifyStatic, {
root: fileURLToPath(new URL(
// Use the pre-compiled, minified scripts instead, if enabled in config.
config.minifyScripts ? "../views/dist/assets/js" : "../views/assets/js",
import.meta.url
)),
prefix: "/assets/js/",
decorateReply: false
root: fileURLToPath(
new URL(
// Use the pre-compiled, minified scripts instead, if enabled in config.
config.minifyScripts ? '../views/dist/assets/js' : '../views/assets/js',
import.meta.url
)
),
prefix: '/assets/js/',
decorateReply: false,
});
app.register(fastifyStatic, {
root: fileURLToPath(new URL(
// Use the pre-compiled, minified stylesheets instead, if enabled in config.
config.minifyScripts ? "../views/dist/assets/css" : "../views/assets/css",
import.meta.url
)),
prefix: "/assets/css/",
decorateReply: false
root: fileURLToPath(
new URL(
// Use the pre-compiled, minified stylesheets instead, if enabled in config.
config.minifyScripts ? '../views/dist/assets/css' : '../views/assets/css',
import.meta.url
)
),
prefix: '/assets/css/',
decorateReply: false,
});
// This combines scripts from the official UV repository with local UV scripts into
// one directory path. Local versions of files override the official versions.
app.register(fastifyStatic, {
root: [
fileURLToPath(new URL(
// Use the pre-compiled, minified scripts instead, if enabled in config.
config.minifyScripts ? "../views/dist/uv" : "../views/uv",
import.meta.url
)),
uvPath
fileURLToPath(
new URL(
// Use the pre-compiled, minified scripts instead, if enabled in config.
config.minifyScripts ? '../views/dist/uv' : '../views/uv',
import.meta.url
)
),
uvPath,
],
prefix: "/uv/",
decorateReply: false
prefix: '/uv/',
decorateReply: false,
});
// Register proxy paths to the website.
app.register(fastifyStatic, {
root: epoxyPath,
prefix: "/epoxy/",
decorateReply: false
prefix: '/epoxy/',
decorateReply: false,
});
app.register(fastifyStatic, {
root: libcurlPath,
prefix: "/libcurl/",
decorateReply: false
prefix: '/libcurl/',
decorateReply: false,
});
app.register(fastifyStatic, {
root: bareModulePath,
prefix: "/bareasmodule/",
decorateReply: false
prefix: '/bareasmodule/',
decorateReply: false,
});
app.register(fastifyStatic, {
root: baremuxPath,
prefix: "/baremux/",
decorateReply: false
prefix: '/baremux/',
decorateReply: false,
});
// All website files are stored in the /views directory.
// This takes one of those files and displays it for a site visitor.
// Paths like /browsing are converted into paths like /views/pages/surf.html
// back here. Which path converts to what is defined in routes.mjs.
app.get("/:path", (req, reply) => {
// Testing for future features that need cookies to deliver alternate source files.
if (req.raw.rawHeaders.includes("Cookie"))
console.log(req.raw.rawHeaders[ req.raw.rawHeaders.indexOf("Cookie") + 1 ]);
app.get('/:path', (req, reply) => {
// Testing for future features that need cookies to deliver alternate source files.
if (req.raw.rawHeaders.includes('Cookie'))
console.log(req.raw.rawHeaders[req.raw.rawHeaders.indexOf('Cookie') + 1]);
const reqPath = req.params.path;
if (reqPath in externalPages) {
let externalRoute = externalPages[reqPath];
if (typeof externalRoute !== "string") externalRoute = externalRoute.default;
if (typeof externalRoute !== 'string')
externalRoute = externalRoute.default;
return reply.redirect(externalRoute);
}
// If a GET request is sent to /test-shutdown and a script-generated shutdown file
// is present, gracefully shut the server down.
if (reqPath === "test-shutdown" && existsSync(shutdown)) {
console.log("Holy Unblocker is shutting down.");
app.close();
unlinkSync(shutdown);
process.exitCode = 0;
}
// If a GET request is sent to /test-shutdown and a script-generated shutdown file
// is present, gracefully shut the server down.
if (reqPath === 'test-shutdown' && existsSync(shutdown)) {
console.log('Holy Unblocker is shutting down.');
app.close();
unlinkSync(shutdown);
process.exitCode = 0;
}
// Return the error page if the query is not found in routes.mjs.
if (reqPath && !(reqPath in pages))
return reply.code(404).type("text/html").send(preloaded404);
// Return the error page if the query is not found in routes.mjs.
if (reqPath && !(reqPath in pages))
return reply.code(404).type('text/html').send(preloaded404);
reply.type("text/html").send(
paintSource(
loadTemplates(
tryReadFile(
path.join(
__dirname,
"views",
// Set the index the as the default page.
reqPath ? pages[reqPath] : pages.index
)
reply.type('text/html').send(
paintSource(
loadTemplates(
tryReadFile(
path.join(
__dirname,
'views',
// Set the index the as the default page.
reqPath ? pages[reqPath] : pages.index
)
)
)
);
)
);
});
app.get("/github/:redirect", (req, reply) => {
app.get('/github/:redirect', (req, reply) => {
if (req.params.redirect in externalPages.github)
reply.redirect(externalPages.github[req.params.redirect]);
else reply.code(404).type("text/html").send(preloaded404);
else reply.code(404).type('text/html').send(preloaded404);
});
/*
@ -256,7 +261,7 @@ app.get("/assets/js/uv/uv.config.js", (req, reply) => {
// Set an error page for invalid paths outside the query string system.
app.setNotFoundHandler((req, reply) => {
reply.code(404).type("text/html").send(preloaded404);
reply.code(404).type('text/html').send(preloaded404);
});
app.listen({ port: serverUrl.port, host: serverUrl.hostname });

View file

@ -1,36 +1,25 @@
import { tryReadFile } from "./randomization.mjs";
import path from "path";
import { tryReadFile } from './randomization.mjs';
import path from 'path';
export { loadTemplates as default };
const __dirname = path.resolve() + "/views/pages/misc/deobf";
const __dirname = path.resolve() + '/views/pages/misc/deobf';
const header = tryReadFile(
path.normalize(__dirname + "/header.html")
),
footer = tryReadFile(
path.normalize(__dirname + "/footer.html")
),
documentation = tryReadFile(
path.normalize(__dirname + "/docs.html")
),
faq = tryReadFile(
path.normalize(__dirname + "/faq.html")
),
terms = tryReadFile(
path.normalize(__dirname + "/tos.html")
),
settings = tryReadFile(
path.normalize(__dirname + "/settings.html")
),
const header = tryReadFile(path.normalize(__dirname + '/header.html')),
footer = tryReadFile(path.normalize(__dirname + '/footer.html')),
documentation = tryReadFile(path.normalize(__dirname + '/docs.html')),
faq = tryReadFile(path.normalize(__dirname + '/faq.html')),
terms = tryReadFile(path.normalize(__dirname + '/tos.html')),
settings = tryReadFile(path.normalize(__dirname + '/settings.html')),
loadTemplates = (str) =>
str.replace("<!--HEADER-->", header)
.replace("<!--FOOTER-->", footer)
str
.replace('<!--HEADER-->', header)
.replace('<!--FOOTER-->', footer)
// Used only on docs.html
.replace("<!--DOCS-->", documentation)
// Used only on faq.html
.replace("<!--FAQ-->", faq)
// Used only on terms.html
.replace("<!--TOS-->", terms)
// Used only on header.html
.replace("<!--SETTINGS-->", settings);
// Used only on docs.html
.replace('<!--DOCS-->', documentation)
// Used only on faq.html
.replace('<!--FAQ-->', faq)
// Used only on terms.html
.replace('<!--TOS-->', terms)
// Used only on header.html
.replace('<!--SETTINGS-->', settings);

View file

@ -6,12 +6,12 @@
/* HU CSS
/* ----------------------------------------------- */
@import url("https://fonts.googleapis.com/css?family=Lato:400,700,400italic");
@import url("https://fonts.googleapis.com/css?family=Montserrat+Alternates");
@import url("https://fonts.googleapis.com/css?family=Titillium+Web:400,600,700");
@import url('https://fonts.googleapis.com/css?family=Lato:400,700,400italic');
@import url('https://fonts.googleapis.com/css?family=Montserrat+Alternates');
@import url('https://fonts.googleapis.com/css?family=Titillium+Web:400,600,700');
@import url('https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap');
@import url("https://unpkg.com/@fortawesome/fontawesome-free@5.15.4/css/all.min.css");
@import url('https://unpkg.com/@fortawesome/fontawesome-free@5.15.4/css/all.min.css');
/*
Nord Theme (https://nordtheme.com)
@ -73,14 +73,13 @@ see https://raw.githubusercontent.com/arcticicestudio/nord-docs/develop/assets/i
--dark: #303030;
}
/* -----------------------------------------------
/* HU Page Layout / General Styling
/* ----------------------------------------------- */
html {
color: white;
font-family: "Figtree", sans-serif;
font-family: 'Figtree', sans-serif;
font-weight: 300;
scroll-behavior: smooth;
}
@ -114,7 +113,7 @@ h3,
h4,
h5,
h6 {
font-family: "Figtree", sans-serif;
font-family: 'Figtree', sans-serif;
font-weight: 900;
}
@ -159,11 +158,11 @@ details[open] summary {
}
.font2 {
font-family: "Titillium Web", sans-serif;
font-family: 'Titillium Web', sans-serif;
}
.font3 {
font-family: "Lato", sans-serif;
font-family: 'Lato', sans-serif;
}
.notbold {
@ -240,9 +239,10 @@ details[open] summary {
/* To change the top padding on the footer, change the 3 vw values here to the same thing. */
#footer {
font-family: "Lato", sans-serif;
font-family: 'Lato', sans-serif;
padding-top: 15vw;
background: url("/assets/img/waves.svg"), linear-gradient(to bottom, transparent 0 15vw, #1d2029 15vw 100%);
background: url('/assets/img/waves.svg'),
linear-gradient(to bottom, transparent 0 15vw, #1d2029 15vw 100%);
background-repeat: no-repeat;
background-size: 100vw auto;
position: relative;
@ -258,12 +258,12 @@ details[open] summary {
color: white;
}
/* -----------------------------------------------
/* Icons and Branding
/* ----------------------------------------------- */
.brand-logo-container, .new {
.brand-logo-container,
.new {
display: flex;
align-items: center; /* Align items vertically */
}
@ -275,7 +275,7 @@ details[open] summary {
line-height: 30px;
white-space: nowrap;
margin-right: 20px; /* Adjust margin as needed */
font-family: "Figtree", sans-serif;
font-family: 'Figtree', sans-serif;
font-weight: 900;
letter-spacing: 1px;
text-decoration: none;
@ -304,7 +304,7 @@ details[open] summary {
}
.new::after {
content: "";
content: '';
padding: 22.75px 25px;
margin-left: 8px;
background-image: url('/assets/img/new.svg');
@ -312,7 +312,6 @@ details[open] summary {
font-size: 0;
}
/* -----------------------------------------------
/* Navigation Bar and Menus (Header Contents)
/* ----------------------------------------------- */
@ -370,7 +369,7 @@ details[open] summary {
cursor: auto;
padding: 15px 25px;
margin-top: 10px;
font-family: "Titillium Web", sans-serif;
font-family: 'Titillium Web', sans-serif;
}
/* "More" Navigation Menu */
@ -409,7 +408,8 @@ details[open] summary {
justify-content: center;
}
.dropdown-parent:focus-within .dropdown-settings:not(:is(:has(.close-settings-btn:active))) {
.dropdown-parent:focus-within
.dropdown-settings:not(:is(:has(.close-settings-btn:active))) {
display: flex; /* Flexbox to center content */
}
@ -463,7 +463,10 @@ details[open] summary {
.close-settings-btn:hover {
color: lightgray;
transition: background-color 0.3s ease, color 0.3s ease, transform 0.3s ease;
transition:
background-color 0.3s ease,
color 0.3s ease,
transform 0.3s ease;
transform: scale(1.05);
}
@ -472,7 +475,8 @@ details[open] summary {
gap: 40px; /* Space between left and right columns */
}
.csel-container-left, .settings-right-column {
.csel-container-left,
.settings-right-column {
display: flex;
flex-direction: column;
gap: 15px; /* Space between items within columns */
@ -514,7 +518,7 @@ details[open] summary {
flex: 1; /* Take up available space */
}
.radio-group input[type="radio"] {
.radio-group input[type='radio'] {
accent-color: #88c0d0;
cursor: pointer;
width: 20px; /* Adjust size for better appearance */
@ -547,7 +551,7 @@ details[open] summary {
.switch::after {
position: absolute;
content: "";
content: '';
height: 14px;
width: 14px;
left: 3px;
@ -580,7 +584,9 @@ select:hover {
background-color: #4c566a;
}
.default-badge, .bare-badge, .beta-badge {
.default-badge,
.bare-badge,
.beta-badge {
display: inline-block;
padding: 2px 5px;
border-radius: 5px;
@ -609,7 +615,7 @@ select:hover {
margin-bottom: 15px;
}
.cloakform input[type="text"] {
.cloakform input[type='text'] {
flex: 1;
background-color: #3b4252;
border: 1px solid #4c566a;
@ -619,7 +625,7 @@ select:hover {
box-sizing: border-box;
}
.cloakform input[type="button"] {
.cloakform input[type='button'] {
background-color: #5e81ac;
border: none;
border-radius: 5px;
@ -628,11 +634,11 @@ select:hover {
cursor: pointer;
}
.cloakform input[type="button"]:hover {
.cloakform input[type='button']:hover {
background-color: #81a1c1;
}
input[type="text"] {
input[type='text'] {
width: 100%;
padding: 10px;
background-color: #3b4252;
@ -649,7 +655,7 @@ input[type="text"] {
gap: 15px;
}
#csel input:not([type=checkbox]),
#csel input:not([type='checkbox']),
#csel select {
outline: none;
box-sizing: border-box;
@ -659,20 +665,26 @@ input[type="text"] {
margin: 5px 0;
background-color: var(--nord1);
border: 1px solid var(--nord9);
transition: background-color 0.3s ease, color 0.3s ease, transform 0.3s ease;
transition:
background-color 0.3s ease,
color 0.3s ease,
transform 0.3s ease;
}
#csel input[type=text]:focus {
#csel input[type='text']:focus {
box-shadow: inset 0 0 5px 0 var(--nord3);
transition: box-shadow 0.15s ease-out;
}
#csel input:is([type=submit], [type=button]):hover {
transition: background-color 0.3s ease, color 0.3s ease, transform 0.3s ease;
#csel input:is([type='submit'], [type='button']):hover {
transition:
background-color 0.3s ease,
color 0.3s ease,
transform 0.3s ease;
transform: scale(1.05);
}
#csel input:is([type=submit], [type=button]):active {
#csel input:is([type='submit'], [type='button']):active {
background-color: #78b0c0;
}
@ -695,7 +707,8 @@ input[type="text"] {
gap: 10px;
}
#hideads, #useonion {
#hideads,
#useonion {
cursor: pointer;
margin-left: 0;
}
@ -771,7 +784,6 @@ input[type="text"] {
vertical-align: top;
}
/* -----------------------------------------------
/* Welcome Screen Content (i.e., Big Bold Words)
/* ----------------------------------------------- */
@ -822,7 +834,12 @@ input[type="text"] {
border-radius: 12px;
overflow: hidden;
background-color: var(--nord0);
background-image: url("/assets/img/noise.png"), linear-gradient(145deg, rgba(34,38,47,0.9) 0%, rgba(34,38,47,0.9) 100%);
background-image: url('/assets/img/noise.png'),
linear-gradient(
145deg,
rgba(34, 38, 47, 0.9) 0%,
rgba(34, 38, 47, 0.9) 100%
);
background-blend-mode: overlay;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
@ -857,7 +874,9 @@ input[type="text"] {
background-color: var(--nord3);
}
.no-select, .comment, .mac-content br {
.no-select,
.comment,
.mac-content br {
user-select: none; /* Prevent text selection */
-webkit-user-select: none; /* For Safari */
-moz-user-select: none; /* For Firefox */
@ -866,7 +885,7 @@ input[type="text"] {
.mac-content {
color: var(--nord4);
font-family: "Source Code Pro", monospace;
font-family: 'Source Code Pro', monospace;
font-optical-sizing: auto;
padding: 40px 0 0 80px;
flex: 1;
@ -882,12 +901,12 @@ input[type="text"] {
}
.cmd::before {
content: "$ ";
content: '$ ';
color: var(--nord4);
}
.cmd::after {
content: "\a";
content: '\a';
}
.url {
@ -895,11 +914,11 @@ input[type="text"] {
}
.comment {
color: #616E88;
color: #616e88;
}
.comment::before {
content: "# ";
content: '# ';
}
.homebutton {
@ -924,7 +943,9 @@ input[type="text"] {
/* NOTE: Currently unused. */
.hovermessage:hover {
transition: color 0.3s ease-in, font-size 0s linear 0.3s;
transition:
color 0.3s ease-in,
font-size 0s linear 0.3s;
}
/* NOTE: Currently unused. */
@ -937,12 +958,14 @@ input[type="text"] {
/* NOTE: Currently unused. */
.hovermessage:hover::before {
font-size: 16px;
transition: font-size 0s linear 0.3s, color 0.3s ease-in 0.3s;
transition:
font-size 0s linear 0.3s,
color 0.3s ease-in 0.3s;
}
/* NOTE: Currently unused. */
.buttonlink {
font-family: "Titillium Web", sans-serif;
font-family: 'Titillium Web', sans-serif;
font-weight: bold;
display: inline-block;
text-decoration: none;
@ -1002,8 +1025,7 @@ input[type="text"] {
.text-center {
text-align: center;
}
iner
.splashstrokeheader {
iner .splashstrokeheader {
position: relative;
display: inline-block;
font-size: 36px;
@ -1098,20 +1120,28 @@ iner
}
.box-hero::after {
content: "";
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url("/assets/img/noise.png") repeat, rgba(255, 255, 255, 0.03);
background:
url('/assets/img/noise.png') repeat,
rgba(255, 255, 255, 0.03);
opacity: var(--noise-opacity, 0.02);
pointer-events: none;
-webkit-mask-image: radial-gradient(circle, white 30%, transparent 50%);
-webkit-mask-size: 800px 800px;
-webkit-mask-position: calc(var(--mouse-x) - 400px) calc(var(--mouse-y) - 400px);
-webkit-mask-position: calc(var(--mouse-x) - 400px)
calc(var(--mouse-y) - 400px);
-webkit-mask-repeat: no-repeat;
mask-image: radial-gradient(closest-side, rgba(37, 35, 35, 0.377) 30%, rgba(255, 255, 255, 0.048) 70%, transparent 90%);
mask-image: radial-gradient(
closest-side,
rgba(37, 35, 35, 0.377) 30%,
rgba(255, 255, 255, 0.048) 70%,
transparent 90%
);
mask-size: 800px 800px;
mask-position: calc(var(--mouse-x) - 400px) calc(var(--mouse-y) - 400px);
mask-repeat: no-repeat;
@ -1205,20 +1235,28 @@ iner
}
.box-card::after {
content: "";
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url("/assets/img/noise.png") repeat, rgba(46, 52, 64, 0.03);
background:
url('/assets/img/noise.png') repeat,
rgba(46, 52, 64, 0.03);
opacity: var(--noise-opacity, 0.02);
pointer-events: none;
-webkit-mask-image: radial-gradient(circle, white 30%, transparent 50%);
-webkit-mask-size: 800px 800px;
-webkit-mask-position: calc(var(--mouse-x) - 400px) calc(var(--mouse-y) - 400px);
-webkit-mask-position: calc(var(--mouse-x) - 400px)
calc(var(--mouse-y) - 400px);
-webkit-mask-repeat: no-repeat;
mask-image: radial-gradient(closest-side, rgba(37, 35, 35, 0.377) 30%, rgba(255, 255, 255, 0.048) 70%, transparent 90%);
mask-image: radial-gradient(
closest-side,
rgba(37, 35, 35, 0.377) 30%,
rgba(255, 255, 255, 0.048) 70%,
transparent 90%
);
mask-size: 800px 800px;
mask-position: calc(var(--mouse-x) - 400px) calc(var(--mouse-y) - 400px);
mask-repeat: no-repeat;
@ -1236,7 +1274,7 @@ iner
width: calc(95% - min(30%, 180px) - 32px);
margin-right: 20px;
box-sizing: border-box;
overflow-wrap: break-word
overflow-wrap: break-word;
}
.image-container {
@ -1391,10 +1429,6 @@ iner
}
}
.box-large {
width: 80vw;
margin: 20px auto;
@ -1406,7 +1440,7 @@ iner
.box-error {
margin: 40vh 0;
font-family: "Lato", sans-serif;
font-family: 'Lato', sans-serif;
}
.box-error h1 {
@ -1437,13 +1471,12 @@ iner
margin-bottom: 8px;
}
/* -----------------------------------------------
/* Documentation and FAQ Pages
/* ----------------------------------------------- */
#documentation {
font-family: "Lato", sans-serif;
font-family: 'Lato', sans-serif;
}
#documentation code {
@ -1498,8 +1531,8 @@ iner
}
.ad::before {
content: "Advertisement";
font-family: "Titillium Web", sans-serif;
content: 'Advertisement';
font-family: 'Titillium Web', sans-serif;
position: absolute;
z-index: -1;
left: 50%;
@ -1527,21 +1560,21 @@ iner
border-radius: 5px;
padding: 10px 12px;
color: white;
font-family: "Montserrat Alternates", sans-serif;
font-family: 'Montserrat Alternates', sans-serif;
font-size: 20px;
margin: 3px;
}
.pr-form input[type=text] {
.pr-form input[type='text'] {
max-width: 700px;
width: calc(100% - 44px);
}
.pr-form input[type=text]:focus {
.pr-form input[type='text']:focus {
animation: glowshadow 2s linear infinite;
}
.pr-form input[type=text]::placeholder {
.pr-form input[type='text']::placeholder {
color: var(--gray);
}
@ -1604,7 +1637,6 @@ iner
background-color: #111;
}
/* -----------------------------------------------
/* HU Games Directory
/* ----------------------------------------------- */
@ -1616,7 +1648,7 @@ iner
/* Games list for non-flash games */
.glist {
font-family: "Lato", sans-serif;
font-family: 'Lato', sans-serif;
display: flex;
flex-wrap: wrap;
justify-content: center;
@ -1660,7 +1692,7 @@ iner
/* Flash Games Search Bar */
#fsearchbar {
font-family: "Lato", sans-serif;
font-family: 'Lato', sans-serif;
font-size: 16px;
background-color: var(--nord0);
outline: none;
@ -1678,7 +1710,7 @@ iner
/* Flash Games List */
.flist {
font-family: "Lato", sans-serif;
font-family: 'Lato', sans-serif;
background-color: var(--nord0);
width: 400px;
height: calc(100vh - 92px);
@ -1713,7 +1745,6 @@ iner
margin: 40px 0 32px;
}
/* -----------------------------------------------
/* CSS Animations
/* ----------------------------------------------- */
@ -1753,7 +1784,10 @@ iner
}
.pulse:hover {
transition: background-color 0.3s ease, color 0.3s ease, transform 0.3s ease;
transition:
background-color 0.3s ease,
color 0.3s ease,
transform 0.3s ease;
transform: scale(1.05);
-webkit-font-smoothing: subpixel-antialiased;
}
@ -1785,7 +1819,7 @@ iner
}
.glowbutton::after {
content: "";
content: '';
border-radius: inherit;
display: inline-block;
position: absolute;
@ -1806,10 +1840,11 @@ iner
.glowbutton:active::after {
background: linear-gradient(90deg, var(--nord7), var(--nord8), var(--nord7));
background-size: 100px auto;
animation: glowshadow 2s linear infinite, glowbg 2s linear infinite;
animation:
glowshadow 2s linear infinite,
glowbg 2s linear infinite;
}
/* -----------------------------------------------
/* Mobile Support
/* ----------------------------------------------- */
@ -1842,9 +1877,11 @@ iner
.mnavebutton::before,
.mnavebutton::after {
content: "";
content: '';
position: absolute;
transition: transform 0.2s ease-out, top 0.2s ease-out;
transition:
transform 0.2s ease-out,
top 0.2s ease-out;
}
.mnavebutton {
@ -1882,7 +1919,6 @@ iner
display: none;
}
/* -----------------------------------------------
/* CSS Media Queries (largely for mobile support)
/* ----------------------------------------------- */
@ -1953,7 +1989,7 @@ iner
#banner {
display: none;
}
/*
/*
.mnave {
display: none !important;
}
@ -2051,7 +2087,6 @@ iner
}
@media (max-width: 600px) {
#header {
padding: 15px 30px;
}
@ -2065,7 +2100,8 @@ iner
font-size: 14px;
}
.navbar, .navbar-1 {
.navbar,
.navbar-1 {
font-size: 11px;
}
@ -2116,13 +2152,15 @@ iner
margin-top: 7px;
}
#csel input:not([type=checkbox]), #csel select {
#csel input:not([type='checkbox']),
#csel select {
padding: 7px 8px;
margin: 3.5px 1.75px;
font-size: 11px;
}
#csel .cseltitle ~ input:not([type=checkbox]), #csel select {
#csel .cseltitle ~ input:not([type='checkbox']),
#csel select {
width: calc(100% - 94.5px);
}
@ -2134,7 +2172,8 @@ iner
width: 60vw;
}
.hero, .image-container {
.hero,
.image-container {
display: none;
}

File diff suppressed because it is too large Load diff

View file

@ -7,35 +7,31 @@
// Encase everything in a new scope so that variables are not accidentally
// attached to the global scope.
(() => {
// Track the cursor position with respect to the top left of the card.
// The "this" keyword gets the element that invoked the event listener.
const handleMouseMove = (element) => {
element.addEventListener('mousemove', (e) => {
const rect = element.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// Track the cursor position with respect to the top left of the card.
// The "this" keyword gets the element that invoked the event listener.
const handleMouseMove = element => {
element.addEventListener("mousemove", e => {
const rect = element.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
element.style.setProperty("--mouse-x", `${x}px`);
element.style.setProperty("--mouse-y", `${y}px`);
});
},
// Reset the cursor tracking variables when the cursor leaves the card.
handleMouseLeave = element => {
element.addEventListener("mouseleave", () => {
element.style.setProperty("--mouse-x", `50%`);
element.style.setProperty("--mouse-y", `50%`);
});
},
// Get the box card elements and add the event listeners to them.
shimmerEffects = document.querySelectorAll(".box-card, .box-hero");
// Attach CSS variables, mouse-x and mouse-y, to elements that will be
// given shimmer effects, by adding or modifying the style attribute.
// CSS calculates and renders the actual shimmer effect from there.
shimmerEffects.forEach(handleMouseMove);
shimmerEffects.forEach(handleMouseLeave);
element.style.setProperty('--mouse-x', `${x}px`);
element.style.setProperty('--mouse-y', `${y}px`);
});
},
// Reset the cursor tracking variables when the cursor leaves the card.
handleMouseLeave = (element) => {
element.addEventListener('mouseleave', () => {
element.style.setProperty('--mouse-x', `50%`);
element.style.setProperty('--mouse-y', `50%`);
});
},
// Get the box card elements and add the event listeners to them.
shimmerEffects = document.querySelectorAll('.box-card, .box-hero');
// Attach CSS variables, mouse-x and mouse-y, to elements that will be
// given shimmer effects, by adding or modifying the style attribute.
// CSS calculates and renders the actual shimmer effect from there.
shimmerEffects.forEach(handleMouseMove);
shimmerEffects.forEach(handleMouseLeave);
})();

File diff suppressed because it is too large Load diff

View file

@ -5,150 +5,168 @@
/* Settings Menu
/* ----------------------------------------------- */
// Encase everything in a new scope so that variables are not accidentally
// attached to the global scope.
(() => {
// Determine the expiration date of a new cookie.
let date = new Date();
date.setFullYear(date.getFullYear() + 100);
date = date.toUTCString();
// Determine the expiration date of a new cookie.
let date = new Date();
date.setFullYear(date.getFullYear() + 100);
date = date.toUTCString();
// All cookies should be secure and are intended to work in iframes.
const setCookie = (name, value) => {
document.cookie =
name +
`=${encodeURIComponent(value)}; expires=${date}; SameSite=None; Secure;`;
},
removeCookie = (name) => {
document.cookie =
name +
'=; expires=Thu, 01 Jan 1970 00:00:01 GMT; SameSite=None; Secure;';
},
readCookie = async (name) => {
// Get the first cookie that has the same name.
for (let cookie of document.cookie.split('; '))
if (!cookie.indexOf(name + '='))
// Return the cookie's stored content.
return decodeURIComponent(cookie.slice(name.length + 1));
},
// Customize the page's title.
pageTitle = (value) => {
let tag =
document.getElementsByTagName('title')[0] ||
document.createElement('title');
tag.innerHTML = value;
document.head.appendChild(tag);
},
// Set the page's favicon to a new URL.
pageIcon = (value) => {
let tag =
document.querySelector("link[rel*='icon']") ||
document.createElement('link');
tag.rel = 'icon';
tag.href = value;
document.head.appendChild(tag);
},
// Make a small stylesheet to override a setting from the main stylesheet.
pageShowAds = () => {
let advertising = document.createElement('style');
advertising.id = 'advertising';
advertising.innerText = '.ad { display:block; }';
(
document.head ||
document.body ||
document.documentElement ||
document
).appendChild(advertising);
},
// Remove the stylesheet made by the function above, if it exists.
pageHideAds = () => {
(document.getElementById('advertising') || new Text()).remove();
},
// These titles and icons are used as autofill templates by settings.html.
// The icon URLs and tab titles may need to be updated over time.
presetIcons = Object.freeze({
'': ' \n ',
Google: 'Google \n https://www.google.com/favicon.ico',
Bing: 'Bing \n https://www.bing.com/sa/simg/favicon-trans-bg-blue-mg-28.ico',
'Google Drive':
'Home - Google Drive \n https://ssl.gstatic.com/images/branding/product/2x/drive_2020q4_48dp.png',
Gmail:
'Inbox - Gmail \n https://ssl.gstatic.com/ui/v1/icons/mail/rfr/gmail.ico',
}),
// Choose the default transport mode, for proxying, based on the browser.
// Firefox is not supported by epoxy yet, which is why this is implemented.
defaultMode = /(?:Chrome|AppleWebKit)\//.test(navigator.userAgent)
? 'epoxy'
: 'libcurl';
// All cookies should be secure and are intended to work in iframes.
const setCookie = (name, value) => {
document.cookie = name + `=${encodeURIComponent(value)}; expires=${date}; SameSite=None; Secure;`;
},
// Load a custom page title and favicon if it was previously stored.
readCookie('HBTitle').then((s) => {
s != undefined && pageTitle(s);
});
readCookie('HBIcon').then((s) => {
s != undefined && pageIcon(s);
});
removeCookie = name => {
document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:01 GMT; SameSite=None; Secure;";
},
// Load the UV transport mode that was last used, or use the default.
readCookie('HBTransport').then((s) => {
let transportMode = document.querySelector(
`#uv-transport-list input[value="${s || defaultMode}"]`
);
if (transportMode) transportMode.click();
});
readCookie = async name => {
for (let cookie of document.cookie.split("; "))
// Get the first cookie that has the same name.
if (!cookie.indexOf(name + "="))
// Return the cookie's stored content.
return decodeURIComponent(cookie.slice(name.length + 1));
},
// Ads are disabled by default. Load ads if ads were enabled previously.
// Change !== to === here if ads should be enabled by default.
readCookie('HBHideAds').then((s) => {
s !== 'false'
? pageHideAds()
: pageShowAds(((document.getElementById('hideads') || {}).checked = 0));
});
// Customize the page's title.
pageTitle = value => {
let tag = document.getElementsByTagName("title")[0] || document.createElement("title");
tag.innerHTML = value;
document.head.appendChild(tag);
},
// Set the page's favicon to a new URL.
pageIcon = value => {
let tag = document.querySelector("link[rel*='icon']") || document.createElement("link");
tag.rel = "icon";
tag.href = value;
document.head.appendChild(tag);
},
// Make a small stylesheet to override a setting from the main stylesheet.
pageShowAds = () => {
let advertising = document.createElement("style");
advertising.id = "advertising";
advertising.innerText = ".ad { display:block; }";
(document.head || document.body || document.documentElement || document).appendChild(advertising);
},
// Remove the stylesheet made by the function above, if it exists.
pageHideAds = () => {
(document.getElementById("advertising")||new Text()).remove();
},
// These titles and icons are used as autofill templates by settings.html.
// The icon URLs and tab titles may need to be updated over time.
presetIcons = Object.freeze({
"": " \n ",
"Google": "Google \n https://www.google.com/favicon.ico",
"Bing": "Bing \n https://www.bing.com/sa/simg/favicon-trans-bg-blue-mg-28.ico",
"Google Drive": "Home - Google Drive \n https://ssl.gstatic.com/images/branding/product/2x/drive_2020q4_48dp.png",
"Gmail": "Inbox - Gmail \n https://ssl.gstatic.com/ui/v1/icons/mail/rfr/gmail.ico"
}),
// Choose the default transport mode, for proxying, based on the browser.
// Firefox is not supported by epoxy yet, which is why this is implemented.
defaultMode = /(?:Chrome|AppleWebKit)\//.test(navigator.userAgent)
? "epoxy"
: "libcurl";
// Load a custom page title and favicon if it was previously stored.
readCookie("HBTitle").then(s => {(s != undefined) && pageTitle(s)});
readCookie("HBIcon").then(s => {(s != undefined) && pageIcon(s)});
// Load the UV transport mode that was last used, or use the default.
readCookie("HBTransport").then(s => {
let transportMode =
document.querySelector(`#uv-transport-list input[value="${
s || defaultMode
}"]`);
if (transportMode) transportMode.click();
});
// Ads are disabled by default. Load ads if ads were enabled previously.
// Change !== to === here if ads should be enabled by default.
readCookie("HBHideAds").then(s => {(s !== "false") ? pageHideAds() : pageShowAds((document.getElementById("hideads") || {}).checked = 0)});
// Tor is disabled by default. Enable Tor if it was enabled previously.
readCookie("HBUseOnion").then(s => {if (s === "true") {
let torCheck = document.getElementById("useonion") ||
{dispatchEvent: () => {}};
torCheck.checked = 1;
torCheck.dispatchEvent(new Event("change"));
}});
// All code below is used by the Settings UI in the navigation bar.
if (document.getElementById("csel")) {
const attachEventListener = (selector, ...args) => (
document.getElementById(selector) ||
document.querySelector(selector)
).addEventListener(...args),
focusElement =
document.getElementsByClassName("dropdown-settings")[0].parentElement.querySelector("a[href='#']");
attachEventListener(".dropdown-settings .close-settings-btn", "click",
() => {document.activeElement.blur()}
);
// Allow users to set a custom title with the UI.
attachEventListener("titleform", "submit", e => {
e.preventDefault();
e = e.target.firstElementChild;
if (e.value) {
pageTitle(e.value);
setCookie("HBTitle", e.value);
e.value = "";
} else if (confirm("Reset the title to default?")) {
// Allow users to reset the title to default if nothing is entered.
focusElement.focus();
removeCookie("HBTitle");
pageTitle("Holy Unblocker LTS");
// Tor is disabled by default. Enable Tor if it was enabled previously.
readCookie('HBUseOnion').then((s) => {
if (s === 'true') {
let torCheck = document.getElementById('useonion') || {
dispatchEvent: () => {},
};
torCheck.checked = 1;
torCheck.dispatchEvent(new Event('change'));
}
});
// Allow users to set a custom favicon with the UI.
attachEventListener("iconform", "submit", e => {
e.preventDefault();
e = e.target.firstElementChild;
if (e.value) {
pageIcon(e.value);
setCookie("HBIcon", e.value);
e.value = "";
} else if (confirm("Reset the icon to default?")) {
// Allow users to reset the favicon to default if nothing is entered.
focusElement.focus();
removeCookie("HBIcon");
pageIcon("assets/img/icon.png");
}
});
// All code below is used by the Settings UI in the navigation bar.
if (document.getElementById('csel')) {
const attachEventListener = (selector, ...args) =>
(
document.getElementById(selector) || document.querySelector(selector)
).addEventListener(...args),
focusElement = document
.getElementsByClassName('dropdown-settings')[0]
.parentElement.querySelector("a[href='#']");
/*
attachEventListener(
'.dropdown-settings .close-settings-btn',
'click',
() => {
document.activeElement.blur();
}
);
// Allow users to set a custom title with the UI.
attachEventListener('titleform', 'submit', (e) => {
e.preventDefault();
e = e.target.firstElementChild;
if (e.value) {
pageTitle(e.value);
setCookie('HBTitle', e.value);
e.value = '';
} else if (confirm('Reset the title to default?')) {
// Allow users to reset the title to default if nothing is entered.
focusElement.focus();
removeCookie('HBTitle');
pageTitle('Holy Unblocker LTS');
}
});
// Allow users to set a custom favicon with the UI.
attachEventListener('iconform', 'submit', (e) => {
e.preventDefault();
e = e.target.firstElementChild;
if (e.value) {
pageIcon(e.value);
setCookie('HBIcon', e.value);
e.value = '';
} else if (confirm('Reset the icon to default?')) {
// Allow users to reset the favicon to default if nothing is entered.
focusElement.focus();
removeCookie('HBIcon');
pageIcon('assets/img/icon.png');
}
});
/*
This is unused in the current settings menu.
@ -163,67 +181,70 @@ if (document.getElementById("csel")) {
});
*/
// Provides users with a handy set of title and icon autofill options.
attachEventListener("icon-list", "change", e => {
let titleform = document.getElementById("titleform"),
iconform = document.getElementById("iconform");
[titleform.firstElementChild.value,
iconform.firstElementChild.value] =
(presetIcons[e.target.value] || " \n ").split(" \n ");
});
// Provides users with a handy set of title and icon autofill options.
attachEventListener('icon-list', 'change', (e) => {
let titleform = document.getElementById('titleform'),
iconform = document.getElementById('iconform');
[titleform.firstElementChild.value, iconform.firstElementChild.value] = (
presetIcons[e.target.value] || ' \n '
).split(' \n ');
});
// Allow users to change the UV transport mode, for proxying, with the UI.
const uvTransportList = document.getElementById("uv-transport-list");
uvTransportList.querySelectorAll("input").forEach(element => {
element.addEventListener("change", e => {
!uvTransportList.querySelector("input:checked") ||
e.target.value === defaultMode
? removeCookie("HBTransport")
: setCookie("HBTransport", e.target.value);
// Allow users to change the UV transport mode, for proxying, with the UI.
const uvTransportList = document.getElementById('uv-transport-list');
uvTransportList.querySelectorAll('input').forEach((element) => {
element.addEventListener('change', (e) => {
!uvTransportList.querySelector('input:checked') ||
e.target.value === defaultMode
? removeCookie('HBTransport')
: setCookie('HBTransport', e.target.value);
// Only the libcurl transport mode supports Tor at the moment.
let torCheck = document.getElementById("useonion");
if(e.target.value !== "libcurl" && torCheck.checked)
torCheck.click();
})
});
// Only the libcurl transport mode supports Tor at the moment.
let torCheck = document.getElementById('useonion');
if (e.target.value !== 'libcurl' && torCheck.checked) torCheck.click();
});
});
// Allow users to toggle ads with the UI.
attachEventListener("hideads", "change", e => {
if (e.target.checked) {
pageHideAds();
setCookie("HBHideAds", "true");
} else {
pageShowAds();
setCookie("HBHideAds", "false");
}
});
// Allow users to toggle ads with the UI.
attachEventListener('hideads', 'change', (e) => {
if (e.target.checked) {
pageHideAds();
setCookie('HBHideAds', 'true');
} else {
pageShowAds();
setCookie('HBHideAds', 'false');
}
});
// Allow users to toggle onion routing in Ultraviolet with the UI. Only
// the libcurl transport mode supports Tor at the moment, so ensure that
// users are aware that they cannot use Tor with other modes.
attachEventListener("useonion", "change", e => {
let unselectedModes =
document.querySelectorAll("#uv-transport-list input:not([value=libcurl])");
if (e.target.checked) {
let selectedMode =
document.querySelector("#uv-transport-list input[value=libcurl]");
unselectedModes.forEach(e => {e.setAttribute("disabled", "true")});
selectedMode.click();
setCookie("HBUseOnion", "true");
} else {
unselectedModes.forEach(e => {e.removeAttribute("disabled")});
// Tor will likely never be enabled by default, so removing the cookie
// here may be better than setting it to false.
removeCookie("HBUseOnion");
}
});
}
// Allow users to toggle onion routing in Ultraviolet with the UI. Only
// the libcurl transport mode supports Tor at the moment, so ensure that
// users are aware that they cannot use Tor with other modes.
attachEventListener('useonion', 'change', (e) => {
let unselectedModes = document.querySelectorAll(
'#uv-transport-list input:not([value=libcurl])'
);
if (e.target.checked) {
let selectedMode = document.querySelector(
'#uv-transport-list input[value=libcurl]'
);
unselectedModes.forEach((e) => {
e.setAttribute('disabled', 'true');
});
selectedMode.click();
setCookie('HBUseOnion', 'true');
} else {
unselectedModes.forEach((e) => {
e.removeAttribute('disabled');
});
// Tor will likely never be enabled by default, so removing the cookie
// here may be better than setting it to false.
removeCookie('HBUseOnion');
}
});
}
})();
/* -----------------------------------------------
/* Original code written by OlyB
/* -----------------------------------------------

View file

@ -2,10 +2,10 @@
await loadFull(tsParticles);
await tsParticles.load({
id: "particles-js",
id: 'particles-js',
options: {
background: {
color: { value: "#1d232a" },
color: { value: '#1d232a' },
},
fullScreen: {
enable: true,
@ -22,14 +22,14 @@
},
particles: {
color: {
value: "#ffffff",
value: '#ffffff',
},
move: {
enable: true,
speed: 0.8,
direction: "none",
direction: 'none',
outModes: {
default: "out",
default: 'out',
},
},
number: {
@ -48,7 +48,7 @@
},
},
shape: {
type: "circle",
type: 'circle',
},
size: {
value: { min: 1, max: 5 },
@ -61,7 +61,7 @@
links: {
enable: true,
distance: 150,
color: "#ffffff",
color: '#ffffff',
opacity: 0.4,
width: 1,
},

View file

@ -1,81 +1,83 @@
// Encase everything in a new scope so that variables are not accidentally
// attached to the global scope.
(() => {
const stockSW = '/uv/sw.js',
blacklistSW = '/uv/sw-blacklist.js',
swAllowedHostnames = ['localhost', '127.0.0.1'],
connection = new BareMux.BareMuxConnection('/baremux/worker.js'),
wispUrl =
(location.protocol === 'https:' ? 'wss' : 'ws') +
'://' +
location.host +
'/wisp/',
// Proxy configuration
proxyUrl = 'socks5h://localhost:9050', // Replace with your proxy URL
transports = {
epoxy: '/epoxy/index.mjs',
libcurl: '/libcurl/index.mjs',
bare: '/baremux/index.mjs',
},
// The following two variables are copied and pasted here from csel.js.
readCookie = async (name) => {
// Get the first cookie that has the same name.
for (let cookie of document.cookie.split('; '))
if (!cookie.indexOf(name + '='))
// Return the cookie's stored content.
return decodeURIComponent(cookie.slice(name.length + 1));
},
// Sets the default transport mode based on the browser. Firefox is not
// supported by epoxy yet, which is why this is implemented.
defaultMode = /(?:Chrome|AppleWebKit)\//.test(navigator.userAgent)
? 'epoxy'
: 'libcurl';
const stockSW = "/uv/sw.js",
blacklistSW = "/uv/sw-blacklist.js",
swAllowedHostnames = ["localhost", "127.0.0.1"],
connection = new BareMux.BareMuxConnection("/baremux/worker.js"),
wispUrl = (location.protocol === "https:" ? "wss" : "ws") + "://" + location.host + "/wisp/",
transports.default = transports[defaultMode];
// Proxy configuration
proxyUrl = "socks5h://localhost:9050", // Replace with your proxy URL
transports = {
epoxy: "/epoxy/index.mjs",
libcurl: "/libcurl/index.mjs",
bare: "/baremux/index.mjs"
},
// Prevent the transports object from accidentally being edited.
Object.freeze(transports);
// The following two variables are copied and pasted here from csel.js.
readCookie = async name => {
for (let cookie of document.cookie.split("; "))
// Get the first cookie that has the same name.
if (!cookie.indexOf(name + "="))
// Return the cookie's stored content.
return decodeURIComponent(cookie.slice(name.length + 1));
},
const registerSW = async () => {
if (!navigator.serviceWorker) {
if (
location.protocol !== 'https:' &&
!swAllowedHostnames.includes(location.hostname)
)
throw new Error('Service workers cannot be registered without https.');
// Sets the default transport mode based on the browser. Firefox is not
// supported by epoxy yet, which is why this is implemented.
defaultMode = /(?:Chrome|AppleWebKit)\//.test(navigator.userAgent)
? "epoxy"
: "libcurl";
throw new Error("Your browser doesn't support service workers.");
}
transports.default = transports[defaultMode];
// If the user has changed the transport mode, use that over the default.
const transportMode =
transports[await readCookie('HBTransport')] || transports.default;
let transportOptions = { wisp: wispUrl };
// Prevent the transports object from accidentally being edited.
Object.freeze(transports);
// Only use Tor with the proxy if the user has enabled it in settings.
if ((await readCookie('HBUseOnion')) === 'true')
transportOptions.proxy = proxyUrl;
const registerSW = async () => {
if (!navigator.serviceWorker) {
if (
location.protocol !== "https:" &&
!swAllowedHostnames.includes(location.hostname)
)
throw new Error("Service workers cannot be registered without https.");
await connection.setTransport(transportMode, [transportOptions]);
throw new Error("Your browser doesn't support service workers.");
}
// Choose a service worker to register based on whether or not the user
// has ads enabled. If the user changes this setting, this script needs
// to be reloaded for this to update, such as by refreshing the page.
const registrations = await navigator.serviceWorker.getRegistrations(),
usedSW =
(await readCookie('HBHideAds')) !== 'false' ? blacklistSW : stockSW;
// If the user has changed the transport mode, use that over the default.
const transportMode = transports[await readCookie("HBTransport")] ||
transports.default;
let transportOptions = { wisp: wispUrl };
// Unregister a service worker if it isn't the one being used.
for (const registration of registrations)
if (
registration.active &&
new URL(registration.active.scriptURL).pathname !==
new URL(usedSW, location.origin).pathname
)
await registration.unregister();
// Only use Tor with the proxy if the user has enabled it in settings.
if (await readCookie("HBUseOnion") === "true")
transportOptions.proxy = proxyUrl;
await navigator.serviceWorker.register(usedSW);
};
await connection.setTransport(transportMode, [transportOptions]);
// Choose a service worker to register based on whether or not the user
// has ads enabled. If the user changes this setting, this script needs
// to be reloaded for this to update, such as by refreshing the page.
const registrations = await navigator.serviceWorker.getRegistrations(),
usedSW = await readCookie("HBHideAds") !== "false"
? blacklistSW
: stockSW;
// Unregister a service worker if it isn't the one being used.
for (const registration of registrations)
if (registration.active &&
new URL(registration.active.scriptURL).pathname !== new URL(usedSW, location.origin).pathname)
await registration.unregister();
await navigator.serviceWorker.register(usedSW);
}
/*
/*
Commented out upon discovering that a duplicate BareMux connection may be
unnecessary; previously thought to have prevented issues with refreshing.
@ -91,6 +93,5 @@ async function setupTransportOnLoad() {
setupTransportOnLoad();
*/
registerSW();
registerSW();
})();

View file

@ -44,18 +44,18 @@
<script src="assets/js/particlesjs/particles.js"></script>
<script>
(function () {
var v = document.getElementById("vsc");
var v = document.getElementById('vsc');
var t, a;
v.addEventListener(
"mouseenter",
'mouseenter',
function () {
t = setTimeout(function () {
if (!a) {
a = true;
var e = new Audio("assets/misc/visualstudiocode.mp3");
var e = new Audio('assets/misc/visualstudiocode.mp3');
e.play();
e.addEventListener(
"ended",
'ended',
function () {
a = false;
},
@ -67,7 +67,7 @@
false
);
v.addEventListener(
"mouseleave",
'mouseleave',
function () {
clearTimeout(t);
},

File diff suppressed because it is too large Load diff

View file

@ -1,53 +1,53 @@
{
"short_name": "Holy Unblocker LTS",
"name": "Holy Unblocker LTS | Free Web Proxy Service",
"icons": [
{
"src": "https://holyunblocker.org/assets/img/icon.png",
"type": "image/png",
"sizes": "300x300"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#b4213b",
"background_color": "#1f003e",
"description": "Holy Unblocker LTS is a free and secure web proxy service that helps you bypass web filters and access blocked websites. Enjoy anonymous browsing and internet freedom on devices like Chromebooks at school or work.",
"short_description": "Free web proxy service for bypassing filters and accessing blocked sites.",
"keywords": [
"proxy",
"web proxy",
"unblock websites",
"free web proxy",
"proxy list",
"online proxy",
"proxy server",
"proxy YouTube",
"bypass web filters",
"Holy Unblocker",
"unblock Chromebook",
"Titanium Network",
"fast proxy",
"secure proxy",
"anonymous browsing",
"internet freedom"
],
"related_applications": [
{
"platform": "web",
"url": "https://holyunblocker.org"
},
{
"platform": "github",
"url": "https://github.com/QuiteAFancyEmerald/Holy-Unblocker"
},
{
"platform": "twitter",
"url": "https://twitter.com/titaniumnetdev"
},
{
"platform": "youtube",
"url": "https://www.youtube.com/channel/UC6LaREFvs9L72SK1s2PcxNg"
}
]
"short_name": "Holy Unblocker LTS",
"name": "Holy Unblocker LTS | Free Web Proxy Service",
"icons": [
{
"src": "https://holyunblocker.org/assets/img/icon.png",
"type": "image/png",
"sizes": "300x300"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#b4213b",
"background_color": "#1f003e",
"description": "Holy Unblocker LTS is a free and secure web proxy service that helps you bypass web filters and access blocked websites. Enjoy anonymous browsing and internet freedom on devices like Chromebooks at school or work.",
"short_description": "Free web proxy service for bypassing filters and accessing blocked sites.",
"keywords": [
"proxy",
"web proxy",
"unblock websites",
"free web proxy",
"proxy list",
"online proxy",
"proxy server",
"proxy YouTube",
"bypass web filters",
"Holy Unblocker",
"unblock Chromebook",
"Titanium Network",
"fast proxy",
"secure proxy",
"anonymous browsing",
"internet freedom"
],
"related_applications": [
{
"platform": "web",
"url": "https://holyunblocker.org"
},
{
"platform": "github",
"url": "https://github.com/QuiteAFancyEmerald/Holy-Unblocker"
},
{
"platform": "twitter",
"url": "https://twitter.com/titaniumnetdev"
},
{
"platform": "youtube",
"url": "https://www.youtube.com/channel/UC6LaREFvs9L72SK1s2PcxNg"
}
]
}

View file

@ -36,7 +36,7 @@
<!-- IMPORTANT-HUCOOKINGINSERT-DONOTDELETE -->
<iframe id="frame" allow="fullscreen" autofocus></iframe>
<script>
document.getElementById("frame").src = localStorage.getItem("huframesrc");
document.getElementById('frame').src = localStorage.getItem('huframesrc');
</script>
<script src="assets/js/csel.js"></script>
</body>

View file

@ -1,54 +1,93 @@
<!-- https://markdowntohtml.com/ -->
<h1 id="holy-unblocker-img-align-left-src-https-raw-githubusercontent-com-titaniumnetwork-dev-holy-unblocker-master-views-assets-img-icon-png-img-">Holy Unblocker Documentation</h1>
<p>Holy Unblocker, an official flagship Titanium Network site, can bypass web filters regardless of whether it is an extension or network-based. Being a secure web proxy service, it supports numerous sites while being updated frequently and concentrating on detail with design, mechanics, and features.</p>
<h1
id="holy-unblocker-img-align-left-src-https-raw-githubusercontent-com-titaniumnetwork-dev-holy-unblocker-master-views-assets-img-icon-png-img-"
>
Holy Unblocker Documentation
</h1>
<p>
Holy Unblocker, an official flagship Titanium Network site, can bypass web
filters regardless of whether it is an extension or network-based. Being a
secure web proxy service, it supports numerous sites while being updated
frequently and concentrating on detail with design, mechanics, and features.
</p>
<p>Works with a large number of sites, including YouTube, Discord, and more!</p>
<p>Also has a good amount of locally hosted games featured on the site.</p>
<p><strong>Read below for information if the official site is blocked or for obtaining more links.</strong></p>
<p>
<strong
>Read below for information if the official site is blocked or for obtaining
more links.</strong
>
</p>
<h4 id="supports">Supports</h4>
<ul>
<li>Youtube.com</li>
<li>Discord.com</li>
<li>Google.com</li>
<li>Reddit.com</li>
<li>Bing.com</li>
<li>And more sites!</li>
<li>Youtube.com</li>
<li>Discord.com</li>
<li>Google.com</li>
<li>Reddit.com</li>
<li>Bing.com</li>
<li>And more sites!</li>
</ul>
<h4 id="features-">Features:</h4>
<ul>
<li>Tab customization using the Options menu for improved stealth </li>
<li>Considerable variety with the open selection of proxy types </li>
<li>Game library with moderately decent titles</li>
<li>Has frequent support articles for issues relating to the various proxy instances</li>
<li>Tab customization using the Options menu for improved stealth</li>
<li>Considerable variety with the open selection of proxy types</li>
<li>Game library with moderately decent titles</li>
<li>
Has frequent support articles for issues relating to the various proxy
instances
</li>
</ul>
<p>Note: EmuLibrary is not featured in the public version.</p>
<p>Official Site: <a href="https://holyubofficial.net">https://holyubofficial.net</a></p>
<p><strong>Be sure to join Titanium Network&#39;s Discord for more official site links:</strong> <a href="https://discord.gg/unblock">https://discord.gg/unblock</a></p>
<p>Simply do <code>%proxy hu</code> in <code>#proxy-commands</code> for more Holy Unblocker links on the TN Discord server.</p>
<p>
Official Site:
<a href="https://holyubofficial.net">https://holyubofficial.net</a>
</p>
<p>
<strong
>Be sure to join Titanium Network&#39;s Discord for more official site
links:</strong
>
<a href="https://discord.gg/unblock">https://discord.gg/unblock</a>
</p>
<p>
Simply do <code>%proxy hu</code> in <code>#proxy-commands</code> for more Holy
Unblocker links on the TN Discord server.
</p>
<h2 id="table-of-contents-">Table of contents:</h2>
<ul>
<li><a href="#how-to-setup">Setup</a>
<li>
<a href="#how-to-setup">Setup</a>
<ul>
<li>
<a href="#structure">Structure</a>
<ul>
<li><a href="#structure">Structure</a>
<ul>
<li><a href="#structure-information">Structure Information</a></li>
<li><a href="#details-of-views">Static Files</a></li>
<li><a href="#scripts-located-in-viewsassetsjs">Scripts</a></li>
</ul>
</li>
<li><a href="#future-additions">Future Additions</a></li>
<li><a href="#vauge-explanation-for-beginners-with-external-proxies-and-hosting">Beginner&#39;s Explanation</a>
<ul>
<li><a href="#list-of-some-good-hosting-options">Hosting Providers</a></li>
<li><a href="#heroku-steps">Heroku Setup</a></li>
<li><a href="#freenomdomain-steps">Domain Setup</a></li>
<li><a href="#cloudflare-steps">Cloudflare Setup</a></li>
<li><a href="#workspace-configurations">Workspace Configurations</a></li>
</ul>
</li>
<li><a href="#detailed-faq">Detailed FAQ</a></li>
<li><a href="#more-information">More Information</a></li>
<li><a href="#structure-information">Structure Information</a></li>
<li><a href="#details-of-views">Static Files</a></li>
<li><a href="#scripts-located-in-viewsassetsjs">Scripts</a></li>
</ul>
</li>
</li>
<li><a href="#future-additions">Future Additions</a></li>
<li>
<a
href="#vauge-explanation-for-beginners-with-external-proxies-and-hosting"
>Beginner&#39;s Explanation</a
>
<ul>
<li>
<a href="#list-of-some-good-hosting-options">Hosting Providers</a>
</li>
<li><a href="#heroku-steps">Heroku Setup</a></li>
<li><a href="#freenomdomain-steps">Domain Setup</a></li>
<li><a href="#cloudflare-steps">Cloudflare Setup</a></li>
<li>
<a href="#workspace-configurations">Workspace Configurations</a>
</li>
</ul>
</li>
<li><a href="#detailed-faq">Detailed FAQ</a></li>
<li><a href="#more-information">More Information</a></li>
</ul>
</li>
</ul>
<h2 id="how-to-setup">How to Setup</h2>
<p>Either use the button above to deploy to Heroku or do the below:</p>
@ -60,167 +99,370 @@ npm install
npm <span class="hljs-literal">start</span>
</code></pre>
<p>The default place for the proxy when its started is <code>http://localhost:8080</code> but you can change it if needed in config.json</p>
<p>This website is hosted locally with Corrosion built-in. More more information go to the Corrosion repository below.</p>
<p>
The default place for the proxy when its started is
<code>http://localhost:8080</code> but you can change it if needed in
config.json
</p>
<p>
This website is hosted locally with Corrosion built-in. More more information
go to the Corrosion repository below.
</p>
<h2 id="structure">Structure</h2>
<ul>
<li><code>index.html</code>: The homepage of the site.</li>
<li><code>404.html</code>: The 404 page.</li>
<li><code>error.html</code>: Other errors that are not 404.</li>
<li><code>info.html</code>: Documentation (This page!)</li>
<li><code>faq.html</code>: Frequently asked questions page.</li>
<li><code>hidden.html</code>: Fake &quot;Site not Found&quot; page (unused)</li>
<li><code>frame.html</code>: Handles any pages under stealth.</li>
<li><code>surf.html</code>: Web Proxies page, page offers to be redirected to any proxies you would like to add. In this case, Corrosion, Womginx, and Palladium.</li>
<li><code>credits.html</code>: List of all contributors to the site.</li>
<li><code>bookmarklets.html</code>: Bookmarklets page, to be worked on more in the future.</li>
<li><code>icons.html</code>: Information regarding Settings Menu page. Added this in for standard users.</li>
<li><code>terms.html</code>: Terms of Services, AUP and Privacy Policy page.</li>
<li><code>gtools.html</code>: Games page, help from @BinBashBanana and @kinglalu.</li>
<li><code>games5.html</code>: HTML5 game navigation page.</li>
<li><code>emulators.html</code>: Emulator navigation page, using <a href="https://github.com/BinBashBanana/webretro">webretro</a>.</li>
<li><code>emulibrary.html</code>: Games page for emulated games (not included in public release)</li>
<li><code>flash.html</code>: Games page for flash games, credits given to @BinBashBanana and Titanium Network for its assets.</li>
<li><code>corrosion.html</code>: Corrosion Proxy page which features Corrosion hosted locally but can be configured to redirect to an external instance.</li>
<li><code>womginx.html</code>: Womginx Proxy page. Script links to a subdomain for Womginx, a highly fast proxy with reCaptcha and discord support.</li>
<li><code>palladium.html</code>: Palladium Proxy page.</li>
<li><code>youtube.html</code>: An proxied version of Youtube running off of the locally hosted Corrosion.</li>
<li><code>discord.html</code>: Hub for the Discord proxy.</li>
<li><code>reddit.html</code>: Hub for the Reddit proxy.</li>
<li><code>index.html</code>: The homepage of the site.</li>
<li><code>404.html</code>: The 404 page.</li>
<li><code>error.html</code>: Other errors that are not 404.</li>
<li><code>info.html</code>: Documentation (This page!)</li>
<li><code>faq.html</code>: Frequently asked questions page.</li>
<li>
<code>hidden.html</code>: Fake &quot;Site not Found&quot; page (unused)
</li>
<li><code>frame.html</code>: Handles any pages under stealth.</li>
<li>
<code>surf.html</code>: Web Proxies page, page offers to be redirected to
any proxies you would like to add. In this case, Corrosion, Womginx, and
Palladium.
</li>
<li><code>credits.html</code>: List of all contributors to the site.</li>
<li>
<code>bookmarklets.html</code>: Bookmarklets page, to be worked on more in
the future.
</li>
<li>
<code>icons.html</code>: Information regarding Settings Menu page. Added
this in for standard users.
</li>
<li>
<code>terms.html</code>: Terms of Services, AUP and Privacy Policy page.
</li>
<li>
<code>gtools.html</code>: Games page, help from @BinBashBanana and
@kinglalu.
</li>
<li><code>games5.html</code>: HTML5 game navigation page.</li>
<li>
<code>emulators.html</code>: Emulator navigation page, using
<a href="https://github.com/BinBashBanana/webretro">webretro</a>.
</li>
<li>
<code>emulibrary.html</code>: Games page for emulated games (not included in
public release)
</li>
<li>
<code>flash.html</code>: Games page for flash games, credits given to
@BinBashBanana and Titanium Network for its assets.
</li>
<li>
<code>corrosion.html</code>: Corrosion Proxy page which features Corrosion
hosted locally but can be configured to redirect to an external instance.
</li>
<li>
<code>womginx.html</code>: Womginx Proxy page. Script links to a subdomain
for Womginx, a highly fast proxy with reCaptcha and discord support.
</li>
<li><code>palladium.html</code>: Palladium Proxy page.</li>
<li>
<code>youtube.html</code>: An proxied version of Youtube running off of the
locally hosted Corrosion.
</li>
<li><code>discord.html</code>: Hub for the Discord proxy.</li>
<li><code>reddit.html</code>: Hub for the Reddit proxy.</li>
</ul>
<h3 id="structure-information">Structure Information</h3>
<ul>
<li><code>/views/</code>: The physical site base of Holy Unblocker goes here where static assets are served.</li>
<li><code>/src/</code>: For future implementation of obfuscation and keyword removing features.</li>
<li>
<code>/views/</code>: The physical site base of Holy Unblocker goes here
where static assets are served.
</li>
<li>
<code>/src/</code>: For future implementation of obfuscation and keyword
removing features.
</li>
</ul>
<h4 id="details-of-views-">Details of <code>/views/</code></h4>
<ul>
<li><code>/archive/</code> is used for game pages and vibeOS.</li>
<li><code>/pages/</code> is used for the HTML for the site.</li>
<li><code>/assets/</code> is used for various assets for CSS, JS, and images.</li>
<li><code>/archive/</code> is used for game pages and vibeOS.</li>
<li><code>/pages/</code> is used for the HTML for the site.</li>
<li>
<code>/assets/</code> is used for various assets for CSS, JS, and images.
</li>
</ul>
<h4 id="scripts-located-in-views-assets-js-">Scripts located in <code>/views/assets/js/</code></h4>
<h4 id="scripts-located-in-views-assets-js-">
Scripts located in <code>/views/assets/js/</code>
</h4>
<ul>
<li><code>common.js</code> is used on all of the pages for common useful functions.</li>
<li><code>csel.js</code> manages the settings menu on the header.</li>
<li>
<code>common.js</code> is used on all of the pages for common useful
functions.
</li>
<li><code>csel.js</code> manages the settings menu on the header.</li>
</ul>
<h2 id="future-additions">Future Additions</h2>
<ul>
<li>Expansive game library</li>
<li>Various parity changes.</li>
<li>Expansive game library</li>
<li>Various parity changes.</li>
</ul>
<h2 id="vauge-explanation-for-beginners-with-external-proxies-and-hosting">Vauge Explanation for Beginners With External Proxies and Hosting</h2>
<p>You will first want to host your proxies locally or externally. </p>
<h4 id="list-of-some-good-hosting-options-">List of some good hosting options:</h4>
<h2 id="vauge-explanation-for-beginners-with-external-proxies-and-hosting">
Vauge Explanation for Beginners With External Proxies and Hosting
</h2>
<p>You will first want to host your proxies locally or externally.</p>
<h4 id="list-of-some-good-hosting-options-">
List of some good hosting options:
</h4>
<ul>
<li><a href="https://dedipath.com">Dedipath</a> (Paid and Dedicated)</li>
<li><a href="https://heroku.com">Heroku</a> (Free)</li>
<li><a href="https://nodeclusters.com">NodeClusters</a> (Paid)</li>
<li><a href="https://glitch.com">Glitch</a> (Free)</li>
<li><a href="https://repl.it">Repl.it</a> (Free)</li>
<li><a href="https://azure.microsoft.com">Azure</a> (Free and Paid)</li>
<li><a href="https://dedipath.com">Dedipath</a> (Paid and Dedicated)</li>
<li><a href="https://heroku.com">Heroku</a> (Free)</li>
<li><a href="https://nodeclusters.com">NodeClusters</a> (Paid)</li>
<li><a href="https://glitch.com">Glitch</a> (Free)</li>
<li><a href="https://repl.it">Repl.it</a> (Free)</li>
<li><a href="https://azure.microsoft.com">Azure</a> (Free and Paid)</li>
</ul>
<p>Out of the list of hosting providers Heroku and NodeClusters rank first as a preference. You may also self-host.</p>
<p>After you have selected a decent VPS, use Cloudflare for the DNS records for both the site and the subdomains for the proxies.</p>
<p>This is an example of DNS records involving Heroku. Self-hosting will require <code>A records</code> preferably.</p>
<p><img src="/assets/img/dnssetup.png" width="500"></img></p>
<p>
Out of the list of hosting providers Heroku and NodeClusters rank first as a
preference. You may also self-host.
</p>
<p>
After you have selected a decent VPS, use Cloudflare for the DNS records for
both the site and the subdomains for the proxies.
</p>
<p>
This is an example of DNS records involving Heroku. Self-hosting will require
<code>A records</code> preferably.
</p>
<p><img src="/assets/img/dnssetup.png" width="500" /></p>
<ul>
<li><code>@</code> and <code>www.deepsoil.ml</code> are being used for the local Corrosion proxy.</li>
<li><code>p.deepsoil.ml</code> is being used for Palladium.</li>
<li><code>a.deepsoil.ml</code> is being used for womginx.</li>
<li><code>cdn.deepsoil.ml</code> is being used for a private Corrosion host on the official sites.</li>
<li>
<code>@</code> and <code>www.deepsoil.ml</code> are being used for the local
Corrosion proxy.
</li>
<li><code>p.deepsoil.ml</code> is being used for Palladium.</li>
<li><code>a.deepsoil.ml</code> is being used for womginx.</li>
<li>
<code>cdn.deepsoil.ml</code> is being used for a private Corrosion host on
the official sites.
</li>
</ul>
<p>As stated previously, Holy Unblocker is hosted locally with Corrosion.</p>
<h4 id="heroku-steps">Heroku Steps</h4>
<p>So you chose to use Heroku to host. I personally favor it as a free choice.</p>
<p>
So you chose to use Heroku to host. I personally favor it as a free choice.
</p>
<ul>
<li>First obtain a card; (Prepaid, Debit, and Credit Cards work). You need this to add custom domains to your Heroku instance.</li>
<li>
First obtain a card; (Prepaid, Debit, and Credit Cards work). You need this
to add custom domains to your Heroku instance.
</li>
</ul>
<p>Make sure you connect your Heroku app to your GitHub and enable automatic deploys. Will make things easier. :) </p>
<p>
Make sure you connect your Heroku app to your GitHub and enable automatic
deploys. Will make things easier. :)
</p>
<h4 id="freenom-domain-steps">Freenom/Domain Steps</h4>
<p>For beginners, Freenom is a good provider for obtaining domains for free. However the catch is that you can only use properly &quot;Freenom&quot; domains for free being .cf, .ml, .gq, ga and .tk. However these can be blocked rather easily.</p>
<p>
For beginners, Freenom is a good provider for obtaining domains for free.
However the catch is that you can only use properly &quot;Freenom&quot;
domains for free being .cf, .ml, .gq, ga and .tk. However these can be blocked
rather easily.
</p>
<ul>
<li>Get some Freenom domains then add them to your Heroku instance (Personal &gt; [App Name] &gt; Settings &gt; Domains) Add a domain for both <code>www.youdomainhere.cf</code> and <code>yourdomainhere.cf</code> with .cf being interchangeable with other
Freenom domain names.</li>
<li>If you prefer to obtain premium domains (TLDs) then use <a href="https://porkbun.com">Porkbun</a>, which offers domains for amazing prices. Literally a <code>.net</code> domain normally costs around $10. On Porkbun for the first year it costs $3 so
its definitely a deal.</li>
<li>
Get some Freenom domains then add them to your Heroku instance (Personal
&gt; [App Name] &gt; Settings &gt; Domains) Add a domain for both
<code>www.youdomainhere.cf</code> and <code>yourdomainhere.cf</code> with
.cf being interchangeable with other Freenom domain names.
</li>
<li>
If you prefer to obtain premium domains (TLDs) then use
<a href="https://porkbun.com">Porkbun</a>, which offers domains for amazing
prices. Literally a <code>.net</code> domain normally costs around $10. On
Porkbun for the first year it costs $3 so its definitely a deal.
</li>
</ul>
<h4 id="cloudflare-steps">Cloudflare Steps</h4>
<ul>
<li>Use Cloudflare (make an account), add your site (Freenom Domain or other) and then add your various DNS targets to Cloudflare. Make sure you add Cloudflare&#39;s Nameservers which will be given later when you are adding your site. </li>
<li>
Use Cloudflare (make an account), add your site (Freenom Domain or other)
and then add your various DNS targets to Cloudflare. Make sure you add
Cloudflare&#39;s Nameservers which will be given later when you are adding
your site.
</li>
</ul>
<p>Make sure they are CNAME although A records also work and try to follow this structure:</p>
<p>
Make sure they are CNAME although A records also work and try to follow this
structure:
</p>
<p><strong>Type | Name | Target</strong></p>
<p><code>CNAME | @ | your-main-heroku-target-here.herokudns.com</code><br><code>CNAME | www | your-main-heroku-target-here.herokudns.com</code></p>
<p><strong>Below are if you want external proxies also with your site:</strong></p>
<p><code>CNAME | p | your-palladium-instance-here.herokudns.com</code><br><code>CNAME | a | your-womginx-instance-here.herokudns.com</code><br><code>CNAME | pd | your-pydodgeb-instance-here.herokudns.com</code></p>
<p>Make sure HTTPS is forced and have SSL set to Flexible for Heroku. Otherwise you can have SSL set to Full.</p>
<p>
<code>CNAME | @ | your-main-heroku-target-here.herokudns.com</code><br /><code
>CNAME | www | your-main-heroku-target-here.herokudns.com</code
>
</p>
<p>
<strong>Below are if you want external proxies also with your site:</strong>
</p>
<p>
<code>CNAME | p | your-palladium-instance-here.herokudns.com</code><br /><code
>CNAME | a | your-womginx-instance-here.herokudns.com</code
><br /><code>CNAME | pd | your-pydodgeb-instance-here.herokudns.com</code>
</p>
<p>
Make sure HTTPS is forced and have SSL set to Flexible for Heroku. Otherwise
you can have SSL set to Full.
</p>
<h4 id="workspace-configurations">Workspace Configurations</h4>
<p>Preferably if you have your own device use Visual Studio Code. Pretty much the best option you can get but obviously this is an opinion. Also make sure you have <a href="https://nodejs.org/">Node.JS</a> installed on your machine.</p>
<p>Not going to go too in depth with this part but first fork this repository. The clone it locally through a Terminal of some sort depending on what OS you are on. Make sure you navigate to the folder you want to set this up in.</p>
<p>
Preferably if you have your own device use Visual Studio Code. Pretty much the
best option you can get but obviously this is an opinion. Also make sure you
have <a href="https://nodejs.org/">Node.JS</a> installed on your machine.
</p>
<p>
Not going to go too in depth with this part but first fork this repository.
The clone it locally through a Terminal of some sort depending on what OS you
are on. Make sure you navigate to the folder you want to set this up in.
</p>
<pre><code>git <span class="hljs-keyword">clone</span> <span class="hljs-title">https</span>://github.com/titaniumnetwork-dev/Holy-Unblocker.git
cd Holy-Unblocker
npm install
</code></pre>
<p>Now simply add the folder you cloned this repo in in <span id="vsc" style="cursor: help;">VSC</span>. Then run <code>npm install</code>. I recommend that if you are releasing this publically on GitHub that you add a <code>.gitignore</code> in your root directory with the following exclusions:</p>
<p>
Now simply add the folder you cloned this repo in in
<span id="vsc" style="cursor: help">VSC</span>. Then run
<code>npm install</code>. I recommend that if you are releasing this
publically on GitHub that you add a <code>.gitignore</code> in your root
directory with the following exclusions:
</p>
<pre><code>node_modules
</code></pre>
<p>Now you have your following workspace environment setup. To deploy the following workspace you just created you will need to look up depending on your hosting provider.</p>
<p>For an online IDE that you can use on your school computer and/or chromebook use GitPod. Basically the equivalent of Visual Studio Code but with in-browser support.</p>
<p>
Now you have your following workspace environment setup. To deploy the
following workspace you just created you will need to look up depending on
your hosting provider.
</p>
<p>
For an online IDE that you can use on your school computer and/or chromebook
use GitPod. Basically the equivalent of Visual Studio Code but with in-browser
support.
</p>
<ul>
<li>Make an account: <code>https://gitpod.io/</code></li>
<li>Fork this repo and enter in this URL to setup your workspace: <code>https://gitpod.io#https://github.com/YourNameHere/Holy-Unblocker/</code></li>
<li>Make an account: <code>https://gitpod.io/</code></li>
<li>
Fork this repo and enter in this URL to setup your workspace:
<code
>https://gitpod.io#https://github.com/YourNameHere/Holy-Unblocker/</code
>
</li>
</ul>
<p>Use the same steps above by running <code>npm install</code> in your repository and adding a <code>.gitignore</code> in your root directory specifying to exclude <code>node_modules</code>.</p>
<p>
Use the same steps above by running <code>npm install</code> in your
repository and adding a <code>.gitignore</code> in your root directory
specifying to exclude <code>node_modules</code>.
</p>
<h2 id="detailed-faq">Detailed FAQ</h2>
<p>A detailed FAQ with common issues and solutions can be found <a href="https://holyunblocker.org/questions">here</a> or on any official HU site on the FAQ page.</p>
<p>
A detailed FAQ with common issues and solutions can be found
<a href="https://holyunblocker.org/questions">here</a> or on any official HU
site on the FAQ page.
</p>
<details>
<summary>Quick FAQ</summary>
<summary>Quick FAQ</summary>
<p><strong>Why is the site I am on not working correctly or having CAPTCHA errors?</strong></p> Captcha support is currently not available on all of the current proxies sadly. Therefore some sites may not work with any of the sites. Read below for issues
with links on sites.
<p>
<strong
>Why is the site I am on not working correctly or having CAPTCHA
errors?</strong
>
</p>
Captcha support is currently not available on all of the current proxies
sadly. Therefore some sites may not work with any of the sites. Read below for
issues with links on sites.
<p><strong>Why are some page links not working or leading to 404 pages?</strong></p> This is an issue with the latest release of Alloy proxy but it may also occur with other proxies. In this case manually entering the URL of the page you would like to view
can solve this or try navigating using the home button. (Reddit, Twitter) The next release of Alloy may fix this also.
<p>
<strong
>Why are some page links not working or leading to 404 pages?</strong
>
</p>
This is an issue with the latest release of Alloy proxy but it may also occur
with other proxies. In this case manually entering the URL of the page you
would like to view can solve this or try navigating using the home button.
(Reddit, Twitter) The next release of Alloy may fix this also.
<p><strong>When using YouTube on any of the proxy sites, why does the page not load fully or the video is just white?</strong></p> There are two methods for fixing this: - Reloading the page normally when the error above happens should load the video. -
Or right-clicking the page and doing Reload Frame if you are using some form of Stealth Mode.
<p>
<strong
>When using YouTube on any of the proxy sites, why does the page not load
fully or the video is just white?</strong
>
</p>
There are two methods for fixing this: - Reloading the page normally when the
error above happens should load the video. - Or right-clicking the page and
doing Reload Frame if you are using some form of Stealth Mode.
<p><strong>When using Discord under Alloy or SysYa, why does the page stay gray/white or the QR code not load?</strong></p> Once again do the same steps above: - Reloading the page normally when the error above happens should load the video - Or right-clicking
the page and doing Reload Frame if you are using some form of Stealth Mode. Make sure you are also doing the steps correctly. Simply view link above for extended Discord proxy information/steps.
<p><strong>I am getting 502 errors. What do I do?</strong></p> When this happens you may either switch sites to fix the error or wait a bit. Sometimes clearing your cache can help. If you still have any questions feel free to ask them in the discord linked
here.
<p>
<strong
>When using Discord under Alloy or SysYa, why does the page stay
gray/white or the QR code not load?</strong
>
</p>
Once again do the same steps above: - Reloading the page normally when the
error above happens should load the video - Or right-clicking the page and
doing Reload Frame if you are using some form of Stealth Mode. Make sure you
are also doing the steps correctly. Simply view link above for extended
Discord proxy information/steps.
<p><strong>I am getting 502 errors. What do I do?</strong></p>
When this happens you may either switch sites to fix the error or wait a bit.
Sometimes clearing your cache can help. If you still have any questions feel
free to ask them in the discord linked here.
</details>
<h2 id="more-information">More Information</h2>
<p>This project is maintained by Quite A Fancy Emerald with massive help from BinBashBanana (OlyB) and is an official flagship Titanium Network proxy site.</p>
<p>
This project is maintained by Quite A Fancy Emerald with massive help from
BinBashBanana (OlyB) and is an official flagship Titanium Network proxy site.
</p>
<ul>
<li><a href="https://github.com/titaniumnetwork-dev/Holy-Unblocker">GitHub link</a></li>
<li><a href="https://github.com/titaniumnetwork-dev/">https://github.com/titaniumnetwork-dev/</a></li>
<li><a href="https://titaniumnetwork.org/">https://titaniumnetwork.org/</a></li>
<li>
<a href="https://github.com/titaniumnetwork-dev/Holy-Unblocker"
>GitHub link</a
>
</li>
<li>
<a href="https://github.com/titaniumnetwork-dev/"
>https://github.com/titaniumnetwork-dev/</a
>
</li>
<li>
<a href="https://titaniumnetwork.org/">https://titaniumnetwork.org/</a>
</li>
</ul>
<p>View the official website for more detail and credits.</p>
<h3 id="proxy-sources-">Proxy Sources:</h3>
<p>This project currently uses Corrosion, Womginx, and Palladium, linked below.</p>
<p>
This project currently uses Corrosion, Womginx, and Palladium, linked below.
</p>
<ul>
<li><a href="https://github.com/titaniumnetwork-dev/Corrosion">Corrosion</a></li>
<li><a href="https://github.com/binary-person/womginx">Womginx</a></li>
<li><a href="https://github.com/LudicrousDevelopment/Palladium">Palladium</a></li>
<li><a href="https://github.com/BinBashBanana/PyDodge">PyDodge</a></li>
<li>
<a href="https://github.com/titaniumnetwork-dev/Corrosion">Corrosion</a>
</li>
<li><a href="https://github.com/binary-person/womginx">Womginx</a></li>
<li>
<a href="https://github.com/LudicrousDevelopment/Palladium">Palladium</a>
</li>
<li><a href="https://github.com/BinBashBanana/PyDodge">PyDodge</a></li>
</ul>
<h3 id="other-">Other:</h3>
<ul>
<li><a href="https://github.com/vibedivide/vibeOS">vibeOS</a></li>
<li><a href="https://github.com/BinBashBanana/webretro">webretro</a></li>
<li><a href="https://ruffle.rs/">Ruffle</a></li>
<li><a href="https://github.com/BlaNKtext/webosu">webosu</a></li>
<li><a href="https://github.com/vibedivide/vibeOS">vibeOS</a></li>
<li><a href="https://github.com/BinBashBanana/webretro">webretro</a></li>
<li><a href="https://ruffle.rs/">Ruffle</a></li>
<li><a href="https://github.com/BlaNKtext/webosu">webosu</a></li>
</ul>
<h3 id="notable-mentions-">Notable Mentions:</h3>
<ul>
<li><a href="https://soyoustart.com/">SoYouStart / OVH</a> (Hosting Provider)</li>
<li>
<a href="https://soyoustart.com/">SoYouStart / OVH</a> (Hosting Provider)
</li>
</ul>
<p>Thanks :D</p>

View file

@ -23,7 +23,7 @@
<a id="iconfinder" class="fancybutton fb-l glowbutton">Find Icon URL</a>
</div>
<script>
document.getElementById("iconfinder").href =
document.getElementById('iconfinder').href =
`javascript:alert((Array.from(document.head.querySelectorAll("link[rel*='icon']")).slice(-1)[0]||0).href||location.origin+"/favicon.ico")`;
</script>
<p>

View file

@ -7,111 +7,143 @@
<div class="footerlist">
<h3>Dependencies</h3>
<ul>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/github/fastify"
title="Fastify - Fast and low overhead web framework, for Node.js "
>Fastify</a
></li>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/github/nord-theme"
title="Nord Theme - An arctic, north-bluish color palette."
>Nord Theme</a
></li>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/github/aos"
title="AOS - Animate on scroll library "
>AOS</a
></li>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/github/font-awesome"
title="Font Awesome - The iconic SVG, font, and CSS toolkit"
>Font Awesome </a
></li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/github/fastify"
title="Fastify - Fast and low overhead web framework, for Node.js "
>Fastify</a
>
</li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/github/nord-theme"
title="Nord Theme - An arctic, north-bluish color palette."
>Nord Theme</a
>
</li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/github/aos"
title="AOS - Animate on scroll library "
>AOS</a
>
</li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/github/font-awesome"
title="Font Awesome - The iconic SVG, font, and CSS toolkit"
>Font Awesome
</a>
</li>
</ul>
</div>
<div class="footerlist">
<h3>Transports</h3>
<ul>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/github/epoxy"
title="Epoxy - Epoxy is an encrypted proxy for browser javascript. It allows you to make requests that bypass CORS without compromising security, by running SSL/TLS inside webassembly."
>Epoxy</a
></li>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/github/libcurl-js"
title="A port of libcurl to WebAssembly, for proxying HTTPS requests from the browser with full TLS encryption"
>Libcurl</a
></li>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/github/bare-module"
title="Bare Module - Tomp Bare Client as a bare-mux module"
>Bare Module</a
></li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/github/epoxy"
title="Epoxy - Epoxy is an encrypted proxy for browser javascript. It allows you to make requests that bypass CORS without compromising security, by running SSL/TLS inside webassembly."
>Epoxy</a
>
</li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/github/libcurl-js"
title="A port of libcurl to WebAssembly, for proxying HTTPS requests from the browser with full TLS encryption"
>Libcurl</a
>
</li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/github/bare-module"
title="Bare Module - Tomp Bare Client as a bare-mux module"
>Bare Module</a
>
</li>
</ul>
</div>
<div class="footerlist">
<h3>Services</h3>
<ul>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/github/ultraviolet"
title="Ultraviolet - Explore Ultraviolet"
>Ultraviolet</a
></li>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/github/wisp"
title="Wisp - Wisp is a low-overhead, easy to implement protocol for proxying multiple TCP/UDP sockets over a single websocket. "
>Wisp Protocol</a
></li>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/rammerhead-discord"
title="Rammerhead - Join Rammerhead on Discord"
>Rammerhead</a
></li>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/github/bare-mux"
title="BareMux - A system for managing http transports in a project such as Ultraviolet"
>Bare-Mux</a
></li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/github/ultraviolet"
title="Ultraviolet - Explore Ultraviolet"
>Ultraviolet</a
>
</li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/github/wisp"
title="Wisp - Wisp is a low-overhead, easy to implement protocol for proxying multiple TCP/UDP sockets over a single websocket. "
>Wisp Protocol</a
>
</li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/rammerhead-discord"
title="Rammerhead - Join Rammerhead on Discord"
>Rammerhead</a
>
</li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/github/bare-mux"
title="BareMux - A system for managing http transports in a project such as Ultraviolet"
>Bare-Mux</a
>
</li>
</ul>
</div>
<div class="footerlist">
<h3>About</h3>
<ul>
<li><a
target="_blank"
rel="noopener noreferrer"
href="/github"
title="Holy Unblocker GitHub Repository"
>GitHub</a
></li>
<li><a href="/terms" title="Privacy Policy and Terms of Service">Privacy and Terms of Service</a></li>
<li><a href="/credits" title="Credits and Acknowledgements">Credits</a></li>
<li>
<a
target="_blank"
rel="noopener noreferrer"
href="/github"
title="Holy Unblocker GitHub Repository"
>GitHub</a
>
</li>
<li>
<a href="/terms" title="Privacy Policy and Terms of Service"
>Privacy and Terms of Service</a
>
</li>
<li>
<a href="/credits" title="Credits and Acknowledgements">Credits</a>
</li>
</ul>
</div>
<div class="footerlist">
<a href="#header" title="Back to Top"><i class="fas fa-angle-double-up" aria-hidden="true"></i></a>
<a href="#header" title="Back to Top"
><i class="fas fa-angle-double-up" aria-hidden="true"></i
></a>
</div>
</div>
<div class="footersocials">

View file

@ -1,20 +1,38 @@
<div class="brand-logo-container" aria-label="Brand Logo">
<div class="logo" role="img" aria-label="Holy Unblocker Logo"></div>
<a href="/" class="brand pulse" title="Holy Unblocker Home Page">Holy Unblocker v6.3.x</a>
<a href="/" class="brand pulse" title="Holy Unblocker Home Page"
>Holy Unblocker v6.3.x</a
>
</div>
<ul class="navbar-1" role="list" aria-label="Primary navigation">
<li class="pulse" style="margin-left: 0;" role="listitem">
<a href="/browsing" title="Web Proxies - Access various web proxies to bypass restrictions">Web Proxies</a>
<li class="pulse" style="margin-left: 0" role="listitem">
<a
href="/browsing"
title="Web Proxies - Access various web proxies to bypass restrictions"
>Web Proxies</a
>
</li>
<li class="pulse" role="listitem">
<a href="/games" title="Games - Explore a range of games available through our service">Games</a>
<a
href="/games"
title="Games - Explore a range of games available through our service"
>Games</a
>
</li>
<li class="pulse" role="listitem">
<a href="/youtube" title="YouTube - Access YouTube content through our proxy service">YouTube</a>
<a
href="/youtube"
title="YouTube - Access YouTube content through our proxy service"
>YouTube</a
>
</li>
<li class="pulse new" role="listitem">
<a href="/apps" title="Applications - Browse a selection of useful applications">Applications</a>
<a
href="/apps"
title="Applications - Browse a selection of useful applications"
>Applications</a
>
</li>
</ul>
@ -26,33 +44,65 @@
<ul class="navbar" role="list" aria-label="Secondary navigation">
<li class="dropdown-parent" role="listitem">
<div class="pulse white-text" aria-haspopup="true" aria-expanded="false">
<a href="#" aria-label="More options">More <i class="fas fa-ellipsis-v" aria-hidden="true"></i></a>
<a href="#" aria-label="More options"
>More <i class="fas fa-ellipsis-v" aria-hidden="true"></i
></a>
</div>
<div class="dropdown-child" tabindex="0" role="menu" aria-label="More options submenu">
<div
class="dropdown-child"
tabindex="0"
role="menu"
aria-label="More options submenu"
>
<ul class="subnavbar" role="menu">
<li role="menuitem">
<a href="/bookmarklets" title="Bookmarklets - Useful tools and shortcuts for your browser">Bookmarklets</a>
<a
href="/bookmarklets"
title="Bookmarklets - Useful tools and shortcuts for your browser"
>Bookmarklets</a
>
</li>
<li role="menuitem">
<a href="/?documentation" title="Documentation - Detailed information and guides">Docs</a>
<a
href="/?documentation"
title="Documentation - Detailed information and guides"
>Docs</a
>
</li>
<li role="menuitem">
<a href="/questions" title="FAQ - Frequently asked questions and answers">FAQ</a>
<a
href="/questions"
title="FAQ - Frequently asked questions and answers"
>FAQ</a
>
</li>
<li role="menuitem">
<a href="/credits" title="Credits - Acknowledgements and contributions">Credits</a>
<a
href="/credits"
title="Credits - Acknowledgements and contributions"
>Credits</a
>
</li>
<li role="menuitem">
<a href="/terms" title="Terms of Service - Rules and policies of use">TOS</a>
<a href="/terms" title="Terms of Service - Rules and policies of use"
>TOS</a
>
</li>
</ul>
</div>
</li>
<li class="dropdown-parent" role="listitem">
<div class="pulse white-text" aria-haspopup="true" aria-expanded="false">
<a href="#" aria-label="Settings menu">Settings <i class="fas fa-cog pulse" aria-hidden="true"></i></a>
<a href="#" aria-label="Settings menu"
>Settings <i class="fas fa-cog pulse" aria-hidden="true"></i
></a>
</div>
<div class="dropdown-settings" tabindex="0" role="menu" aria-label="Settings menu">
<div
class="dropdown-settings"
tabindex="0"
role="menu"
aria-label="Settings menu"
>
<div id="csel"><!--SETTINGS--></div>
</div>
</li>

View file

@ -1,85 +1,91 @@
<div id="csel" class="settings-content">
<div class="settings-header">
<p class="cseltitle-main">Settings</p>
<i class="far fa-times-circle close-settings-btn"></i>
<p class="cseltitle-main">Settings</p>
<i class="far fa-times-circle close-settings-btn"></i>
</div>
<div class="settings-content-body">
<div class="csel-container-left">
<p class="cseltitle">Tab Cloak</p>
<form id="titleform" class="cloakform">
<input type="text" placeholder="Tab Title" spellcheck="false">
<input type="submit" value="Apply">
</form>
<form id="iconform" class="cloakform">
<input type="text" placeholder="Icon URL" spellcheck="false">
<input type="submit" value="Apply">
</form>
<p class="cseltitle">Ultraviolet Proxy Transport</p>
<div class="radio-group" id=uv-transport-list>
<label>
<p>Libcurl <span class="default-badge">Cross-Browser/Secure (Firefox)</span></p>
<input type="radio" name="uv-transport" value="libcurl" checked>
</label>
<label>
<p>Epoxy <span class="bare-badge">Fastest/Secure (Chromium, Apple)</span></p>
<input type="radio" name="uv-transport" value="epoxy">
</label>
<label>
<p>Bare <span class="beta-badge">Least Secure (All)</span></p>
<input type="radio" name="uv-transport" value="bare">
</label>
</div>
<p class="cseltitle">Advanced Options</p>
<div class="radio-group">
<label>
<p>Hide Ads <span class="default-badge">AdGuard</span></p>
<input type="checkbox" id="hideads" class="switch" checked>
</label>
<label>
<p>Enable Tor <span class="bare-badge">SOCKS5 Onion Routing</span></p>
<input type="checkbox" id="useonion" class="switch">
</label>
</div>
<div class="csel-container-left">
<p class="cseltitle">Tab Cloak</p>
<form id="titleform" class="cloakform">
<input type="text" placeholder="Tab Title" spellcheck="false" />
<input type="submit" value="Apply" />
</form>
<form id="iconform" class="cloakform">
<input type="text" placeholder="Icon URL" spellcheck="false" />
<input type="submit" value="Apply" />
</form>
<p class="cseltitle">Ultraviolet Proxy Transport</p>
<div class="radio-group" id="uv-transport-list">
<label>
<p>
Libcurl
<span class="default-badge">Cross-Browser/Secure (Firefox)</span>
</p>
<input type="radio" name="uv-transport" value="libcurl" checked />
</label>
<label>
<p>
Epoxy
<span class="bare-badge">Fastest/Secure (Chromium, Apple)</span>
</p>
<input type="radio" name="uv-transport" value="epoxy" />
</label>
<label>
<p>Bare <span class="beta-badge">Least Secure (All)</span></p>
<input type="radio" name="uv-transport" value="bare" />
</label>
</div>
<div class="settings-right-column">
<p class="cseltitle">Search Engine</p>
<select>
<option>Google</option>
<option>Bing</option>
<option>DuckDuckGo</option>
<option>Yahoo</option>
</select>
<p class="cseltitle">About:Blank</p>
<div class="switch-container">
<p>Stealth Tab <span class="default-badge">Default</span></p>
<input type="checkbox" class="switch">
</div>
<p class="cseltitle">Select Theme</p>
<div class="radio-group">
<label>
<p>Light</p>
<input type="radio" name="theme" value="lighttheme" checked>
</label>
<label>
<p>Dark</p>
<input type="radio" name="theme" value="darktheme">
</label>
</div>
<p class="cseltitle">Icon Presets</p>
<select id=icon-list>
<option><!-- Leave this blank to avoid a bug. --></option>
<option>Google</option>
<option>Bing</option>
<option>Google Drive</option>
<option>Gmail</option>
</select>
<p class="cseltitle">Enable Devtools</p>
<div class="radio-group">
<label>
<p>Eruda Devtools<span class="bare-badge">CTRL+SHIFT+I</span></p>
<input type="radio" name="theme" value="lighttheme" checked>
</label>
</div>
<p class="cseltitle">Advanced Options</p>
<div class="radio-group">
<label>
<p>Hide Ads <span class="default-badge">AdGuard</span></p>
<input type="checkbox" id="hideads" class="switch" checked />
</label>
<label>
<p>Enable Tor <span class="bare-badge">SOCKS5 Onion Routing</span></p>
<input type="checkbox" id="useonion" class="switch" />
</label>
</div>
</div>
<div class="settings-right-column">
<p class="cseltitle">Search Engine</p>
<select>
<option>Google</option>
<option>Bing</option>
<option>DuckDuckGo</option>
<option>Yahoo</option>
</select>
<p class="cseltitle">About:Blank</p>
<div class="switch-container">
<p>Stealth Tab <span class="default-badge">Default</span></p>
<input type="checkbox" class="switch" />
</div>
<p class="cseltitle">Select Theme</p>
<div class="radio-group">
<label>
<p>Light</p>
<input type="radio" name="theme" value="lighttheme" checked />
</label>
<label>
<p>Dark</p>
<input type="radio" name="theme" value="darktheme" />
</label>
</div>
<p class="cseltitle">Icon Presets</p>
<select id="icon-list">
<option><!-- Leave this blank to avoid a bug. --></option>
<option>Google</option>
<option>Bing</option>
<option>Google Drive</option>
<option>Gmail</option>
</select>
<p class="cseltitle">Enable Devtools</p>
<div class="radio-group">
<label>
<p>Eruda Devtools<span class="bare-badge">CTRL+SHIFT+I</span></p>
<input type="radio" name="theme" value="lighttheme" checked />
</label>
</div>
</div>
</div>
</div>

View file

@ -36,7 +36,7 @@
<div id="particles-js" class="fullwidth"></div>
<div id="mainbody" class="fullwidth">
<div class="box-g text-center textm">
<div id=emu-nav class=glist></div>
<div id="emu-nav" class="glist"></div>
<div class="gfooter">
<p>I promise I'll fix N64 and add DS soon ._.</p>
</div>

View file

@ -36,7 +36,7 @@
<div id="particles-js" class="fullwidth"></div>
<div id="mainbody" class="fullwidth">
<div class="box-g text-center textm">
<div id=emulib-nav class=glist></div>
<div id="emulib-nav" class="glist"></div>
<div class="gfooter">
<p>
Have a game request? Contact us on <a id="tnlink">discord</a> or

View file

@ -44,7 +44,7 @@
autocomplete="off"
placeholder="Search"
/>
<div id=flash-nav class=flist></div>
<div id="flash-nav" class="flist"></div>
<div class="gfooter-only">
<p>
Have a game request? Contact us on <a id="tnlink">discord</a> or

View file

@ -40,7 +40,7 @@
<div id="particles-js" class="fullwidth"></div>
<div id="mainbody" class="fullwidth">
<div class="box-g text-center textm">
<div id=h5-nav class=glist></div>
<div id="h5-nav" class="glist"></div>
<div class="gfooter">
<p>
Have a game request? Contact us on <a id="tnlink">discord</a> or

View file

@ -49,7 +49,7 @@
>
</div>
<script>
document.getElementById("iconfinder").href =
document.getElementById('iconfinder').href =
`javascript:alert((Array.from(document.head.querySelectorAll("link[rel*='icon']")).slice(-1)[0]||0).href||location.origin+"/favicon.ico")`;
</script>
<p>

View file

@ -90,13 +90,24 @@
</ul>
</div>
<div>
<div id=pr-rh-dc>
<a href="#" class="fancybutton glowbutton pr-go1">Ra&#173;mmer&#173;head (Classic)</a>
<a href="#" class="fancybutton glowbutton pr-go2">Ra&#173;mmer&#173;head (Stealth)</a>
<div id="pr-rh-dc">
<a href="#" class="fancybutton glowbutton pr-go1"
>Ra&#173;mmer&#173;head (Classic)</a
>
<a href="#" class="fancybutton glowbutton pr-go2"
>Ra&#173;mmer&#173;head (Stealth)</a
>
</div>
<div id=pr-uv-dc>
<a href="#" style="display:none;" class="fancybutton glowbutton pr-go1">Ultr&#173;av&#173;iol&#173;et (Classic)</a>
<a href="#" class="fancybutton glowbutton pr-go2">Ultr&#173;avi&#173;ole&#173;t (Stealth)</a>
<div id="pr-uv-dc">
<a
href="#"
style="display: none"
class="fancybutton glowbutton pr-go1"
>Ultr&#173;av&#173;iol&#173;et (Classic)</a
>
<a href="#" class="fancybutton glowbutton pr-go2"
>Ultr&#173;avi&#173;ole&#173;t (Stealth)</a
>
</div>
</div>
</div>

View file

@ -57,8 +57,13 @@
<br />Sometimes the proxies are under high load so things may be slow,
sorry. In that case simply wait for the page to load.
</p>
<div id=pr-yt class="responsive-fix">
<a href="#" style="display:none;" class="fancybutton glowbutton pr-go1">Classic</a>
<div id="pr-yt" class="responsive-fix">
<a
href="#"
style="display: none"
class="fancybutton glowbutton pr-go1"
>Classic</a
>
<a href="#" class="fancybutton glowbutton pr-go2">Stealth</a>
</div>
</div>

View file

@ -50,7 +50,7 @@
Its session-based proxying concept enables much support for webites
like Discord, YouTube, and more!
</p>
<div id=pr-rh class="pr-form">
<div id="pr-rh" class="pr-form">
<input
type="text"
spellcheck="false"

View file

@ -55,15 +55,17 @@
such as service workers and sophisticated rewriting techniques with
CAPTCHA support.
</p>
<div id=pr-uv class="pr-form">
<div id="pr-uv" class="pr-form">
<input
type="text"
spellcheck="false"
autocomplete="off"
placeholder="Search or enter in a target site!"
/>
<a href="#" style="display:none;" class="pr-button glowbutton pr-go1">Stea&#173;lth</a>
<a href="#"" class="pr-button glowbutton pr-go2">Stea&#173;lth</a>
<a href="#" style="display: none" class="pr-button glowbutton pr-go1"
>Stea&#173;lth</a
>
<a href="#" class="pr-button glowbutton pr-go2">Stea&#173;lth</a>
</div>
<h3>More Information:</h3>
<div class="font3">

View file

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<meta charset="utf-8" />

View file

@ -7,6 +7,6 @@
class WWError extends Error {
constructor(message) {
super(message);
this.name = "[WorkerWare Exception]";
this.name = '[WorkerWare Exception]';
}
}

View file

@ -1,6 +1,6 @@
importScripts("/uv/uv.bundle.js");
importScripts("/uv/uv.config.js");
importScripts(__uv$config.sw || "/uv/uv.sw.js");
importScripts('/uv/uv.bundle.js');
importScripts('/uv/uv.config.js');
importScripts(__uv$config.sw || '/uv/uv.sw.js');
/*
@ -28,53 +28,54 @@ ww.use({
*/
const uv = new UVServiceWorker();
// Get list of blacklisted domains.
const blacklist = {};
fetch("/assets/json/blacklist.json").then(request => {
request.json().then(jsonData => {
fetch('/assets/json/blacklist.json').then((request) => {
request.json().then((jsonData) => {
// Organize each domain by their tld (top level domain) ending.
jsonData.forEach((domain) => {
const domainTld = domain.replace(/.+(?=\.\w)/, '');
if (!blacklist.hasOwnProperty(domainTld)) blacklist[domainTld] = [];
// Organize each domain by their tld (top level domain) ending.
jsonData.forEach(domain => {
const domainTld = domain.replace(/.+(?=\.\w)/, "");
if (!blacklist.hasOwnProperty(domainTld))
blacklist[domainTld] = [];
// Store each entry in an array. Each tld has its own array, which will
// later be concatenated into a regular expression.
// Store each entry in an array. Each tld has its own array, which will
// later be concatenated into a regular expression.
blacklist[domainTld].push(
encodeURIComponent(domain.slice(0, -domainTld.length))
.replace(/([()])/g, "\\$1")
.replace(/(\*\.)|\./g, (match, firstExpression) =>
firstExpression ? "(?:.+\\.)?" : "\\" + match)
.replace(/([()])/g, '\\$1')
.replace(/(\*\.)|\./g, (match, firstExpression) =>
firstExpression ? '(?:.+\\.)?' : '\\' + match
)
);
});
// Turn each domain list into a regular expression and prevent this
// from being accidentally modified afterward.
// Turn each domain list into a regular expression and prevent this
// from being accidentally modified afterward.
for (let [domainTld, domainList] of Object.entries(blacklist))
blacklist[domainTld] = new RegExp(`^(?:${domainList.join("|")})$`);
blacklist[domainTld] = new RegExp(`^(?:${domainList.join('|')})$`);
Object.freeze(blacklist);
});
});
self.addEventListener("fetch", (event) => {
self.addEventListener('fetch', (event) => {
event.respondWith(
(async () => {
if (uv.route(event)) {
// The one and only ghetto domain blacklist.
const domain = new URL(uv.config.decodeUrl(
new URL(event.request.url).pathname
.replace(uv.config.prefix, "")
)).hostname,
domainTld = domain.replace(/.+(?=\.\w)/, "");
// The one and only ghetto domain blacklist.
const domain = new URL(
uv.config.decodeUrl(
new URL(event.request.url).pathname.replace(uv.config.prefix, '')
)
).hostname,
domainTld = domain.replace(/.+(?=\.\w)/, '');
// If the domain is in the blacklist, return a 406 response code.
if (blacklist.hasOwnProperty(domainTld) &&
blacklist[domainTld].test(domain.slice(0, -domainTld.length)))
return new Response(new Blob(), {status: 406});
// If the domain is in the blacklist, return a 406 response code.
if (
blacklist.hasOwnProperty(domainTld) &&
blacklist[domainTld].test(domain.slice(0, -domainTld.length))
)
return new Response(new Blob(), { status: 406 });
return await uv.fetch(event);
}

View file

@ -1,11 +1,10 @@
importScripts("/uv/uv.bundle.js");
importScripts("/uv/uv.config.js");
importScripts(__uv$config.sw || "/uv/uv.sw.js");
importScripts('/uv/uv.bundle.js');
importScripts('/uv/uv.config.js');
importScripts(__uv$config.sw || '/uv/uv.sw.js');
const uv = new UVServiceWorker();
self.addEventListener("fetch", (event) => {
self.addEventListener('fetch', (event) => {
event.respondWith(
(async () => {
if (uv.route(event)) return await uv.fetch(event);

View file

@ -1,12 +1,12 @@
// This file overwrites the stock UV config.js
self.__uv$config = {
prefix: "/uv/service/",
prefix: '/uv/service/',
encodeUrl: Ultraviolet.codec.xor.encode,
decodeUrl: Ultraviolet.codec.xor.decode,
handler: "/uv/uv.handler.js",
client: "/uv/uv.client.js",
bundle: "/uv/uv.bundle.js",
config: "/uv/uv.config.js",
sw: "/uv/uv.sw.js",
handler: '/uv/uv.handler.js',
client: '/uv/uv.client.js',
bundle: '/uv/uv.bundle.js',
config: '/uv/uv.config.js',
sw: '/uv/uv.sw.js',
};

View file

@ -4,10 +4,10 @@
/* Service Worker Middleware Script
/* ----------------------------------------------- */
importScripts("./WWError.js");
const dbg = console.log.bind(console, "[WorkerWare]");
const time = console.time.bind(console, "[WorkerWare]");
const timeEnd = console.timeEnd.bind(console, "[WorkerWare]");
importScripts('./WWError.js');
const dbg = console.log.bind(console, '[WorkerWare]');
const time = console.time.bind(console, '[WorkerWare]');
const timeEnd = console.timeEnd.bind(console, '[WorkerWare]');
/*
OPTS:
@ -23,26 +23,26 @@ const defaultOpt = {
};
const validEvents = [
"abortpayment",
"activate",
"backgroundfetchabort",
"backgroundfetchclick",
"backgroundfetchfail",
"backgroundfetchsuccess",
"canmakepayment",
"contentdelete",
"cookiechange",
"fetch",
"install",
"message",
"messageerror",
"notificationclick",
"notificationclose",
"paymentrequest",
"periodicsync",
"push",
"pushsubscriptionchange",
"sync",
'abortpayment',
'activate',
'backgroundfetchabort',
'backgroundfetchclick',
'backgroundfetchfail',
'backgroundfetchsuccess',
'canmakepayment',
'contentdelete',
'cookiechange',
'fetch',
'install',
'message',
'messageerror',
'notificationclick',
'notificationclose',
'paymentrequest',
'periodicsync',
'push',
'pushsubscriptionchange',
'sync',
];
class WorkerWare {
@ -52,7 +52,7 @@ class WorkerWare {
}
info() {
return {
version: "0.1.0",
version: '0.1.0',
middlewares: this._middlewares,
options: this._opt,
};
@ -61,10 +61,11 @@ class WorkerWare {
let validateMW = this.validateMiddleware(middleware);
if (validateMW.error) throw new WWError(validateMW.error);
// This means the middleware is an anonymous function, or the user is silly and named their function "function"
if (middleware.function.name == "function") middleware.name = crypto.randomUUID();
if (middleware.function.name == 'function')
middleware.name = crypto.randomUUID();
if (!middleware.name) middleware.name = middleware.function.name;
if (this._opt.randomNames) middleware.name = crypto.randomUUID();
if (this._opt.debug) dbg("Adding middleware:", middleware.name);
if (this._opt.debug) dbg('Adding middleware:', middleware.name);
this._middlewares.push(middleware);
}
// Run all middlewares for the event type passed in.
@ -91,12 +92,16 @@ class WorkerWare {
return fn;
}
deleteByName(middlewareID) {
if (this._opt.debug) dbg("Deleting middleware:", middlewareID);
this._middlewares = this._middlewares.filter((mw) => mw.name !== middlewareID);
if (this._opt.debug) dbg('Deleting middleware:', middlewareID);
this._middlewares = this._middlewares.filter(
(mw) => mw.name !== middlewareID
);
}
deleteByEvent(middlewareEvent) {
if (this._opt.debug) dbg("Deleting middleware by event:", middlewareEvent);
this._middlewares = this._middlewares.filter((mw) => !mw.events.includes(middlewareEvent));
if (this._opt.debug) dbg('Deleting middleware by event:', middlewareEvent);
this._middlewares = this._middlewares.filter(
(mw) => !mw.events.includes(middlewareEvent)
);
}
get() {
return this._middlewares;
@ -107,7 +112,7 @@ class WorkerWare {
*/
runMW(name, event) {
const middlewares = this._middlewares;
if (this._opt.debug) dbg("Running middleware:", name);
if (this._opt.debug) dbg('Running middleware:', name);
// if (middlewares.includes(name)) {
// return middlewares[name](event);
// } else {
@ -119,7 +124,7 @@ class WorkerWare {
didCall = true;
event.workerware = {
config: middlewares[i].configuration || {},
}
};
if (this._opt.timing) console.time(middlewares[i].name);
let call = middlewares[i].function(event);
if (this._opt.timing) console.timeEnd(middlewares[i].name);
@ -127,7 +132,7 @@ class WorkerWare {
}
}
if (!didCall) {
throw new WWError("Middleware not found!");
throw new WWError('Middleware not found!');
}
}
// type middlewareManifest = {
@ -139,32 +144,40 @@ class WorkerWare {
validateMiddleware(middleware) {
if (!middleware.function)
return {
error: "middleware.function is required",
error: 'middleware.function is required',
};
if (typeof middleware.function !== "function")
if (typeof middleware.function !== 'function')
return {
error: "middleware.function must be typeof function",
error: 'middleware.function must be typeof function',
};
if (typeof middleware.configuration !== "object" && middleware.configuration !== undefined) {
if (
typeof middleware.configuration !== 'object' &&
middleware.configuration !== undefined
) {
return {
error: "middleware.configuration must be typeof object",
error: 'middleware.configuration must be typeof object',
};
}
if (!middleware.events)
return {
error: "middleware.events is required",
error: 'middleware.events is required',
};
if (!Array.isArray(middleware.events))
return {
error: "middleware.events must be an array",
error: 'middleware.events must be an array',
};
if (middleware.events.some((ev) => !validEvents.includes(ev)))
return {
error: "Invalid event type! Must be one of the following: " + validEvents.join(", "),
error:
'Invalid event type! Must be one of the following: ' +
validEvents.join(', '),
};
if (middleware.explicitCall && typeof middleware.explicitCall !== "boolean") {
if (
middleware.explicitCall &&
typeof middleware.explicitCall !== 'boolean'
) {
return {
error: "middleware.explicitCall must be typeof boolean",
error: 'middleware.explicitCall must be typeof boolean',
};
}
return {