Compare commits
36 commits
master
...
v6.3_produ
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb6c24073d |
||
|
|
2c555a8aa4 |
||
|
|
8f87b56886 |
||
|
|
0778ecbf83 |
||
|
|
32706dd9be |
||
|
|
dc0ff7890b |
||
|
|
961f58af56 |
||
|
|
63a2514dd4 |
||
|
|
4558af2efd |
||
|
|
898c313019 |
||
|
|
8a23d2ad0d |
||
|
|
253f457ba0 |
||
|
|
673c0a37d2 |
||
|
|
35c8b25235 | ||
|
|
df1e03d2c6 |
||
|
|
4645b0140e |
||
|
|
fca2563b15 |
||
|
|
cf8e5d75e4 |
||
|
|
6126f9f74e | ||
|
|
94ba8bce08 | ||
|
|
fa0f0065d0 | ||
|
|
eb7a998a33 | ||
|
|
107b75aca0 | ||
|
|
060a69a9d1 | ||
|
|
25dbf27768 | ||
|
|
b6f976e6ff | ||
|
|
bed7aac10d |
||
|
|
f3ca425a70 |
||
|
|
c71ca40c3d |
||
|
|
53d24d5eda |
||
|
|
7babbc02f7 |
||
|
|
e071a7397e |
||
|
|
dac476fc69 |
||
|
|
2b9c9779fd |
||
|
|
4cb02710e6 |
||
|
|
1e277b2d19 |
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Holy Unblocker LTS",
|
||||
"image": "mcr.microsoft.com/devcontainers/javascript-node:0-20",
|
||||
"image": "mcr.microsoft.com/devcontainers/javascript-node:0-20",
|
||||
"features": {
|
||||
"node": "20"
|
||||
"node": "20"
|
||||
},
|
||||
"postCreateCommand": "npm install"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
node_modules
|
||||
.gitpod.yml
|
||||
.vscode
|
||||
.gitattributes
|
||||
.well-known
|
||||
views/archive
|
||||
ngrok.exe
|
||||
pnpm-lock.yaml
|
||||
debug.log
|
||||
lib/rammerhead/sessions/*
|
||||
!lib/rammerhead/sessions/.gitkeep
|
||||
lib/rammerhead/cache-js/*
|
||||
!lib/rammerhead/cache-js/.gitkeep
|
||||
views/dist/*
|
||||
src/.shutdown
|
||||
lib/rammerhead/src/client/hammerhead.min.js
|
||||
lib/rammerhead/src/client/rammerhead.min.js
|
||||
views/archive/gfiles/rarch/roms
|
||||
.idea
|
||||
2
.github/FUNDING.yml
vendored
|
|
@ -1,7 +1,7 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: holyunblockerlts
|
||||
patreon: #
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
|
|
|
|||
2
.github/workflows/ci-windows.yml
vendored
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
node-version: '20.8.0'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm run fresh-install
|
||||
run: npm install
|
||||
|
||||
- name: Build libraries
|
||||
run: npm run build
|
||||
|
|
|
|||
7
.github/workflows/ci.yml
vendored
|
|
@ -20,16 +20,11 @@ jobs:
|
|||
node-version: '20.8.0'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm run fresh-install
|
||||
run: npm install
|
||||
|
||||
- name: Build libraries
|
||||
run: npm run build
|
||||
|
||||
- name: Allow AppArmor sandbox to work on Ubuntu
|
||||
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
|
||||
# A safer option to fix sandboxes if Chrome is installed on a local client:
|
||||
# echo -e "\nexport CHROME_DEVEL_SANDBOX=/opt/google/chrome/chrome-sandbox" >> ~/.bashrc
|
||||
|
||||
- name: Start server
|
||||
run: npm run workflow-test
|
||||
|
||||
|
|
|
|||
35
.github/workflows/ci_production.yml
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
name: CI-Win-Production
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [v6.3-production]
|
||||
pull_request:
|
||||
branches: [v6.3-production]
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20.8.0'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Build libraries
|
||||
run: npm run build
|
||||
|
||||
- name: Start server
|
||||
run: npm run workflow-test
|
||||
|
||||
- name: Test server response
|
||||
run: npm test
|
||||
|
||||
- name: Stop server after testing
|
||||
run: npm stop
|
||||
15
.gitignore
vendored
|
|
@ -7,13 +7,12 @@ views/archive
|
|||
ngrok.exe
|
||||
pnpm-lock.yaml
|
||||
debug.log
|
||||
lib/rammerhead/sessions/*
|
||||
!lib/rammerhead/sessions/.gitkeep
|
||||
lib/rammerhead/cache-js/*
|
||||
!lib/rammerhead/cache-js/.gitkeep
|
||||
views/dist/*
|
||||
src/.shutdown
|
||||
/lib/rammerhead/sessions/*
|
||||
!/lib/rammerhead/sessions/.gitignore
|
||||
/lib/rammerhead/cache-js/*
|
||||
!/lib/rammerhead/cache-js/.gitignore
|
||||
/views/dist/*
|
||||
/src/.shutdown
|
||||
lib/rammerhead/src/client/hammerhead.min.js
|
||||
lib/rammerhead/src/client/rammerhead.min.js
|
||||
views/archive/gfiles/rarch/roms
|
||||
.idea
|
||||
views/archive/gfiles/rarch/roms
|
||||
39
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
[submodule "views/archive"]
|
||||
path = views/archive
|
||||
url = https://github.com/QuiteAFancyEmerald/HU-Archive.git
|
||||
|
||||
[submodule "views/archive/osu"]
|
||||
path = views/archive/osu
|
||||
url = https://github.com/BlaNKtext/webosu.git
|
||||
|
||||
[submodule "views/archive/g/house"]
|
||||
path = views/archive/g/house
|
||||
url = https://github.com/razh/game-off-2013
|
||||
|
||||
[submodule "views/archive/g/househorror"]
|
||||
path = views/archive/g/househorror
|
||||
url = https://github.com/arturkot/the-house-game
|
||||
|
||||
[submodule "views/archive/g/pond"]
|
||||
path = views/archive/g/pond
|
||||
url = https://github.com/Zolmeister/pond
|
||||
|
||||
[submodule "views/archive/g/particle-clicker"]
|
||||
path = views/archive/g/particle-clicker
|
||||
url = https://github.com/particle-clicker/particle-clicker
|
||||
|
||||
[submodule "views/archive/g/nsshaft"]
|
||||
path = views/archive/g/nsshaft
|
||||
url = https://github.com/iPel/NS-SHAFT
|
||||
|
||||
[submodule "views/archive/g/adarkroom"]
|
||||
path = views/archive/g/adarkroom
|
||||
url = https://github.com/doublespeakgames/adarkroom
|
||||
|
||||
[submodule "views/archive/g/trimps"]
|
||||
path = views/archive/g/trimps
|
||||
url = https://github.com/Trimps/Trimps.github.io
|
||||
|
||||
[submodule "views/archive/g/zork1"]
|
||||
path = views/archive/g/zork1
|
||||
url = https://github.com/jessicalevine/Adventure.js
|
||||
28
Dockerfile
|
|
@ -1,23 +1,25 @@
|
|||
FROM node:20-alpine
|
||||
FROM node:20
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
LABEL org.opencontainers.image.title="Holy Unblocker LTS" \
|
||||
org.opencontainers.image.description="An effective, privacy-focused web proxy service" \
|
||||
org.opencontainers.image.version="6.9.3" \
|
||||
org.opencontainers.image.authors="Holy Unblocker Team" \
|
||||
org.opencontainers.image.source="https://github.com/QuiteAFancyEmerald/Holy-Unblocker/"
|
||||
COPY package.json ./
|
||||
|
||||
RUN apk add --no-cache tor bash
|
||||
RUN npm config set unsafe-perm true
|
||||
RUN npm set registry https://registry.npmjs.org/
|
||||
RUN npm config set fetch-retries 5
|
||||
RUN npm install --verbose
|
||||
|
||||
# Copy the rest of the project files
|
||||
COPY . .
|
||||
|
||||
RUN npm run fresh-install
|
||||
RUN npm run build
|
||||
# Expose the port
|
||||
EXPOSE 8080
|
||||
|
||||
EXPOSE 8080 9050 9051
|
||||
# Start the app
|
||||
CMD ["npm", "start"]
|
||||
|
||||
COPY serve.sh /serve.sh
|
||||
RUN chmod +x /serve.sh
|
||||
|
||||
CMD ["/serve.sh"]
|
||||
# Build and Run Commands
|
||||
|
||||
# docker build -t holyunblocker .
|
||||
# docker run -p 8080:8080 holyunblocker
|
||||
487
README.md
|
|
@ -1,84 +1,71 @@
|
|||
<img align="center" src="https://raw.githubusercontent.com/titaniumnetwork-dev/Holy-Unblocker/master/views/assets/img/github_banner.png"></img>
|
||||
<img align="left" width="70px" src="https://raw.githubusercontent.com/titaniumnetwork-dev/Holy-Unblocker/master/views/assets/img/icon.png"></img>
|
||||
|
||||
<img align="left" width="40px" src="https://raw.githubusercontent.com/titaniumnetwork-dev/Holy-Unblocker/master/views/assets/img/logo_github.png"></img>
|
||||
|
||||
# Holy Unblocker LTS (v6.x.x)
|
||||
# Holy Unblocker LTS (v6.3.9)
|
||||
|
||||

|
||||

|
||||
[](https://hub.docker.com/r/quiteafancyemerald/holy-unblocker)
|
||||
[](https://hub.docker.com/r/quiteafancyemerald/holy-unblocker)
|
||||
|
||||
Holy Unblocker LTS is an experimental web proxy service that can bypass web filters or "blockers" regardless of whether the method of censorship is client-side or network-based. This includes the ability to bypass content blockers from governments, chrome extensions, localized client firewalls, and network-related filters. The project even allows the ability to browse Tor/Onion sites in any browser (even Chromium) all through a website!
|
||||
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.
|
||||
|
||||
## You can support Holy Unblocker by starring the repository!
|
||||
|
||||
This project serves mostly as a proof of concept for the ideal clientless solution to bypassing censorship. A good use case of this project would be if you ever needed a clientless solution to use Tor or leave minimal traces of device activity. Simply host this project on any domain and have an alternative solution to a VPN without needing to download anything on said device. Being a secure web proxy service, it supports numerous sites while being updated frequently and concentrating on being easy to self-host. Holy Unblocker LTS works with a large number of sites, including YouTube, Discord, GeForce NOW and more!
|
||||
This project serves mostly as a proof of concept for the ideal clientless solution to bypassing censorship. Being a secure web proxy service, it supports numerous sites while being updated frequently and concentrating on detail with design, mechanics, and features.
|
||||
|
||||
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.
|
||||
|
||||
### Over 30M+ users since 2020. Thank you so much for the support I could have never imagined how massive the web proxy community has become.
|
||||
|
||||
#### Current Branch: Latest
|
||||
|
||||
#### Current Branch: Production
|
||||
<details><summary>Branch Types</summary>
|
||||
|
||||
- Latest (master; built for FOSS and SEO)
|
||||
- Beta (pending changes; changes that may break things)
|
||||
- Production (v4, v5, v6; stable version of Holy Unblocker LTS. Changes for self hosting in production settings; max filtering evasion and request handling)
|
||||
- Stable (v4, v5, v6; stable version of Holy Unblocker LTS)
|
||||
- Production (changes for self hosting in production settings; max filtering evasion and request handling)
|
||||
</details>
|
||||
|
||||
#### Considering switching branches for self-hosting to a production branch!
|
||||
|
||||
View the <a href="#deploy-holy-unblocker">self-deployment options</a> if you wish to self host this project. Can't deploy using any of the free options? Check out Railway or look into cheap, paid VPS hosting solutions. If you don't wish to self-host join the discord for more official instance links that are restocked frequently.
|
||||
|
||||
**Be sure to join Titanium Network's Discord for more official site links:** <a href="https://discord.gg/unblock">https://discord.gg/unblock</a>
|
||||
|
||||
<br>
|
||||
|
||||
> [!CAUTION]
|
||||
> If you are going to self-host Holy Unblocker LTS please switch to the PRODUCTION branch for filter evasion features. The master branch is intended for development work and a highly readable source for developers. You can select a production branch (v6.x_production) via the branches dropdown.
|
||||
|
||||
> [!TIP]
|
||||
> Holy Unblocker LTS is optimized for self-hosting to provide you with maximum privacy control! Fork this repository and consider starring. You can self-host using either free or paid deployment options, or set it up on a dedicated instance (VPS) for enhanced performance.
|
||||
|
||||
| **Supported Sites** | **Features** |
|
||||
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Youtube | Built-in variety of open source web proxies with both a focus on speed and/or security |
|
||||
| Reddit | Features Source Randomization and DOM Masquerading to circumvent major filters effectively along with randomizations to proxy globals |
|
||||
| Discord | Tab title + icon customization using the Settings Menu for improved browsing history stealth |
|
||||
| Instagram | Adblocking support across all websites while surfing and low latency DNS on official servers |
|
||||
| Reddit.com | SOCKS5 and Onion routing support with Tor within the Settings Menu. Use Tor/Onion sites in any browser! |
|
||||
| GeForce NOW | Game library with moderately decent titles and open-source emulation projects |
|
||||
| Spotify | Bypass regional proxy blocks by swapping regions or enabling Tor |
|
||||
| And essentially all sites! | Built for intensive production loads and ease of setup |
|
||||
| **Supported Sites** | **Features** |
|
||||
|-----------------------------|------------------------------------------------------------------------------------------------------------------------|
|
||||
| Youtube | Built-in variety of open source web proxies with both a focus on speed and/or security |
|
||||
| CoolMathGames | Features "Source Randomization" to circumvent major filters effectively along with randomizations to proxy globals |
|
||||
| Discord | Tab title + icon customization using the Settings Menu for improved browsing stealth |
|
||||
| Now.gg | Adblocking support across all websites while surfing |
|
||||
| Reddit.com | SOCKS5 and Onion routing support with Tor within the Settings Menu |
|
||||
| GeForce NOW | Game library with moderately decent titles and open-source emulation projects |
|
||||
| Spotify | Has frequent support articles for issues relating to various proxy instances |
|
||||
| And essentially all sites! | Built for intensive production loads and speed |
|
||||
|
||||
<img src="https://raw.githubusercontent.com/titaniumnetwork-dev/Holy-Unblocker/master/views/assets/img/preview/hu-v6.4.3-preview.png"></img>
|
||||
|
||||
<img src="https://raw.githubusercontent.com/titaniumnetwork-dev/Holy-Unblocker/master/views/assets/img/preview/hu-v6.3.5-preview.png"></img>
|
||||
<img src="https://raw.githubusercontent.com/titaniumnetwork-dev/Holy-Unblocker/master/views/assets/img/preview/hu-v6.3.0-preview-settings.png"></img>
|
||||
|
||||
Read below for information if the official site is blocked or for obtaining more links. Can't deploy using any of the free options below? Check out Railway or look into cheap, paid VPS hosting solutions.
|
||||
|
||||
**Be sure to join Titanium Network's Discord for more official site links:** <a href="https://discord.gg/unblock">https://discord.gg/unblock</a>
|
||||
|
||||
## Deploy Holy Unblocker
|
||||
|
||||
### Free Deployments
|
||||
|
||||
[](https://app.koyeb.com/deploy?name=holy-unblocker&type=git&repository=QuiteAFancyEmerald%2FHoly-Unblocker&branch=v6.3_production&builder=buildpack&env%5B%5D=&ports=8080%3Bhttp%3B%2F)
|
||||
[](https://app.koyeb.com/deploy?name=holy-unblocker&type=git&repository=QuiteAFancyEmerald%2FHoly-Unblocker&branch=master&builder=buildpack&env%5B%5D=&ports=8080%3Bhttp%3B%2F)
|
||||
[](https://cloud.oracle.com/resourcemanager/stacks/create?zipUrl=https://github.com/BinBashBanana/deploy-buttons/archive/refs/heads/main.zip)
|
||||
|
||||
<details><summary>Alternative Free Sources</summary>
|
||||
<details><summary>More</summary>
|
||||
|
||||
[](https://app.cyclic.sh/api/app/deploy/shuttlenetwork/shuttle)
|
||||
[](https://render.com/deploy?repo=https://github.com/QuiteAFancyEmerald/Holy-Unblocker)
|
||||
[](https://fly.io/launch?repo=https://github.com/QuiteAFancyEmerald/Holy-Unblocker)
|
||||
|
||||
</details>
|
||||
|
||||
### Production Paid/Free Options (Requires Payment Info)
|
||||
|
||||
[](https://deploy.azure.com/?repository=https://github.com/QuiteAFancyEmerald/Holy-Unblocker)
|
||||
[](https://cloud.ibm.com/devops/setup/deploy?repository=https://github.com/QuiteAFancyEmerald/Holy-Unblocker)
|
||||
[](https://console.aws.amazon.com/amplify/home#/deploy?repo=https://github.com/QuiteAFancyEmerald/Holy-Unblocker)
|
||||
[](https://deploy.cloud.run/?git_repo=https://github.com/QuiteAFancyEmerald/Holy-Unblocker)
|
||||
|
||||
#### What happened to Replit/Heroku Deployment?
|
||||
|
||||
Replit is no longer free and Heroku has a set policy against web proxies. Try GitHub Codespaces or Gitpod instead for development on the cloud OR Koyeb for free hosting.
|
||||
|
||||
### GitHub Codespaces
|
||||
|
|
@ -87,10 +74,10 @@ Replit is no longer free and Heroku has a set policy against web proxies. Try Gi
|
|||
|
||||
- Fork (and star!) this repository to your GitHub account
|
||||
- Head to the official <a href="https://github.com/codespaces">Codespaces</a> website (ensure you have a GitHub account already made)
|
||||
- Select **New Codespaces** and look for _[USERNAME]/Holy-Unblocker_ on your account
|
||||
- Select **New Codespaces** and look for *[USERNAME]/Holy-Unblocker* on your account
|
||||
- Ensure the branch is set to `master` and the dev container configuration is set to **Holy Unblocker LTS**
|
||||
- Select **Create Codespace** and allow the container to setup
|
||||
- Type `npm run fresh-install` and `npm start` in the terminal
|
||||
- Type `npm install` and `npm start` in the terminal
|
||||
- Click "Make public" on the application popup, then access the deployed website via the ports tab.
|
||||
|
||||
</details>
|
||||
|
|
@ -98,13 +85,6 @@ Replit is no longer free and Heroku has a set policy against web proxies. Try Gi
|
|||
## Table of contents:
|
||||
|
||||
- [Setup](#how-to-setup)
|
||||
- [Terminal](#terminal)
|
||||
- [Project Configuration](#configuration)
|
||||
- [Server Configuration](#server-configuration-setup)
|
||||
- [TOR Routing](#toronion-routing-setup)
|
||||
- [Proxy](#proxy-configuration)
|
||||
- [Client Navigation](#client-navigation-configuration)
|
||||
- [Games Management](#games-management)
|
||||
- [Structure](#structure)
|
||||
- [Structure Information](#structure-information)
|
||||
- [Static Files](#details-of-views)
|
||||
|
|
@ -120,224 +100,56 @@ Replit is no longer free and Heroku has a set policy against web proxies. Try Gi
|
|||
|
||||
## How to Setup
|
||||
|
||||
#### It is highly recommended you switch branches via your IDE to a production released branch. Often the master branch contains unstable or WIP changes.|
|
||||
|
||||
#### Example: v6.x_production instead of master
|
||||
|
||||
### Terminal
|
||||
|
||||
Either use the button above to deploy to the deployment options above or type the commands below on a dedicated server
|
||||
|
||||
**THIS PROJECT REQUIRES NGINX NOT CADDY.**
|
||||
|
||||
Please ensure you are using Node 20.x as well:
|
||||
Either use the button above to deploy to the deployment options above or type the commands below on a dedicated server:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/QuiteAFancyEmerald/Holy-Unblocker.git
|
||||
git clone --recurse-submodules https://github.com/titaniumnetwork-dev/Holy-Unblocker.git
|
||||
|
||||
cd Holy-Unblocker
|
||||
|
||||
# Edit config.js and set production to true if you want to use pm2 (Allows for easier VPS hosting)
|
||||
npm run fresh-install
|
||||
npm start
|
||||
|
||||
# Or on subsequent uses...
|
||||
npm restart
|
||||
|
||||
# For killing any production processes made with pm2
|
||||
npm run kill
|
||||
|
||||
# For clearing respective Rammerhead cache
|
||||
npm run clean
|
||||
|
||||
# If you encounter any build errors...
|
||||
npm run build
|
||||
|
||||
# If you encounter any service errors...
|
||||
npm run test
|
||||
```
|
||||
|
||||
This website is hosted locally with Scramjet, Ultraviolet (Wisp, Bare-Mux, EpoxyTransport, CurlTransport) and Rammerhead built-in.
|
||||
### It is highly recommended you switch branches via your IDE to a stable released branch. Often the master branch contains unstable or WIP changes.
|
||||
|
||||
### For security reasons when hosting with a reverse proxy PLEASE use NGINX not Caddy. This is due to wisp-js using loopbacks.
|
||||
#### Example v6.x instead of master
|
||||
|
||||
#### Detailed Setup (Ubuntu Example)
|
||||
You will need Node.js 20.x and Git installed; below is an example for Debian/Ubuntu setup.
|
||||
<details>
|
||||
The default place for the proxy when its started is `http://localhost:8080`, but you can change it if needed in `./ecosystem.config.js`. You can also modify the other configuration values at `/src/config.json`. To clarify you change the PORT and other production metrics via `./ecosystem.config.js`. Localized changes for source randomization, auto-minify, etc. are located in `/src/config.json`.
|
||||
|
||||
For simplicity sake you can join the TN discord at discord.gg/unblock and request for mirror site links (that are restocked and unblocked).
|
||||
|
||||
### Hosting
|
||||
|
||||
If you wish to self-host however you will first need a VPS or hosting provider:
|
||||
|
||||
- https://docs.titaniumnetwork.org/guides/vps-hosting/
|
||||
- https://github.com/QuiteAFancyEmerald/Holy-Unblocker#deploy-holy-unblocker
|
||||
- https://docs.titaniumnetwork.org/guides/dns-setup/
|
||||
|
||||
### Dependencies
|
||||
|
||||
You will then need to setup git, nginx (or caddy) and Node.js. Here is an example for Ubuntu LTS:
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
sudo apt install curl git nginx
|
||||
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
|
||||
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||
|
||||
nvm install 20
|
||||
nvm use 20
|
||||
```
|
||||
https://github.com/nvm-sh/nvm
|
||||
https://docs.titaniumnetwork.org/guides/nginx/
|
||||
|
||||
### Tor Support (Optional)
|
||||
https://github.com/QuiteAFancyEmerald/Holy-Unblocker#toronionsocks5-routing-setup
|
||||
|
||||
### Configurating Holy Unblocker
|
||||
Most important options are production along with the obfuscation and DOM masquerading techniques.
|
||||
|
||||
From there just configure as needed: https://github.com/QuiteAFancyEmerald/Holy-Unblocker#configuration
|
||||
|
||||
### Cloning and Running Holy Unblocker
|
||||
|
||||
Then run the respective process; if you have production set to true in the configuration pm2 will be automatically enabled with our own workers/cache system.
|
||||
|
||||
```
|
||||
git clone https://github.com/QuiteAFancyEmerald/Holy-Unblocker.git
|
||||
cd Holy-Unblocker
|
||||
|
||||
npm run fresh-start
|
||||
```
|
||||
|
||||
Then of course if you used NGINX or caddy please restart/reload it
|
||||
```
|
||||
sudo systemctl restart nginx
|
||||
sudo systemctl restart tor
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
Resources for self-hosting:
|
||||
|
||||
- https://github.com/nvm-sh/nvm
|
||||
- https://docs.titaniumnetwork.org/guides/nginx/
|
||||
- https://docs.titaniumnetwork.org/guides/vps-hosting/
|
||||
- https://docs.titaniumnetwork.org/guides/dns-setup/
|
||||
|
||||
### Configuration
|
||||
|
||||
#### Server Configuration Setup
|
||||
|
||||
The default PORT for the proxy when started is `http://localhost:8080`. You can change the PORT and other production metrics if needed in `./ecosystem.config.js`.
|
||||
|
||||
The default PORT for Rammerhead is `3000`. You can change this <a href="https://github.com/QuiteAFancyEmerald/Holy-Unblocker/blob/8f6dcfedb71439a43a19cc0a015ee6ca7e29fd11/lib/rammerhead/holy-config.js#L9">here</a>.
|
||||
|
||||
Every other localized changes for source randomization, auto-minify, etc. are located in `./config.json`.
|
||||
|
||||
**config.json**
|
||||
- `minifyScripts`: Automatically minify respective static assets upon starting the server.
|
||||
- `randomizeIdentifiers`: Enable experimental proxy global randomization for Ultraviolet. This reduces the chances of UV being detected by any extension based filters.
|
||||
- `production`: Utilize a pre-configured production setup for server hosting. Automatically has cache control, session jobs for Rammerhead and source rewrites setup.
|
||||
- `disguiseFiles`: Enable DOM masquerading which obfuscates real the real content fetches for HU LTS. This is done through disguising requests, decompressing and then reconstructing the DOM tree.
|
||||
- `usingSEO`: Enable Source Randomization which randomizes the source by swapping chunks of data specified in `./src/data.json`. Highly useful for masking keywords that will automatically flag or block Holy Unblocker LTS as well as preventing source blocks.
|
||||
|
||||
#### Tor/Onion/SOCKS5 Routing Setup
|
||||
|
||||
You need to setup Tor (no GUI need/GUI is alright. With GUI replace port 9050 with 9150) in order for the Onion Routing setting to work!
|
||||
|
||||
Simply host Tor using this guide: https://tb-manual.torproject.org/installation/
|
||||
|
||||
Alternative Guide (for CLI): https://community.torproject.org/onion-services/setup/install/
|
||||
|
||||
If you are hosting Holy Unblocker LTS on a VPS utilizing Ubuntu consider attaching Tor to systemctl for easier production management. Once Tor is up and running on either Linux or Windows it will work automatically with Holy Unblocker LTS when enabled by the user via the Settings menu.
|
||||
|
||||
If you wish to use a custom HTTP/HTTPS/SOCKS5 proxy to route all traffic through for Scramjet and Ultraviolet this is handled in `./views/assets/js/register-sw.js.` Modify `proxyUrl` with the respective protocol and address. This is done via the proxy option for Wisp. You can change the cases as needed.
|
||||
|
||||
```js
|
||||
proxyUrl = {
|
||||
tor: 'socks5h://localhost:9050',
|
||||
eu: 'socks5h://localhost:7000',
|
||||
jp: 'socks5h://localhost:7001',
|
||||
}
|
||||
```
|
||||
|
||||
#### Proxy Configuration
|
||||
|
||||
The primary location for tweaking any web proxy related settings assigned via the Settings menu is `./views/assets/js/register-sw.js`. Here you can modify the provided transport options set locally via a cookie, swap out SOCKS5 proxies, change Onion routing ports, specify a blacklist, and more.
|
||||
|
||||
- `stockSW`: The default service worker configuration file for Ultraviolet. For Holy Unblocker however adblocking is automatically enabled so this is not used by default.
|
||||
- `blacklistSW`: A modified version of Ultraviolet that allows for blacklisting domains and adblocking.
|
||||
- `proxyUrl`: Specifies a SOCKS5/HTTPS/HTTP protocol URL defaulting to the default Tor proxy port. This can be swapped out with any valid port or SOCK5s proxy. This is done via the proxy option for both epoxy and libcurl.
|
||||
- `transports`: Specifies any provided ports to be swapped via Bare-Mux and utilize Wisp.
|
||||
- `wispUrl`: Modify the pathname or url handling for Wisp
|
||||
- `defaultMode`: Specify the default transport used globally (can be swapped by the users still via the Settings menu)
|
||||
- `ScramjetController`: This constructor allows you to swap out the prefix used for Scramjet dynamically and specify file locations. Note you may need to edit `./views/scram/scramjet.sw` when changing file names.
|
||||
|
||||
#### Client Navigation Configuration
|
||||
|
||||
The primary location for any client side navigation scripts is `./views/assets/js/common.js`. This file is primary used for Omnibox (Search Engine) functionality, swapping proxy options and linking games.
|
||||
|
||||
- `getDomain`: This constant is used for specifying any subdomains to remove when appending a URL into the omnibox.
|
||||
- `goFrame`: This specifies the stealth frame used for Holy Unblocker LTS
|
||||
- `sx`: This constant specifies the search engine you want to be proxied whenever a user types something in that isn't a URL
|
||||
- `search/uvUrl/sjUrl`: These functions specify and parse the queries used for submitted URLs
|
||||
- `RammerheadEncode:` This constant is a dependency for Rammerhead parsing and querying
|
||||
- `urlHandler/asyncUrlHandler`: Used to set functions for the goProx object.
|
||||
- `goProx`: This constant allows for the mapping of URL handling for specific proxies, games or links that need to fall under a web proxy.
|
||||
|
||||
```js
|
||||
const goProx = Object.freeze({
|
||||
ultraviolet: urlHandler(uvUrl),
|
||||
|
||||
scramjet: urlHandler(sjUrl),
|
||||
|
||||
rammerhead: asyncUrlHandler(
|
||||
async (url) => location.origin + (await RammerheadEncode(search(url)))
|
||||
),
|
||||
|
||||
// `location.protocol + "//" + getDomain()` more like `location.origin`
|
||||
|
||||
examplepath: urlHandler(location.protocol + `//c.${getDomain()}/example/`),
|
||||
|
||||
examplesubdomain: urlHandler(location.protocol + '//c.' + getDomain()),
|
||||
|
||||
example: urlHandler(sjUrl('https://example.com')),
|
||||
});
|
||||
```
|
||||
|
||||
- `prSet`: Attaches event listeners using goProx for any buttons or inputs needed
|
||||
|
||||
```js
|
||||
// prSet function code here....
|
||||
|
||||
prSet('pr-uv', 'ultraviolet');
|
||||
prSet('pr-sj', 'scramjet');
|
||||
prSet('pr-rh', 'rammerhead');
|
||||
prSet('pr-yt', 'youtube');
|
||||
prSet('pr-example', 'example');
|
||||
```
|
||||
|
||||
- `huLinks/navLists`: Automatically takes paths stated in `./views/assets/json` and appends them depending on the page and usage. This is used for hiding links that would lead to filter blocks and create an easier system for adding games.
|
||||
|
||||
#### Games Management
|
||||
|
||||
As stated above all game links that need to be appended to a page (including images and descriptions) are managed via the nav files in`./views/assets/json`.
|
||||
|
||||
Download the latest release <a href="https://github.com/QuiteAFancyEmerald/Holy-Unblocker/blob/master/views/GAMES.md">here</a> and extract it within a folder called `/views/archive`.
|
||||
|
||||
- `views/archive/g`: Contains any local or external HTML5/web games.
|
||||
- `views/archive/gfiles/flash`: Contains Ruffle (an Adobe Flash emulator) and a collection of flash games linked to an external CDN.
|
||||
- `views/archive/gfiles/rarch`: Contains webretro which is a project that ports RetroArch to WASM. Supports many systems like GBA, N64, etc; ROMS are NOT INCLUDED.
|
||||
This website is hosted locally with Ultraviolet and Rammerhead built-in.
|
||||
|
||||
## Structure
|
||||
|
||||
<details><summary>Web Pages</summary>
|
||||
|
||||
WIP
|
||||
|
||||
- `index.html`: The homepage of the site.
|
||||
- `error.html`: A general error page for all 404 errors and other errors.
|
||||
- `info.html`: Documentation (This page!)
|
||||
- `faq.html`: Frequently asked questions page.
|
||||
- `hidden.html`: Fake "Site not Found" page (unused)
|
||||
- `frame.html`: Handles any pages under stealth.
|
||||
- `surf.html`: Web Proxies page, page offers to be redirected to any proxies you would like to add. In this case, Ultraviolet and Rammerhead.
|
||||
- `credits.html`: List of all contributors to the site.
|
||||
- `bookmarklets.html`: Bookmarklets page, to be worked on more in the future.
|
||||
- `icons.html`: Information regarding Settings Menu page. Added this in for standard users.
|
||||
- `terms.html`: Terms of Services, AUP and Privacy Policy page.
|
||||
- `gtools.html`: Games page, help from @BinBashBanana and @kinglalu.
|
||||
- `games5.html`: HTML5 game navigation page.
|
||||
- `emulators.html`: Emulator navigation page, using <a href="https://github.com/BinBashBanana/webretro">webretro</a>.
|
||||
- `emulibrary.html`: Games page for emulated games (not included in public release)
|
||||
- `flash.html`: Games page for flash games, credits given to @BinBashBanana and Titanium Network for its assets.
|
||||
- `ultraviolet.html`: TODO
|
||||
- `rammerhead.html`: TODO
|
||||
- `youtube.html`: A proxied version of Youtube running off the locally hosted Ultraviolet.
|
||||
- `discord.html`: Hub for the Discord proxy.
|
||||
- `reddit.html`: Hub for the Reddit proxy.
|
||||
</details>
|
||||
|
||||
### Structure Information
|
||||
|
||||
- `/views/`: The physical site base of Holy Unblocker goes here where static assets are served.
|
||||
|
|
@ -345,66 +157,170 @@ Download the latest release <a href="https://github.com/QuiteAFancyEmerald/Holy-
|
|||
|
||||
#### Details of `/views/`
|
||||
|
||||
- `/dist/` is used for minfied files. Created on build.
|
||||
- `/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.
|
||||
- `/scram/` contains the respective local Scramjet implementation. Some files are overridden by the node module.
|
||||
- `/uv/` contains the UV implementation.
|
||||
|
||||
#### 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 most site features to function such as autocomplete.
|
||||
- `csel.js` manages the settings menu, omnibox function and other additional features.
|
||||
- `loader.js` is used as an asset for DOM masquerading.
|
||||
- `common.js` is used on all pages and allows commonly used features to function.
|
||||
- `csel.js` manages the settings menu on the header.
|
||||
- `particles.js` is the animated background effect that's present on all pages.
|
||||
- `register-sw.js` creates and manages service workers that allow Ultraviolet to function, and also uses bare transport.
|
||||
|
||||
</details>
|
||||
|
||||
## Future Additions
|
||||
|
||||
<a href="https://github.com/QuiteAFancyEmerald/Holy-Unblocker/blob/master/TODO.md">This</a> is our nonexhaustive todo list for Holy Unblocker LTS v6.x.x and above. Release for production will be v7.x.x and above.
|
||||
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
|
||||
|
||||
## 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
|
||||
|
||||
## 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)
|
||||
|
||||
## Community Requests
|
||||
|
||||
- [ ] 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
|
||||
|
||||
## Vague Explanation for Beginners With External Proxies and Hosting
|
||||
|
||||
You will first want to host your proxies locally or externally.
|
||||
You will first want to host your proxies locally or externally. OUTDATED
|
||||
|
||||
#### List of some good hosting options:
|
||||
|
||||
- <a href="https://crunchbits.com/">Crunchbits</a> ( Current Hosting Provider)
|
||||
- <a href="https://greencloudvps.com">Greencloud</a> (Paid)
|
||||
- <a href="https://www.oracle.com/cloud">Oracle Cloud</a> (Free, Paid, Dedicated)
|
||||
- <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)
|
||||
|
||||
Out of the list of hosting providers Dedipath and Azure rank first as a preference. You may also self-host.
|
||||
|
||||
After you have selected a decent VPS, use Cloudflare for the DNS records for both the site and the subdomains for the proxies.
|
||||
|
||||
This is an example of DNS records. Self-hosting will require `A records` preferably.
|
||||
This is an example of DNS records involving Heroku. Self-hosting will require `A records` preferably.
|
||||
<img src="https://raw.githubusercontent.com/titaniumnetwork-dev/Holy-Unblocker/master/views/assets/img/dnssetup.png" width="500"></img>
|
||||
|
||||
- `@` and `www.example.com` are being used for Holy Unblocker LTS.
|
||||
- `a.example.com` is being used for other instances like Libreddit, Invidious or web ported games depending on what the site maintainer needs.
|
||||
- `@` and `www.example.ml` are being used for the local Ultraviolet proxy.
|
||||
- `client.example.ml` is being used for Rammerhead.
|
||||
- `a.example.ml` is being used for womginx.
|
||||
- `cdn.example.ml` is being used for a private Ultraviolet host on the official sites.
|
||||
|
||||
As stated previously, Holy Unblocker is hosted locally with Scramjet, Ultraviolet and Rammerhead out of the box. No need for external instances.
|
||||
As stated previously, Holy Unblocker is hosted locally with Ultraviolet.
|
||||
|
||||
#### Domain Steps
|
||||
#### Freenom/Domain Steps
|
||||
|
||||
- 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 `.org` domain normally costs around $5 first year.
|
||||
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.
|
||||
- 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 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.
|
||||
- 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:
|
||||
|
||||
**Type | Name | Target**
|
||||
|
||||
`A | @ | VPS IP GOES HERE`
|
||||
`A | www | VPS IP GOES HERE`
|
||||
`A | a | VPS IP GOES HERE`
|
||||
`CNAME | @ | your-main-heroku-target-here.herokudns.com`
|
||||
`CNAME | www | your-main-heroku-target-here.herokudns.com`
|
||||
|
||||
Make sure HTTPS is forced and have SSL set to Flexible (if you don't use LetsEncrypt). Otherwise you can have SSL set to Full.
|
||||
**Below are if you want external proxies also with your site:**
|
||||
|
||||
`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
|
||||
|
||||
|
|
@ -417,15 +333,7 @@ git clone https://github.com/QuiteAFancyEmerald/Holy-Unblocker.git
|
|||
|
||||
cd Holy-Unblocker
|
||||
|
||||
npm run fresh-install
|
||||
|
||||
# If you wish to start the project
|
||||
|
||||
npm start
|
||||
|
||||
# For testing endpoints and errors
|
||||
|
||||
npm run test
|
||||
npm install
|
||||
```
|
||||
|
||||
Now simply add the folder you cloned this repo in in VSC. Then run `npm install`. I recommend that if you are releasing this publically on GitHub that you add a `.gitignore` in your root directory with the following exclusions:
|
||||
|
|
@ -454,7 +362,7 @@ Due to piracy concerns, size, etc. this has been moved over <a href="https://git
|
|||
|
||||
**Why is the site I am on not working correctly or having CAPTCHA errors?**
|
||||
|
||||
Captcha support is spotty on all of the current proxies sadly. It is primarily supported by Scramjet. Therefore some sites may not work with any of the sites.
|
||||
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.
|
||||
|
||||
**I am getting 502 errors. What do I do?**
|
||||
|
||||
|
|
@ -466,7 +374,7 @@ If you still have any questions feel free to ask them in the discord linked here
|
|||
|
||||
### 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: domain restocks as needed and a highly maintained source. More than ever, this project serves as a proof of concept for the brave souls willing to innovate in the web proxy service space.
|
||||
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>
|
||||
|
||||
|
|
@ -496,17 +404,14 @@ View the official website for more detail and credits.
|
|||
|
||||
### Web Proxy Sources:
|
||||
|
||||
This project currently uses Scramjet and Ultraviolet as web proxies adhering to the Wisp protocol. Bare-Mux is utilized for swapping transport systems to be utilized with Wisp. The included transport systems are EpoxyTransport and libcurl-transport. Rammerhead is also provided as an additional web proxy option.
|
||||
This project currently uses Ultraviolet, Wisp, Womginx, and Rammerhead, linked below.
|
||||
|
||||
- <a href="https://github.com/MercuryWorkshop/scramjet">Scramjet</a>
|
||||
- <a href="https://github.com/titaniumnetwork-dev/Ultraviolet">Ultraviolet</a>
|
||||
- <a href="https://github.com/MercuryWorkshop/wisp-server-node">Wisp-Server-Node</a>
|
||||
- <a href="https://github.com/MercuryWorkshop/wisp-server-python">Wisp-Server-Python</a>
|
||||
- <a href="https://github.com/MercuryWorkshop/EpoxyTransport">EpoxyTransport</a>
|
||||
- <a href="https://github.com/MercuryWorkshop/CurlTransport">libcurl-transport</a>
|
||||
- <a href="https://github.com/MercuryWorkshop/bare-mux">Bare-Mux</a>
|
||||
- <a href="https://github.com/binary-person/womginx">Womginx</a>
|
||||
- <a href="https://github.com/binary-person/rammerhead">Rammerhead</a>
|
||||
- <a href="https://gist.github.com/BinBashBanana/a1fd7345e2d86e69d5a532f16cbdbdaa">DetectorDetector</a>
|
||||
- <a href="https://github.com/MercuryWorkshop/wisp-server-node">Wisp</a>
|
||||
- <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:
|
||||
|
||||
|
|
|
|||
141
TODO.md
|
|
@ -1,99 +1,84 @@
|
|||
This will be our nonexhaustive todo list for Holy Unblocker LTS v6.x.x and above. Release for production will be v8.x.x and above.
|
||||
|
||||
## Proxy/Site Functionality
|
||||
|
||||
- [ ] Update to use scramjetFrame instead of our own window handling
|
||||
- [ ] Implement wisp python to the project instead of the unreliable wisp-server-node
|
||||
- [ ] Add booksmark menu (source wise already present pretty much)
|
||||
- [ ] Add Chii + ensuring users can access devtools while browsing - partial
|
||||
- [ ] Setting to open multiple stealth frames; basically about:blank but using our system. Pops out in another tab
|
||||
- [ ] Omnibox should state what the current site the user is on like a proper URL bar
|
||||
- [ ] Improve adblocking functions on site using Workerware + a pre-bundled uBlock Origin
|
||||
- [ ] Add a "website self-destruct" button to the settings menu
|
||||
- [ ] Transport Options Swapping on Frame (Settings Menu doesn't swap)
|
||||
- [ ] Implement advanced data URI system
|
||||
- [ ] Allow custom Wisp urls from the settings menu (not config side)
|
||||
- [x] Swap to wisp-js over wisp-server-node for security and performance - done
|
||||
- [x] Fix keyword/descriptor randomisation - done
|
||||
- [x] Adapt Wisp protocol replacing bare which is very unsecure - done
|
||||
- [x] Improved error handling for proxy errors - done
|
||||
- [x] Ensure Ultraviolet is updated to support bare-mux and wisp - done
|
||||
- [x] Ensure Scramjet is added and works together with UV's implementation - done
|
||||
- [x] Adapt Scramjet as main proxy for the project - done
|
||||
- [x] Refactor register-sw.js - 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)
|
||||
- [x] Adapt Applications page to use Scramjet (for Reddit, YouTube, Discord) - done
|
||||
- [x] Added libcurl transport and epoxy transport to meet standards of SJ + Wisp - done
|
||||
- [x] SOCKS5/Tor routing option that can be configured as a settings menu option - done
|
||||
- [x] SOCKS5 regional proxy implementation - done
|
||||
- [x] Update Applications page to reflect modern fast links (use examples from the modern web proxy base) - done. can be expanded later
|
||||
- [x] Update settings menu again to make more room for more features - done
|
||||
- [x] Update csel.js (after Setting menu redesign) to support custom transports, icon swap, routing - done
|
||||
- [x] Flesh out and rework the UV / Scramjet / bare client error page - done
|
||||
- [x] Update sw.js to support workerware (https://github.com/MercuryWorkshop/workerware)-- This is not done however we have our own middleware system implemented for adblocking, etc.
|
||||
- [x] Omnibox autoupdate script (for the Google/Bing style auto suggest feature) - done
|
||||
- [x] Omnibar functionality (back and forward navigation, settings menu and create new stealth page with URL) - done
|
||||
- [x] Games library will feature new games - done
|
||||
- [x] Servers now utilise NextDNS w/ ads and malware blocked; anycast + low latency - done
|
||||
- [x] Revamp the Stealth Frame with a slight animation (ease in and then the wheeling loading with a gradient fading away once its loaded or shows the error page LOL), a loading wheel/page and lastly a omnibox widget. It will have like nav buttons, some of the settings from the settings menu, a home button, a button that brings up the Setting menu and be in a designed position. Intent is to reduce the back/forth nature that users have to do currently making it more tedious to use the site. - partial. needs functionality.
|
||||
|
||||
## Code Cleanup
|
||||
|
||||
- [x] Optimize the JS. This time it won't be in one line and will be somewhat thoroughly commented.
|
||||
- [x] Ensure all the original submodules get added back to HU-Archive
|
||||
- [x] SEO overhaul adapted from the v3 SEO Guide format - partial
|
||||
- [x] Optimize the stylesheets and the HTML layout. Add more proper commenting and redivide the code so that it's less hard on the eyes.
|
||||
- [x] 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 Fastify 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.
|
||||
- [x] Restructure navigation scripts to ensure updated proxy functionality is sanitized and effective - done
|
||||
- [ ] 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 CI testing script - done
|
||||
- [x] Create test script - done
|
||||
- [x] XSS and fingerprinting protection (may need updates) - done
|
||||
- [x] Greatly improved native source rewrites and routing - done
|
||||
- [x] Update games navigation JS and page/change to JSON object system - done
|
||||
- [x] Mobile support - (partial)
|
||||
- [ ] 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 v3 SEO Guide format - partial
|
||||
- [x] Fastify routes modified to ensure perfect SEO. This means absolute paths such as /example instead of ?z - done
|
||||
- [x] Randomize the \_\_uv$config global, and optionally randomize the UV prefix and URL encoding via cookies
|
||||
- [ ] 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 to 10000 games
|
||||
- [ ] Update Applications page to reflect modern fast links (use examples from the modern web proxy base)
|
||||
- [ ] 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 - partial. function implementation done however styles not
|
||||
- [x] Update sw.js to support workerware (https://github.com/MercuryWorkshop/workerware)-- This is not done however we have our own middleware system implemented for adblocking, etc.
|
||||
- [ ] 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
|
||||
- [ ] Attach proxyvalidatorscript to a status page > have this be served via Fastify, etc. etc; config option disabled as it will cause issues potentially unless if we refactor it slightly.
|
||||
- [ ] Improve adblocking functions on site using AnuraOS standards
|
||||
|
||||
## Site Redesign
|
||||
|
||||
- [x] Documentation on-site + Getting Started information updated (Tor, etc.) - partial; good enough
|
||||
- [x] Update colors + add themes - done
|
||||
- [x] Landing Cards - done
|
||||
- [x] Change fonts to cleaner look
|
||||
- [x] Add more AOS interactions on scroll or hover
|
||||
- [x] Add subtle noise to background elements
|
||||
- [x] Toggle elements
|
||||
- [x] Other card options
|
||||
- [x] Radial blur elements
|
||||
- [x] Code standard examples - in source
|
||||
- [x] Horizontal/general movement on scroll with AOS
|
||||
- [x] Showcase dev dependencies
|
||||
- [x] Update branding and icons
|
||||
- [x] Landing Page
|
||||
- [x] Settings Menu - partial I want to fix some colours
|
||||
- [x] More Dropdown Menu
|
||||
- [x] Web Proxies page
|
||||
- [x] Application page
|
||||
- [x] Games Library page
|
||||
- [x] Emulators Library page
|
||||
- [x] Emu Library page
|
||||
- [x] Web Games page
|
||||
- [x] Flash Games page
|
||||
- [x] FAQ page
|
||||
- [x] Credits page
|
||||
- [x] TOS page
|
||||
- [x] Footer Design
|
||||
- [x] Header Design
|
||||
- [ ] 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 on-site + Getting Started information updated (Tor, etc.)
|
||||
- [ ] FAQ page
|
||||
- [ ] Credits page
|
||||
- [ ] TOS page
|
||||
- [x] Footer Design - (partial/needs work)
|
||||
- [x] Header Design - (partial/needs work)
|
||||
|
||||
## Community Requests
|
||||
|
||||
- [x] Add [Quake WASM](https://github.com/GMH-Code/Quake-WASM)
|
||||
- [x] Celeste WASM
|
||||
- [ ] Add [Quake WASM](https://github.com/GMH-Code/Quake-WASM)
|
||||
- [ ] Celeste WASM
|
||||
- [ ] Doom WASM
|
||||
|
||||
## Changelog (Old; too lazy to type it all out now)
|
||||
## Changelog
|
||||
|
||||
- Added wisp support
|
||||
- Fixed AD config setting being opt-out; ads are not implemented in the project however
|
||||
|
|
|
|||
7
app.json
|
|
@ -1,12 +1,11 @@
|
|||
{
|
||||
"name": "Holy Unblocker v6.8.7",
|
||||
"name": "Holy Unblocker v6.3.9",
|
||||
"description": "Holy Unblocker is a secure web proxy service supporting numerous sites while concentrating on detail with design, mechanics, and features. Bypass web filters regardless of whether it is an extension or network-based.",
|
||||
"repository": "https://github.com/QuiteAFancyEmerald/Holy-Unblocker",
|
||||
"logo": "https://raw.githubusercontent.com/QuiteAFancyEmerald/Holy-Unblocker/master/views/assets/img/icon.png",
|
||||
"repository": "https://github.com/titaniumnetwork-dev/Holy-Unblocker",
|
||||
"logo": "https://raw.githubusercontent.com/titaniumnetwork-dev/Holy-Unblocker/master/views/assets/img/icon.png",
|
||||
"keywords": [
|
||||
"holyunblocker",
|
||||
"rammerhead",
|
||||
"scramjet",
|
||||
"ultraviolet",
|
||||
"titaniumnetwork",
|
||||
"node",
|
||||
|
|
|
|||
152
detectordetector.js
Normal file
|
|
@ -1,12 +0,0 @@
|
|||
version: "3.9"
|
||||
|
||||
services:
|
||||
holy-unblocker:
|
||||
image: quiteafancyemerald/holy-unblocker:6.9.4
|
||||
build: .
|
||||
container_name: holy-unblocker
|
||||
ports:
|
||||
- "8080:8080"
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
|
|
@ -20,41 +20,5 @@ module.exports = {
|
|||
kill_timeout: 3000,
|
||||
watch: false,
|
||||
},
|
||||
{
|
||||
name: 'HolyUBLTS-src-refresh',
|
||||
script: './run-command.mjs',
|
||||
args: 'build',
|
||||
env: {
|
||||
NODE_ENV: 'development',
|
||||
},
|
||||
env_production: {
|
||||
NODE_ENV: 'production',
|
||||
},
|
||||
instances: '1',
|
||||
exec_interpreter: 'babel-node',
|
||||
exec_mode: 'fork',
|
||||
autorestart: true,
|
||||
restart_delay: 1000 * 60 * 10,
|
||||
kill_timeout: 3000,
|
||||
watch: false,
|
||||
},
|
||||
{
|
||||
name: 'HolyUBLTS-cache-clean',
|
||||
script: './run-command.mjs',
|
||||
args: 'clean',
|
||||
env: {
|
||||
NODE_ENV: 'development',
|
||||
},
|
||||
env_production: {
|
||||
NODE_ENV: 'production',
|
||||
},
|
||||
instances: '1',
|
||||
exec_interpreter: 'babel-node',
|
||||
exec_mode: 'fork',
|
||||
autorestart: true,
|
||||
restart_delay: 1000 * 60 * 60 * 24 * 7,
|
||||
kill_timeout: 3000,
|
||||
watch: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
BIN
lib/rammerhead/cache-js/.gitignore
vendored
Normal file
573
lib/rammerhead/package-lock.json
generated
|
|
@ -471,9 +471,9 @@
|
|||
"optional": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.4.tgz",
|
||||
"integrity": "sha512-d9RWfoR7JC/87vj7n+PVTzGg9hDyuFjir3RxUHbjFSKNd9mpxbxwMEyaCim/ddCmy4IuW7HjTzF3g9p3EtWEOg==",
|
||||
"version": "22.8.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.7.tgz",
|
||||
"integrity": "sha512-LidcG+2UeYIWcMuMUpBKOnryBWG/rnmOHQR5apjn8myTQcx3rinFRn7DcIFhMnS0PPFSC6OafdIKEad0lj6U0Q==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
|
|
@ -621,6 +621,12 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/asar/node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/asar/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
|
|
@ -654,6 +660,15 @@
|
|||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/asar/node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/asar/node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
|
|
@ -698,6 +713,12 @@
|
|||
"tmp": "0.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/asar/node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/async-exit-hook": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz",
|
||||
|
|
@ -758,73 +779,12 @@
|
|||
"eslint": ">= 4.12.1"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bowser": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/bowser/-/bowser-1.6.0.tgz",
|
||||
"integrity": "sha512-Fk23J0+vRnI2eKDEDoUZXWtbMjijr098lKhuj4DKAfMKMCRVfJOuxXlbpxy0sTgbZ/Nr2N8MexmOir+GGI/ZMA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
|
|
@ -886,6 +846,12 @@
|
|||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/css/node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/css/node_modules/resolve-url": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
||||
|
|
@ -955,15 +921,6 @@
|
|||
"node": ">= 8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "7.32.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
|
||||
|
|
@ -2431,44 +2388,12 @@
|
|||
"ret": "~0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/http-cache-semantics": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
||||
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/json-format": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-format/-/json-format-1.0.1.tgz",
|
||||
|
|
@ -2551,6 +2476,12 @@
|
|||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/merge-stream/node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/merge-stream/node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
|
|
@ -2593,6 +2524,12 @@
|
|||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream/node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
|
||||
|
|
@ -2605,12 +2542,6 @@
|
|||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mustache": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.2.tgz",
|
||||
|
|
@ -2656,15 +2587,6 @@
|
|||
"npm-force-resolutions": "index.js"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/os-family": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/os-family/-/os-family-1.1.0.tgz",
|
||||
|
|
@ -2729,6 +2651,26 @@
|
|||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pino/node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pino/node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
|
|
@ -2780,6 +2722,26 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pino/node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/pino/node_modules/on-exit-leak-free": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
|
||||
|
|
@ -2851,6 +2813,26 @@
|
|||
"node": ">= 12.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pino/node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pino/node_modules/safe-stable-stringify": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
|
||||
|
|
@ -2878,6 +2860,15 @@
|
|||
"node": ">= 10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/pino/node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pino/node_modules/thread-stream": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz",
|
||||
|
|
@ -2940,16 +2931,6 @@
|
|||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/read-file-relative": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/read-file-relative/-/read-file-relative-1.2.0.tgz",
|
||||
|
|
@ -2967,20 +2948,6 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.8",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||
|
|
@ -3140,6 +3107,12 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/rimraf/node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/rimraf/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
|
|
@ -3152,6 +3125,15 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/rimraf/node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/rimraf/node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
|
|
@ -3161,25 +3143,11 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
"node_modules/rimraf/node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/secure-json-parse": {
|
||||
"version": "2.7.0",
|
||||
|
|
@ -3386,6 +3354,26 @@
|
|||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
|
|
@ -3395,6 +3383,17 @@
|
|||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
|
|
@ -3406,6 +3405,30 @@
|
|||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/cacache": {
|
||||
"version": "15.3.0",
|
||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz",
|
||||
|
|
@ -3554,6 +3577,15 @@
|
|||
"iconv-lite": "^0.6.2"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/env-paths": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
|
||||
|
|
@ -3586,6 +3618,12 @@
|
|||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||
|
|
@ -3720,6 +3758,26 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||
|
|
@ -3759,6 +3817,12 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/ini": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
|
|
@ -3992,6 +4056,12 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
|
|
@ -4091,6 +4161,15 @@
|
|||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/p-map": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||
|
|
@ -4164,6 +4243,16 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/pump": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/rc": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||
|
|
@ -4179,6 +4268,20 @@
|
|||
"rc": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/retry": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
||||
|
|
@ -4189,6 +4292,26 @@
|
|||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
|
|
@ -4316,6 +4439,15 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
|
|
@ -4370,6 +4502,40 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/tar-fs": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
|
||||
"integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^2.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/tar-fs/node_modules/chownr": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/tar/node_modules/minipass": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||
|
|
@ -4399,6 +4565,12 @@
|
|||
"imurmurhash": "^0.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
|
@ -4425,49 +4597,18 @@
|
|||
"string-width": "^1.0.2 || 2 || 3 || 4"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/sqlite3/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz",
|
||||
"integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^2.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/testcafe-hammerhead": {
|
||||
"version": "24.5.18",
|
||||
"resolved": "https://registry.npmjs.org/testcafe-hammerhead/-/testcafe-hammerhead-24.5.18.tgz",
|
||||
|
|
@ -4627,6 +4768,26 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel-agent/node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/uglify-js": {
|
||||
"version": "3.19.3",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
|
||||
|
|
@ -4646,12 +4807,6 @@
|
|||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
|
|
@ -4670,12 +4825,6 @@
|
|||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
||||
|
|
|
|||
BIN
lib/rammerhead/sessions/.gitignore
vendored
Normal file
|
|
@ -16,9 +16,6 @@ class RammerheadSession extends Session {
|
|||
data = {};
|
||||
createdAt = Date.now();
|
||||
lastUsed = Date.now();
|
||||
// ID used to generate the global autocomplete session.
|
||||
// This must be a string containing 32 alphanumerical characters.
|
||||
static autocompleteId = 'collectsearchautocompleteresults';
|
||||
|
||||
/**
|
||||
* @param {object} options
|
||||
|
|
@ -54,12 +51,8 @@ class RammerheadSession extends Session {
|
|||
// disable http2. error handling from http2 proxy client to non-http2 user is too complicated to handle
|
||||
// (status code 0, for example, will crash rammerhead)
|
||||
this.isHttp2Disabled = () => true;
|
||||
if (id !== RammerheadSession.autocompleteId) {
|
||||
this.injectable.scripts.push(...prependScripts);
|
||||
this.injectable.scripts.push('/rammer/rammerhead.js');
|
||||
} else {
|
||||
this.injectable.scripts.length = 0;
|
||||
}
|
||||
this.injectable.scripts.push(...prependScripts);
|
||||
this.injectable.scripts.push('/rammer/rammerhead.js');
|
||||
|
||||
this.id = id;
|
||||
this.shuffleDict = disableShuffling ? null : StrShuffler.generateDictionary();
|
||||
|
|
|
|||
|
|
@ -143,7 +143,6 @@ class RammerheadSessionFileCache extends RammerheadSessionAbstractStore {
|
|||
* @returns {boolean} - returns true when a delete operation is performed
|
||||
*/
|
||||
delete(id) {
|
||||
if (id === RammerheadSession.autocompleteId) return false;
|
||||
this.logger.debug(`(FileCache.delete) deleting ${id}`);
|
||||
if (this.has(id)) {
|
||||
fs.unlinkSync(this._getSessionFilePath(id));
|
||||
|
|
|
|||
1
lib/rammerhead/src/client/hammerhead.min.js
vendored
Normal file
3
lib/rammerhead/src/client/rammerhead.min.js
vendored
Normal file
|
|
@ -79,11 +79,6 @@ module.exports = function setupRoutes(proxyServer, sessionStore, logger) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (id === RammerheadSession.autocompleteId) {
|
||||
res.end('Failure');
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStore.delete(id);
|
||||
res.end('Success');
|
||||
});
|
||||
|
|
@ -99,17 +94,4 @@ module.exports = function setupRoutes(proxyServer, sessionStore, logger) {
|
|||
const serverInfo = config.getServerInfo(req);
|
||||
res.end((serverInfo.port || '').toString());
|
||||
});
|
||||
|
||||
// Generate the global autocomplete session if it does not already exist.
|
||||
if (!sessionStore.has(RammerheadSession.autocompleteId)) {
|
||||
const session = new RammerheadSession({
|
||||
id: RammerheadSession.autocompleteId,
|
||||
dontConnectToData: true,
|
||||
});
|
||||
// workaround for saving the modified session to disk
|
||||
sessionStore.addSerializedSession(
|
||||
RammerheadSession.autocompleteId,
|
||||
session.serializeSession()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
4268
package-lock.json
generated
46
package.json
|
|
@ -1,24 +1,20 @@
|
|||
{
|
||||
"name": "holyunblocker",
|
||||
"version": "6.9.4",
|
||||
"version": "6.3.9",
|
||||
"repository": "https://github.com/QuiteAFancyEmerald/Holy-Unblocker",
|
||||
"description": "Holy Unblocker LTS is a web proxy service that helps you access websites that may be blocked by your network, government or policy all within your browser with no download or setup.",
|
||||
"description": "Holy Unblocker is a secure web proxy service with support for many sites.",
|
||||
"main": "backend.js",
|
||||
"engines": {
|
||||
"node": "20.x"
|
||||
},
|
||||
"scripts": {
|
||||
"fresh-install": "npm cache verify && npm update && npm ci && cd lib/rammerhead && npm ci",
|
||||
"fresh-start": "npm run fresh-install && npm start",
|
||||
"start": "npm stop && npm run build && npm run manual-start",
|
||||
"start": "npm install && npm run build && npm run manual-start",
|
||||
"restart": "node run-command.mjs stop start",
|
||||
"stop": "node run-command.mjs stop",
|
||||
"test": "npm run proxy-validator",
|
||||
"manual-start": "node run-command.mjs start",
|
||||
"kill": "node run-command.mjs stop kill",
|
||||
"build": "node run-command.mjs build && cd lib/rammerhead && npm run build",
|
||||
"clear": "node run-command.mjs clean",
|
||||
"clean": "node run-command.mjs clean format",
|
||||
"build": "node run-command.mjs build && cd lib/rammerhead && npm install && npm run build",
|
||||
"proxy-validator": "node proxyServiceValidator.js",
|
||||
"workflow-test": "node run-command.mjs workflow",
|
||||
"deployment": "npm install && npm run build && node backend.js"
|
||||
|
|
@ -31,24 +27,24 @@
|
|||
"author": "Titanium Network",
|
||||
"license": "GNU AFFERO",
|
||||
"dependencies": {
|
||||
"@fastify/helmet": "^13.0.2",
|
||||
"@fastify/static": "^8.3.0",
|
||||
"@mercuryworkshop/bare-mux": "^2.1.7",
|
||||
"@mercuryworkshop/epoxy-transport": "^2.1.28",
|
||||
"@mercuryworkshop/libcurl-transport": "^1.5.1",
|
||||
"@mercuryworkshop/scramjet": "https://github.com/MercuryWorkshop/scramjet/releases/download/latest/mercuryworkshop-scramjet-2.0.0-alpha.tgz",
|
||||
"@mercuryworkshop/wisp-js": "^0.4.0",
|
||||
"@titaniumnetwork-dev/ultraviolet": "^3.2.10",
|
||||
"axios": "^1.13.2",
|
||||
"chii": "^1.15.5",
|
||||
"fastify": "^5.6.1",
|
||||
"pm2": "^6.0.13",
|
||||
"puppeteer": "^24.29.1",
|
||||
"utf-8-validate": "^6.0.5",
|
||||
"ws": "^8.18.3"
|
||||
"@fastify/helmet": "^12.0.1",
|
||||
"@fastify/static": "^8.0.2",
|
||||
"@mercuryworkshop/bare-as-module3": "^2.2.5",
|
||||
"@mercuryworkshop/bare-mux": "^2.1.6",
|
||||
"@mercuryworkshop/epoxy-transport": "^2.1.26",
|
||||
"@mercuryworkshop/libcurl-transport": "^1.3.12",
|
||||
"@titaniumnetwork-dev/ultraviolet": "~3.2.10",
|
||||
"@tomphttp/bare-server-node": "^2.0.5",
|
||||
"axios": "^1.7.7",
|
||||
"fastify": "^5.1.0",
|
||||
"mime-types": "^2.1.35",
|
||||
"pm2": "^5.4.2",
|
||||
"puppeteer": "^23.7.1",
|
||||
"wisp-server-node": "^1.1.7",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/node": "^7.28.0",
|
||||
"esbuild": "^0.25.12"
|
||||
"@babel/node": "^7.26.0",
|
||||
"esbuild": "^0.24.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const testEndpoint = async (url) => {
|
|||
const response = await axios.get(url);
|
||||
return response.status === 200;
|
||||
} catch (error) {
|
||||
console.error(`Error ${error.code} while testing ${url}:`, error.message);
|
||||
console.error(`Error while testing ${url}:`, error.message);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
|
@ -17,9 +17,8 @@ const testEndpoint = async (url) => {
|
|||
const generateUrl = async (omniboxId, urlPath, errorPrefix = 'failure') => {
|
||||
// Wait for the document to load before getting the omnibox.
|
||||
await new Promise((resolve) => {
|
||||
const waitLonger = () => setTimeout(resolve, 5000);
|
||||
if (document.readyState === 'complete') waitLonger();
|
||||
else window.addEventListener('load', waitLonger);
|
||||
if (document.readyState === 'complete') resolve();
|
||||
else window.addEventListener('load', resolve);
|
||||
});
|
||||
|
||||
let omnibox = document.getElementById(omniboxId);
|
||||
|
|
@ -83,24 +82,28 @@ const testServerResponse = async () => {
|
|||
'http://localhost:8080/',
|
||||
'http://localhost:8080/test-404',
|
||||
'http://localhost:8080/browsing',
|
||||
'http://localhost:8080/physics',
|
||||
'http://localhost:8080/networking',
|
||||
'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/books',
|
||||
'http://localhost:8080/dictionary',
|
||||
'http://localhost:8080/catalogue',
|
||||
'http://localhost:8080/textbook',
|
||||
'http://localhost:8080/math',
|
||||
'http://localhost:8080/wiki',
|
||||
'http://localhost:8080/software',
|
||||
'http://localhost:8080/whiteboard',
|
||||
'http://localhost:8080/notebook',
|
||||
'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-1735118314.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',
|
||||
|
|
@ -109,20 +112,16 @@ const testServerResponse = async () => {
|
|||
'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/gmt/index.js',
|
||||
'http://localhost:8080/gmt/worker.js',
|
||||
'http://localhost:8080/epoch/index.mjs',
|
||||
'http://localhost:8080/worker/working.all.js',
|
||||
'http://localhost:8080/worker/working.sw.js',
|
||||
'http://localhost:8080/worker/working.sw-blacklist.js',
|
||||
'http://localhost:8080/network/networking.bundle.js',
|
||||
'http://localhost:8080/network/networking.sw.js',
|
||||
'http://localhost:8080/network/networking.config.js',
|
||||
'http://localhost:8080/network/workerware.js',
|
||||
'http://localhost:8080/network/WWError.js',
|
||||
'http://localhost:8080/baremux/index.js',
|
||||
'http://localhost:8080/baremux/worker.js',
|
||||
'http://localhost:8080/epoxy/index.mjs',
|
||||
'http://localhost:8080/config/config.bundle.js',
|
||||
'http://localhost:8080/config/sw.js',
|
||||
'http://localhost:8080/config/config.config.js',
|
||||
'http://localhost:8080/config/workerware.js',
|
||||
'http://localhost:8080/config/WWError.js',
|
||||
];
|
||||
|
||||
|
||||
const results = await Promise.all(endpoints.map(testEndpoint));
|
||||
const allPassed = results.every((result) => result);
|
||||
|
||||
|
|
@ -144,6 +143,7 @@ const testCommonJSOnPage = async () => {
|
|||
'--enable-features=ServiceWorker',
|
||||
'--enable-features=InsecureOrigins',
|
||||
],
|
||||
devtools: true,
|
||||
headless: true,
|
||||
ignoreHTTPSErrors: true,
|
||||
});
|
||||
|
|
@ -162,7 +162,7 @@ const testCommonJSOnPage = async () => {
|
|||
const testRammerhead = async () => {
|
||||
const omniboxId = 'pr-rh',
|
||||
urlPath = 'example.com';
|
||||
await page.goto('http://localhost:8080/physics');
|
||||
await page.goto('http://localhost:8080/rammerhead');
|
||||
const generatedUrl = await page.evaluate(generateUrl, omniboxId, urlPath);
|
||||
const testResults = {};
|
||||
testResults.rammerhead = generatedUrl;
|
||||
|
|
@ -183,42 +183,59 @@ const testCommonJSOnPage = async () => {
|
|||
return rammerheadTestPassed;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
xx
|
||||
xx xx
|
||||
xxx xx
|
||||
xxx xx
|
||||
xxx xx
|
||||
xxx xx
|
||||
xx xx
|
||||
xx xx
|
||||
xx
|
||||
xx
|
||||
|
||||
|
||||
|
||||
|
||||
x x
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
xxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxx xxxxx
|
||||
xxxx xxx
|
||||
xxx xxx
|
||||
xxx xx
|
||||
xx xx
|
||||
xx xx
|
||||
xxx x
|
||||
xx x
|
||||
xx xx
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
WIP detectordetector eval changes
|
||||
|
||||
xx
|
||||
xx xx
|
||||
xxx xx
|
||||
xxx xx
|
||||
xxx xx
|
||||
xxx xx
|
||||
xx xx
|
||||
xx xx
|
||||
xx
|
||||
xx
|
||||
|
||||
|
||||
|
||||
|
||||
x x
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
xxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxx xxxxx
|
||||
xxxx xxx
|
||||
xxx xxx
|
||||
xxx xx
|
||||
xx xx
|
||||
xx xx
|
||||
xxx x
|
||||
xx x
|
||||
xx xx
|
||||
const detectoreval = detectordetector;
|
||||
|
||||
*/
|
||||
const filterCheck = async () => {
|
||||
const result = await page.evaluate(detectoreval);
|
||||
|
||||
const filterCheckPassed =
|
||||
console.log(
|
||||
'Detection Result:', result
|
||||
);
|
||||
return filterCheckPassed;
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
const testUltraviolet = async () => {
|
||||
const omniboxId = 'pr-uv',
|
||||
errorPrefix = 'failure',
|
||||
|
|
@ -227,7 +244,7 @@ xx xx
|
|||
path: 'example.com',
|
||||
title: 'Example Domain',
|
||||
});
|
||||
await page.goto('http://localhost:8080/networking');
|
||||
await page.goto('http://localhost:8080/ultraviolet');
|
||||
const generatedUrl = await page.evaluate(
|
||||
generateUrl,
|
||||
omniboxId,
|
||||
|
|
@ -241,9 +258,8 @@ xx xx
|
|||
|
||||
await new Promise((resolve) => {
|
||||
const waitForDocument = () => {
|
||||
const waitLonger = () => setTimeout(resolve, 5000);
|
||||
if (document.readyState === 'complete') waitLonger();
|
||||
else window.addEventListener('load', waitLonger);
|
||||
if (document.readyState === 'complete') resolve();
|
||||
else window.addEventListener('load', resolve);
|
||||
},
|
||||
// Wait until a service worker is registered before continuing.
|
||||
// Also check again to make sure the document is loaded.
|
||||
|
|
@ -315,12 +331,12 @@ xx xx
|
|||
};
|
||||
|
||||
// Run tests for Rammerhead and Ultraviolet.
|
||||
await page.goto('http://localhost:8080/');
|
||||
const rammerheadPassed = await testRammerhead();
|
||||
const ultravioletPassed = await testUltraviolet();
|
||||
//const filterCheckPassed = await filterCheck();
|
||||
|
||||
if (rammerheadPassed && ultravioletPassed) {
|
||||
console.log('Both tests passed.');
|
||||
if (rammerheadPassed && ultravioletPassed /* && filterCheckPassed */ ) {
|
||||
console.log('All tests passed.');
|
||||
process.exitCode = 0;
|
||||
} else {
|
||||
console.error('Tests failed.');
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
services:
|
||||
- type: web
|
||||
runtime: docker
|
||||
name: hu-lts
|
||||
repo: https://github.com/QuiteAFancyEmerald/Holy-Unblocker
|
||||
region: oregon
|
||||
name: holy-forest-1234
|
||||
env: node
|
||||
plan: free
|
||||
branch: master
|
||||
startCommand: npm start
|
||||
267
run-command.mjs
|
|
@ -1,36 +1,30 @@
|
|||
import {
|
||||
writeFileSync,
|
||||
unlinkSync,
|
||||
mkdirSync,
|
||||
readdirSync,
|
||||
lstatSync,
|
||||
copyFileSync,
|
||||
rmSync,
|
||||
existsSync,
|
||||
} from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { readFile, writeFile, unlink, mkdir, rm } from 'node:fs/promises';
|
||||
import { exec, fork } from 'node:child_process';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { build } from 'esbuild';
|
||||
import {
|
||||
config,
|
||||
serverUrl,
|
||||
flatAltPaths,
|
||||
splashRandom,
|
||||
} from './src/routes.mjs';
|
||||
import { epoxyPath } from '@mercuryworkshop/epoxy-transport';
|
||||
import { libcurlPath } from '@mercuryworkshop/libcurl-transport';
|
||||
import { baremuxPath } from '@mercuryworkshop/bare-mux/node';
|
||||
import { uvPath } from '@titaniumnetwork-dev/ultraviolet';
|
||||
import paintSource from './src/source-rewrites.mjs';
|
||||
import { loadTemplates, tryReadFile } from './src/templates.mjs';
|
||||
import ecosystem from './ecosystem.config.js';
|
||||
|
||||
const scramjetPath = join(
|
||||
dirname(fileURLToPath(import.meta.url)),
|
||||
'node_modules/@mercuryworkshop/scramjet/dist'
|
||||
);
|
||||
// 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)))
|
||||
),
|
||||
ecosystemConfig = Object.freeze(
|
||||
ecosystem.apps.find((app) => app.name === 'HolyUBLTS') || ecosystem.apps[0]
|
||||
);
|
||||
|
||||
const serverUrl = ((base) => {
|
||||
try {
|
||||
base = new URL(config.host);
|
||||
} catch (e) {
|
||||
base = new URL('http://a');
|
||||
base.host = config.host;
|
||||
}
|
||||
base.port =
|
||||
ecosystemConfig[config.production ? 'env_production' : 'env'].PORT;
|
||||
return Object.freeze(base);
|
||||
})();
|
||||
|
||||
// This constant is copied over from /src/server.mjs.
|
||||
const shutdown = fileURLToPath(new URL('./src/.shutdown', import.meta.url));
|
||||
|
||||
// Run each command line argument passed after node run-command.mjs.
|
||||
|
|
@ -45,7 +39,7 @@ commands: for (let i = 2; i < process.argv.length; i++)
|
|||
'npx pm2 start ecosystem.config.js --env production',
|
||||
(error, stdout) => {
|
||||
if (error) throw error;
|
||||
console.log('[Start]', stdout);
|
||||
console.log(stdout);
|
||||
}
|
||||
);
|
||||
// Handle setup on Windows differently from platforms with POSIX-compliant
|
||||
|
|
@ -53,10 +47,10 @@ commands: for (let i = 2; i < process.argv.length; i++)
|
|||
else if (process.platform === 'win32')
|
||||
exec('START /MIN "" node backend.js', (error, stdout) => {
|
||||
if (error) {
|
||||
console.error('[Start Error]', error);
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
console.log('[Start]', stdout);
|
||||
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.
|
||||
|
|
@ -73,7 +67,7 @@ commands: for (let i = 2; i < process.argv.length; i++)
|
|||
// 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': {
|
||||
writeFileSync(shutdown, '');
|
||||
await writeFile(shutdown, '');
|
||||
let timeoutId,
|
||||
hasErrored = false;
|
||||
try {
|
||||
|
|
@ -82,7 +76,7 @@ commands: for (let i = 2; i < process.argv.length; i++)
|
|||
* immediately if checking the server on localhost and the port is unused.
|
||||
*/
|
||||
const response = await Promise.race([
|
||||
fetch(new URL(serverUrl.pathname + 'test-shutdown', serverUrl)),
|
||||
fetch(new URL('/test-shutdown', serverUrl)),
|
||||
new Promise((resolve) => {
|
||||
timeoutId = setTimeout(() => {
|
||||
resolve('Error');
|
||||
|
|
@ -93,12 +87,12 @@ commands: for (let i = 2; i < process.argv.length; i++)
|
|||
if (response === 'Error') throw new Error('Server is unresponsive.');
|
||||
} catch (e) {
|
||||
// Remove the temporary shutdown file since the server didn't remove it.
|
||||
unlinkSync(shutdown);
|
||||
await unlink(shutdown);
|
||||
// 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('[Stop Error]', e);
|
||||
console.error(e);
|
||||
// Stop here unless Node will be killed later.
|
||||
if (!process.argv.slice(i + 1).includes('kill')) hasErrored = true;
|
||||
}
|
||||
|
|
@ -107,10 +101,10 @@ commands: for (let i = 2; i < process.argv.length; i++)
|
|||
if (config.production && !process.argv.slice(i + 1).includes('kill'))
|
||||
exec('npx pm2 stop ecosystem.config.js', (error, stdout) => {
|
||||
if (error) {
|
||||
console.error('[Stop Error]', error);
|
||||
console.error(error);
|
||||
hasErrored = true;
|
||||
}
|
||||
console.log('[Stop]', stdout);
|
||||
console.log(stdout);
|
||||
});
|
||||
// Do not continue executing commands since the server was unable to be stopped.
|
||||
// Mostly implemented to prevent duplicating Node instances with npm restart.
|
||||
|
|
@ -123,184 +117,20 @@ commands: for (let i = 2; i < process.argv.length; i++)
|
|||
|
||||
case 'build': {
|
||||
const dist = fileURLToPath(new URL('./views/dist', import.meta.url));
|
||||
rmSync(dist, { force: true, recursive: true });
|
||||
mkdirSync(dist);
|
||||
|
||||
/* The archive directory is excluded from this process, since source
|
||||
* rewrites are not intended to be used by any of those files.
|
||||
* Assets are compiled separately, before the rest of the files.
|
||||
*/
|
||||
const ignoredDirectories = ['dist', 'assets', 'uv', 'scram', 'archive'];
|
||||
const ignoredFileTypes = /\.map$/;
|
||||
|
||||
const compile = (
|
||||
dir,
|
||||
base = '',
|
||||
outDir = '',
|
||||
initialDir = dir,
|
||||
applyRewrites = initialDir === './views'
|
||||
) =>
|
||||
readdirSync(base + dir).forEach((file) => {
|
||||
let oldLocation = new URL(
|
||||
file,
|
||||
new URL(base + dir + '/', import.meta.url)
|
||||
);
|
||||
if (
|
||||
(ignoredDirectories.includes(file) && applyRewrites) ||
|
||||
ignoredFileTypes.test(file)
|
||||
)
|
||||
return;
|
||||
const fileStats = lstatSync(oldLocation),
|
||||
targetPath = fileURLToPath(
|
||||
new URL(
|
||||
'./views/dist/' +
|
||||
outDir +
|
||||
(base + dir + '/').slice(initialDir.length + 1) +
|
||||
((!config.usingSEO && flatAltPaths['files/' + file]) || file),
|
||||
import.meta.url
|
||||
)
|
||||
);
|
||||
if (fileStats.isFile() && !existsSync(targetPath))
|
||||
if (/\.(?:html|js|css|json|txt|xml)$/.test(file) && applyRewrites)
|
||||
writeFileSync(
|
||||
targetPath,
|
||||
paintSource(
|
||||
loadTemplates(
|
||||
tryReadFile(base + dir + '/' + file, import.meta.url, false)
|
||||
)
|
||||
)
|
||||
);
|
||||
else copyFileSync(base + dir + '/' + file, targetPath);
|
||||
else if (fileStats.isDirectory()) {
|
||||
if (!existsSync(targetPath)) mkdirSync(targetPath);
|
||||
compile(file, base + dir + '/', outDir, initialDir, applyRewrites);
|
||||
}
|
||||
});
|
||||
|
||||
const localAssetDirs = ['assets', 'scram', 'uv'];
|
||||
for (const path of localAssetDirs) {
|
||||
mkdirSync('./views/dist/' + path);
|
||||
compile('./views/' + path, '', path + '/', './views/' + path, true);
|
||||
}
|
||||
|
||||
// Combine scripts from the corresponding node modules into the same
|
||||
// dist-generated directories for compiling, and avoid overwriting files.
|
||||
const compilePaths = {
|
||||
epoxy: epoxyPath,
|
||||
libcurl: libcurlPath,
|
||||
baremux: baremuxPath,
|
||||
uv: uvPath,
|
||||
scram: scramjetPath,
|
||||
chii: 'node_modules/chii',
|
||||
};
|
||||
for (const path of Object.entries(compilePaths)) {
|
||||
const prefix = path[0] + '/',
|
||||
prefixUrl = new URL('./views/dist/' + prefix, import.meta.url);
|
||||
if (!existsSync(prefixUrl)) mkdirSync(prefixUrl);
|
||||
|
||||
compile(path[1].slice(path[1].indexOf('node_modules')), '', prefix);
|
||||
}
|
||||
|
||||
// Minify the scripts and stylesheets upon compiling, if enabled in config.
|
||||
if (config.minifyScripts)
|
||||
await build({
|
||||
entryPoints: [
|
||||
'./views/dist/uv/**/*.js',
|
||||
'./views/dist/scram/**/*.js',
|
||||
'./views/dist/scram/**/*.wasm.wasm',
|
||||
'./views/dist/assets/js/**/*.js',
|
||||
'./views/dist/assets/css/**/*.css',
|
||||
],
|
||||
platform: 'browser',
|
||||
sourcemap: true,
|
||||
bundle: true,
|
||||
minify: true,
|
||||
loader: { '.wasm.wasm': 'copy' },
|
||||
external: ['*.png', '*.jpg', '*.jpeg', '*.webp', '*.svg'],
|
||||
outdir: dist,
|
||||
allowOverwrite: true,
|
||||
});
|
||||
|
||||
compile('./views');
|
||||
|
||||
// Compile the archive directory separately.
|
||||
mkdirSync('./views/dist/archive');
|
||||
if (existsSync('./views/archive'))
|
||||
compile('./views/archive', '', 'archive/');
|
||||
|
||||
const createFile = (location, text) => {
|
||||
writeFileSync(
|
||||
fileURLToPath(new URL('./views/dist/' + location, import.meta.url)),
|
||||
paintSource(loadTemplates(text))
|
||||
);
|
||||
};
|
||||
|
||||
createFile('assets/json/splash.json', JSON.stringify(splashRandom));
|
||||
|
||||
if (config.disguiseFiles) {
|
||||
const compress = async (dir, recursive = false) => {
|
||||
for (const file of readdirSync(dir)) {
|
||||
const fileLocation = dir + '/' + file;
|
||||
if (file.endsWith('.html'))
|
||||
writeFileSync(
|
||||
fileLocation,
|
||||
Buffer.from(
|
||||
await new Response(
|
||||
new Blob([
|
||||
tryReadFile(fileLocation, import.meta.url, false),
|
||||
])
|
||||
.stream()
|
||||
.pipeThrough(new CompressionStream('gzip'))
|
||||
).arrayBuffer()
|
||||
)
|
||||
);
|
||||
else if (
|
||||
recursive &&
|
||||
lstatSync(fileLocation).isDirectory() &&
|
||||
file !== 'deobf'
|
||||
)
|
||||
await compress(fileLocation, true);
|
||||
}
|
||||
};
|
||||
await compress('./views/dist');
|
||||
await compress('./views/dist/pages', true);
|
||||
await compress('./views/dist/archive', true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Delete all files in target locations. This is primarily used to manage
|
||||
// Rammerhead's cache output.
|
||||
case 'clean': {
|
||||
// If including Rammerhead sessions, be careful to not let the global
|
||||
// autocomplete session be deleted without restarting the server.
|
||||
const targetDirs = ['./lib/rammerhead/cache-js'];
|
||||
for (const targetDir of targetDirs)
|
||||
try {
|
||||
const targetPath = fileURLToPath(new URL(targetDir, import.meta.url));
|
||||
rmSync(targetPath, { force: true, recursive: true });
|
||||
mkdirSync(targetPath);
|
||||
writeFileSync(
|
||||
fileURLToPath(new URL(targetDir + '/.gitkeep', import.meta.url)),
|
||||
''
|
||||
);
|
||||
console.log(
|
||||
'[Clean]',
|
||||
`Reset folder ${targetDir} at ${new Date().toISOString()}.`
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('[Clean Error]', e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'format': {
|
||||
exec('npx prettier --write .', (error, stdout) => {
|
||||
if (error) {
|
||||
console.error('[Clean Error]', error);
|
||||
}
|
||||
console.log('[Clean]', stdout);
|
||||
await rm(dist, { force: true, recursive: true });
|
||||
await mkdir(dist);
|
||||
await build({
|
||||
entryPoints: [
|
||||
'./views/network/**/*.js',
|
||||
'./views/assets/js/**/*.js',
|
||||
'./views/assets/css/**/*.css',
|
||||
],
|
||||
platform: 'browser',
|
||||
sourcemap: true,
|
||||
bundle: true,
|
||||
minify: true,
|
||||
external: ['*.png', '*.jpg', '*.jpeg', '*.webp', '*.svg'],
|
||||
outdir: dist,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
@ -314,14 +144,14 @@ commands: for (let i = 2; i < process.argv.length; i++)
|
|||
exec(
|
||||
'( npx pm2 delete ecosystem.config.js ) ; taskkill /F /IM node*',
|
||||
(error, stdout) => {
|
||||
console.log('[Kill]', stdout);
|
||||
console.log(stdout);
|
||||
}
|
||||
);
|
||||
else
|
||||
exec(
|
||||
'npx pm2 delete ecosystem.config.js; pkill node',
|
||||
(error, stdout) => {
|
||||
console.log('[Kill]', stdout);
|
||||
console.log(stdout);
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
|
@ -343,8 +173,7 @@ commands: for (let i = 2; i < process.argv.length; i++)
|
|||
tempServer.stderr.on('data', (stderr) => {
|
||||
// The temporary server will print startup errors that aren't deprecation
|
||||
// warnings; stop the process and return an error exit code upon doing so.
|
||||
if (stderr.toString().indexOf('DeprecationWarning') >= 0)
|
||||
return console.log(stderr.toString());
|
||||
if (stderr.toString().indexOf('DeprecationWarning') >= 0) return;
|
||||
console.error(stderr.toString());
|
||||
tempServer.kill();
|
||||
process.exitCode = 1;
|
||||
|
|
|
|||
5
serve.sh
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Start Tor in the background; note that this may take awhile even after the app starts
|
||||
tor &
|
||||
|
||||
exec node backend.js
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
{
|
||||
"title": "HU LTS",
|
||||
"host": "0.0.0.0",
|
||||
"pathname": "/",
|
||||
"minifyScripts": true,
|
||||
"randomizeIdentifiers": true,
|
||||
"production": false,
|
||||
"disguiseFiles": true,
|
||||
"usingSEO": false
|
||||
"production": false
|
||||
}
|
||||
|
|
@ -1,91 +1,22 @@
|
|||
{
|
||||
"chars": ["­", "​", "­"],
|
||||
"keywords": [
|
||||
"Pencil",
|
||||
"Notebook",
|
||||
"Pad",
|
||||
"Document",
|
||||
"Text",
|
||||
"Editor",
|
||||
"Writing",
|
||||
"Notes",
|
||||
"Markdown",
|
||||
"Note-taking",
|
||||
"Note",
|
||||
"Notepad",
|
||||
"Notebooks",
|
||||
"Textpad",
|
||||
"Text Pad",
|
||||
"Text Editor",
|
||||
"Text Editors",
|
||||
"Write",
|
||||
"Writing App",
|
||||
"Writing Apps",
|
||||
"Writer",
|
||||
"Writers",
|
||||
"Jotter",
|
||||
"Jotters",
|
||||
"Diary",
|
||||
"Diaries"
|
||||
"Example1",
|
||||
"Example2",
|
||||
"Example3",
|
||||
"Example4",
|
||||
"Example5",
|
||||
"Example6",
|
||||
"Example7",
|
||||
"Example8",
|
||||
"Example9"
|
||||
],
|
||||
"content": [
|
||||
"This is a document with text and editing features. You can write notes, create lists, and format your text using Markdown syntax. It's a simple and efficient way to keep track of your ideas and tasks.",
|
||||
"This example is a sample text that demonstrates the capabilities of the text editor. You can easily create headings, bold or italicize text, and add links or images. The editor supports various formatting options to enhance your writing experience.",
|
||||
"Feel free to explore the features of this text editor. You can create bullet points, numbered lists, and even code snippets. The editor is designed to be user-friendly and intuitive, making it easy for anyone to use.",
|
||||
"Whether you're jotting down quick notes or composing longer documents, this text editor has you covered. You can save your work, export it in different formats, and even collaborate with others in real-time.",
|
||||
"With this text editor, you can organize your thoughts and ideas effectively. Use headings to structure your content, and take advantage of the various formatting options to make your text visually appealing.",
|
||||
"You can also use this editor to write blog posts, articles, or any other type of content. The Markdown syntax allows for easy formatting, and the live preview feature lets you see how your text will look as you write.",
|
||||
"Overall, this text editor is a versatile tool for anyone who needs to write and edit text. Whether you are a student, professional, or casual writer, you'll find it to be a valuable resource for your writing needs.",
|
||||
"Start writing your next masterpiece today with this powerful and user-friendly text editor. Happy writing!"
|
||||
"Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1Example1",
|
||||
"Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2Example2"
|
||||
],
|
||||
"delimiter": "*",
|
||||
"textMasks": {
|
||||
"Holy Unblocker": ["H*ol*y *Un*b*lo*c*k*er"],
|
||||
"Holy Unblocker LTS": ["H*ol*y *Un*b*lo*c*k*er *L*T*S"],
|
||||
"Webretro": ["W*e*b*r*e*t*r*o"],
|
||||
"Ruffle": ["R*u*f*f*l*e"],
|
||||
"Tab Cloaker": ["T*a*b C*l*o*a*k*e*r"],
|
||||
"Tab Cloakers": ["T*a*b C*l*o*a*k*e*rs"],
|
||||
"Search": ["S*e*a*r*c*h"],
|
||||
"Searching": ["S*e*a*r*c*h*i*n*g"],
|
||||
"Freely": ["F*r*e*e*l*y"],
|
||||
"Free": ["F*r*e*e"],
|
||||
"Surfing": ["S*u*r*f*i*n*g"],
|
||||
"Surf": ["S*u*r*f"],
|
||||
"VPN": ["V*P*N"],
|
||||
"VPNs": ["V*P*N*s"],
|
||||
"Server": ["S*e*r*v*e*r"],
|
||||
"Servers": ["S*e*r*v*e*r*s"],
|
||||
"Network": ["N*e*t*w*o*r*k"],
|
||||
"Networks": ["N*e*t*w*o*r*k*s"],
|
||||
"Connection": ["C*o*n*n*e*c*t*i*o*n"],
|
||||
"Connections": ["C*o*n*n*e*c*t*i*o*n*s"],
|
||||
"Privacy": ["P*r*i*v*a*c*y"],
|
||||
"Private": ["P*r*i*v*a*t*e"],
|
||||
"Games": ["G*a*m*e*s"],
|
||||
"Croxy": ["Cr*o*x*y"],
|
||||
"CroxyProxy": ["Cr*o*x*y*Pr*o*x*y"],
|
||||
"Proxy": ["Pr*ox*y", "P*ro*x*y", "Pro*x*y"],
|
||||
"Proxies": ["Pr*ox*i*es", "P*ro*x*ies", "Pro*x*i*es", "Pr*ox*ie*s"],
|
||||
"Proxied": ["Pr*ox*i*e*d", "P*ro*x*ied", "Pro*x*i*ed", "Pr*ox*ie*d"],
|
||||
"Proxying": ["Pr*o*x*y*i*n*g", "P*r*o*x*y*i*n*g"],
|
||||
"Unblock": ["Un*b*lo*c*k", "Un*bl*o*c*k", "Unb*lo*c*k"],
|
||||
"Unblocked": ["Un*b*lo*c*k*e*d", "Un*bl*o*c*k*e*d", "Unb*lo*c*k*e*d"],
|
||||
"Unblocking": ["Un*b*lo*c*k*i*n*g", "Un*bl*o*c*k*i*n*g", "Unb*lo*c*k*i*n*g"],
|
||||
"Unblocks": ["Un*b*lo*c*k*s", "Un*bl*o*c*k*s", "Unb*lo*c*k*s"],
|
||||
"Unblocker": ["Un*b*lo*c*k*er", "Un*bl*o*c*k*er", "Unb*lo*c*k*er"],
|
||||
"Unblockers": ["Un*b*lo*c*k*ers", "Un*bl*o*c*k*ers", "Unb*lo*c*k*ers"],
|
||||
"Bypass": ["By*pa*ss", "Byp*as*s", "B*y*p*a*s*s"],
|
||||
"Titanium Network": ["Ti*ta*ni*um Ne*tw*or*k"],
|
||||
"Wisp": ["W*i*s*p"],
|
||||
"Tor": ["T*o*r"],
|
||||
"Onion": ["O*n*i*o*n"],
|
||||
"Ultraviolet": ["Ul*t*ra*vi*o*le*t"],
|
||||
"Scramjet": ["Sc*r*a*m*j*e*t"],
|
||||
"Rammerhead": ["Ra*m*m*e*r*h*e*a*d"]
|
||||
},
|
||||
"splash": [
|
||||
"{{mask}}{{This version is the public build of the HU LTS project, and it's being worked on via the master branch! Stuff will NOT work!}}"
|
||||
"This version is the public HU LTS build of the web proxy service project and being worked on (master branch)! Stuff will NOT work!"
|
||||
],
|
||||
"version": ["6.9.3"]
|
||||
}
|
||||
"version": ["6.3.9"]
|
||||
}
|
||||
135
src/express.mjs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
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();
|
||||
|
||||
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',
|
||||
];
|
||||
|
||||
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) => {
|
||||
/*
|
||||
if (bare.shouldRoute(req)) {
|
||||
bare.routeRequest(req, res);
|
||||
} else
|
||||
*/
|
||||
if (shouldRouteRh(req)) {
|
||||
routeRhRequest(req, res);
|
||||
} else {
|
||||
app(req, res);
|
||||
}
|
||||
});
|
||||
|
||||
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/')) {
|
||||
wisp.routeRequest(req, socket, head);
|
||||
}
|
||||
});
|
||||
|
||||
// Apply Helmet middleware for security.
|
||||
app.use(
|
||||
helmet({
|
||||
contentSecurityPolicy: false, // Disable CSP
|
||||
})
|
||||
);
|
||||
|
||||
/* All website files are stored in the /views directory.
|
||||
* 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
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
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.disable('x-powered-by');
|
||||
|
||||
// Redundant code since 404 is handled elsewhere; left here as insurance.
|
||||
app.use((req, res) => {
|
||||
res.status(404).send(paintSource(loadTemplates(text404)));
|
||||
});
|
||||
|
||||
server.listen(port);
|
||||
console.log('Holy Unblocker is listening on port ' + port + '.');
|
||||
88
src/randomization.mjs
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
import pkg from './routes.mjs';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
export { paintSource, preloaded404, tryReadFile };
|
||||
const {
|
||||
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
|
||||
* changes with each time it is loaded.
|
||||
*/
|
||||
const randomListItem = (lis) => () => lis[(Math.random() * lis.length) | 0],
|
||||
charset = /­|​|­|<wbr>/gi,
|
||||
getRandomChar = randomListItem(charRandom),
|
||||
insertCharset = (str) => str.replace(charset, getRandomChar),
|
||||
getRandomSplash = randomListItem(splashRandom),
|
||||
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-HUCOOKINGINSERT-DONOTDELETE -->',
|
||||
getCookingText
|
||||
),
|
||||
// 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.
|
||||
paintSource = (str) =>
|
||||
insertCharset(hutaoInsert(versionInsert(insertCooking(cacheBusting(str))))),
|
||||
// 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.
|
||||
tryReadFile = (file, baseUrl) => {
|
||||
file = fileURLToPath(new URL(file, baseUrl));
|
||||
return existsSync(file + '')
|
||||
? readFileSync(file + '', 'utf8')
|
||||
: preloaded404;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
All of this is now old code.
|
||||
The newer versions of these functions are directly above.
|
||||
|
||||
function randomListItem(lis) {
|
||||
return lis[Math.floor(Math.random() * lis.length)];
|
||||
}
|
||||
|
||||
function insertCharset(str) {
|
||||
return str.replace(/­|​|­|<wbr>/g, function() { return randomListItem(charRandom); });
|
||||
}
|
||||
|
||||
function hutaoInsert(str) {
|
||||
return str.replace(/<!--HUTAOWOA-->/g, function() { return randomListItem(splashRandom); });
|
||||
}
|
||||
|
||||
function insertCooking(str) {
|
||||
return str.replace(/<!-- IMPORTANT-HUCOOKINGINSERT-DONOTDELETE -->/g, function() { return '<span style="display: none;" data-fact="' + randomListItem(vegetables) + '" data-type="' + randomListItem(vegetables) + '">' + randomListItem(cookingInserts) + '</span>'; }); // this needs to be inside a function, so that not every string is the same
|
||||
}
|
||||
|
||||
function cacheBusting(str) {
|
||||
for (var item of Object.entries(cacheBustList)) {
|
||||
str = str.replace(new RegExp(item[0], "g"), item[1]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
export function paintSource(str) {
|
||||
return insertCharset(hutaoInsert(insertCooking(cacheBusting(str))));
|
||||
}
|
||||
|
||||
export function tryReadFile(file) {
|
||||
return existsSync(file) ? readFileSync(file, 'utf8') : text404;
|
||||
}
|
||||
|
||||
*/
|
||||
263
src/routes.mjs
|
|
@ -1,55 +1,21 @@
|
|||
import { readFileSync } from 'node:fs';
|
||||
import ecosystem from '../ecosystem.config.js';
|
||||
import { readFileSync } from 'fs';
|
||||
import path from 'path';
|
||||
import { readFile } from 'fs/promises';
|
||||
|
||||
// For toggling SEO display and more, see the config.json file.
|
||||
const config = Object.freeze(
|
||||
JSON.parse(readFileSync(new URL('../config.json', import.meta.url)))
|
||||
const insert = JSON.parse(
|
||||
await readFile(new URL('./data.json', import.meta.url))
|
||||
);
|
||||
|
||||
const ecosystemConfig = Object.freeze(
|
||||
ecosystem.apps.find((app) => app.name === 'HolyUB') || ecosystem.apps[0]
|
||||
const __dirname = path.resolve();
|
||||
|
||||
const text404 = readFileSync(
|
||||
path.normalize(__dirname + '/views/error.html'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
/* 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) => {
|
||||
try {
|
||||
base = new URL(config.host);
|
||||
} catch (e) {
|
||||
base = new URL('http://a');
|
||||
base.host = config.host;
|
||||
}
|
||||
base.port =
|
||||
ecosystemConfig[config.production ? 'env_production' : 'env'].PORT;
|
||||
base.pathname =
|
||||
(config.pathname || '/').replace(/\/+$|[^\w\/\.-]+/g, '') + '/';
|
||||
return Object.freeze(base);
|
||||
})();
|
||||
|
||||
let pages = {
|
||||
/* If you are trying to add pages or assets in the root folder and
|
||||
* NOT entire folders, check the routes below and add it manually.
|
||||
* If you change route names here, also check the altPaths variable below.
|
||||
*/
|
||||
|
||||
// Set the default page for when no pathname is supplied. Be sure to change the
|
||||
// option for disguiseFiles if the entry point should be hidden.
|
||||
default: config.disguiseFiles ? 'login' : 'index',
|
||||
const pages = {
|
||||
index: 'index.html',
|
||||
'manifest.json': 'manifest.json',
|
||||
|
||||
/* Users must visit this route if disguiseFiles is enabled. The page loader only
|
||||
* requests the site's contents if it has a local key, which is given by this page.
|
||||
* Be sure to update the following line(s) in src/server.mjs if you change this
|
||||
* variable:
|
||||
* let exemptPages = ['login', .........];
|
||||
* if (pages.default === 'login') exemptPages.push('');
|
||||
*/
|
||||
login: 'pages/misc/deobf/entry-point.html',
|
||||
|
||||
// This route for the error page is also used to define text404 down below.
|
||||
'test-404': 'error.html',
|
||||
/* Main */
|
||||
documentation: 'docs.html',
|
||||
|
|
@ -57,223 +23,64 @@ let pages = {
|
|||
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/directory.html',
|
||||
'web-games': 'pages/nav/games5.html',
|
||||
emulators: 'pages/nav/emulators.html',
|
||||
'flash-games': 'pages/nav/flash.html',
|
||||
'retro-games': 'pages/nav/emulibrary.html',
|
||||
g: 'pages/nav/gtools.html',
|
||||
e: 'pages/nav/games5.html',
|
||||
c: 'pages/nav/emulators.html',
|
||||
f: 'pages/nav/flash.html',
|
||||
d: 'pages/nav/emulibrary.html',
|
||||
/* Proxies */
|
||||
ultraviolet: 'pages/proxnav/ultraviolet.html',
|
||||
scramjet: 'pages/proxnav/scramjet.html',
|
||||
uverror: 'pages/proxnav/ultraviolet-error.html',
|
||||
sjerror: 'pages/proxnav/scramjet-error.html',
|
||||
rammerhead: 'pages/proxnav/rammerhead.html',
|
||||
a: 'pages/proxnav/ultraviolet.html',
|
||||
b: 'pages/proxnav/rammerhead.html',
|
||||
/* Proxy Presets */
|
||||
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',
|
||||
'robots.txt': 'robots.txt',
|
||||
'sitemap.xml': 'sitemap.xml',
|
||||
'browserconfig.xml': 'browserconfig.xml',
|
||||
'vibe-os': 'archive/vibeOS/index.html',
|
||||
};
|
||||
|
||||
let externalPages = {
|
||||
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',
|
||||
bam: 'https://github.com/motortruck1221/bare-as-module3',
|
||||
bm: 'https://github.com/MercuryWorkshop/bare-mux',
|
||||
ep: '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',
|
||||
lj: 'https://github.com/ading2210/libcurl.js',
|
||||
'nord-theme': 'https://github.com/nordtheme',
|
||||
scramjet: 'https://github.com/MercuryWorkshop/scramjet',
|
||||
ultraviolet: 'https://github.com/titaniumnetwork-dev/Ultraviolet',
|
||||
wisp: 'https://github.com/MercuryWorkshop/wisp-protocol',
|
||||
config: 'https://github.com/titaniumnetwork-dev/Ultraviolet',
|
||||
wm: 'https://github.com/MercuryWorkshop/wisp-protocol',
|
||||
},
|
||||
codespaces: 'https://github.com/codespaces',
|
||||
'tor-project': 'https://tb-manual.torproject.org/installation',
|
||||
'titaniumnetwork-documentation': 'https://docs.titaniumnetwork.org',
|
||||
'patreon': 'https://www.patreon.com/holyunblockerlts',
|
||||
'titaniumnetwork-discord': 'https://discord.gg/CwWpdGkuWY',
|
||||
'truffled': 'https://truffled.lol',
|
||||
'rammerhead-discord': 'https://discord.gg/VNT4E7gN5Y',
|
||||
'config-docs': 'https://docs.titaniumnetwork.org',
|
||||
'config-chat': 'https://discord.gg/VNT4E7gN5Y',
|
||||
'nt': 'https://nordtheme.com',
|
||||
};
|
||||
|
||||
// Override the route names below when usingSEO is disabled in config.json.
|
||||
let altPaths = {
|
||||
games: 'books',
|
||||
'web-games': 'dictionary',
|
||||
emulators: 'catalogue',
|
||||
'flash-games': 'textbook',
|
||||
'retro-games': 'math',
|
||||
ultraviolet: 'networking',
|
||||
scramjet: 'working',
|
||||
uverror: 'network-error',
|
||||
sjerror: 'worker-error',
|
||||
rammerhead: 'physics',
|
||||
youtube: 'wiki',
|
||||
apps: 'software',
|
||||
flash: 'whiteboard',
|
||||
webretro: 'notebook',
|
||||
'vibe-os': 'pencil',
|
||||
github: {
|
||||
'bare-module': 'module',
|
||||
'bare-mux': 'bm',
|
||||
epoxy: 'ep',
|
||||
fastify: 'fs',
|
||||
'libcurl-js': 'ljs',
|
||||
scramjet: 'wr',
|
||||
ultraviolet: 'nt',
|
||||
wisp: 'router',
|
||||
},
|
||||
'titaniumnetwork-documentation': 'docs',
|
||||
codespaces: 'codesp',
|
||||
'tor-project': 'tr',
|
||||
'titaniumnetwork-discord': 'social',
|
||||
'truffled': 'educational',
|
||||
'rammerhead-discord': 'rdis',
|
||||
/* Raw File Names */
|
||||
files: {
|
||||
'scramjet.all.js': 'working.all.js',
|
||||
'scramjet.sw.js': 'working.sw.js',
|
||||
'scramjet.sw-blacklist.js': 'working.sw-blacklist.js',
|
||||
'scramjet.sync.js': 'working.sync.js',
|
||||
'scramjet.wasm.wasm': 'working.wasm.wasm',
|
||||
'uv.handler.js': 'networking.handler.js',
|
||||
'uv.client.js': 'networking.client.js',
|
||||
'uv.bundle.js': 'networking.bundle.js',
|
||||
'uv.config.js': 'networking.config.js',
|
||||
'uv.sw.js': 'networking.sw.js',
|
||||
'uv.webp': 'nt.webp',
|
||||
'scramjet.webp': 'wr.webp',
|
||||
'rammerhead.webp': 'physics.webp',
|
||||
'fastify.webp': 'fs.webp',
|
||||
'nordtheme.webp': 'nord.webp',
|
||||
'nodejs.webp': 'node.webp',
|
||||
'fontawesome.webp': 'fa.webp',
|
||||
'webretro.webp': 'notebook.webp',
|
||||
'ruffle.webp': 'rs.webp',
|
||||
},
|
||||
/* Prefixes */
|
||||
prefixes: {
|
||||
roms: 'ms',
|
||||
uv: 'network',
|
||||
scram: 'worker',
|
||||
chii: 'ani',
|
||||
epoxy: 'epoch',
|
||||
libcurl: 'unix',
|
||||
bareasmodule: 'utc',
|
||||
baremux: 'gmt',
|
||||
wisp: 'cron',
|
||||
},
|
||||
};
|
||||
|
||||
const useAltPaths = (altPaths, targetPaths, ancestor, tempKey = '') => {
|
||||
if ('object' === typeof altPaths) {
|
||||
for (const [key, value] of Object.entries(altPaths)) {
|
||||
if (key in targetPaths) {
|
||||
const isEndPoint = 'object' !== typeof value;
|
||||
delete altPaths[
|
||||
useAltPaths(
|
||||
value,
|
||||
isEndPoint ? targetPaths : targetPaths[key],
|
||||
altPaths,
|
||||
key
|
||||
)
|
||||
];
|
||||
if (isEndPoint) delete targetPaths[key];
|
||||
}
|
||||
}
|
||||
if ('object' === typeof ancestor) delete ancestor[tempKey];
|
||||
} else {
|
||||
targetPaths[altPaths] = targetPaths[tempKey];
|
||||
return tempKey;
|
||||
}
|
||||
return altPaths;
|
||||
};
|
||||
|
||||
const getAltPrefix = (prefix, serverPathname = '/') =>
|
||||
serverPathname +
|
||||
((!config.usingSEO && altPaths.prefixes[prefix]) || prefix) +
|
||||
'/',
|
||||
getPathEntries = (pathObject, prefix = '') => {
|
||||
if (prefix) prefix += '/';
|
||||
let inserts = [];
|
||||
for (let [key, value] of Object.entries(pathObject)) {
|
||||
if ('object' === typeof value)
|
||||
inserts = inserts.concat(getPathEntries(value, key));
|
||||
else
|
||||
inserts.push([
|
||||
prefix + key,
|
||||
prefix.replace(/^(?:prefixes|files)\//, '') +
|
||||
(config.usingSEO ? key : value),
|
||||
]);
|
||||
}
|
||||
return inserts;
|
||||
},
|
||||
normalizePaths = (pathObject) =>
|
||||
Object.fromEntries(getPathEntries(pathObject));
|
||||
|
||||
const flatAltPaths = Object.freeze(normalizePaths(altPaths));
|
||||
|
||||
const insert = JSON.parse(
|
||||
readFileSync(new URL('./data.json', import.meta.url))
|
||||
),
|
||||
text404 = readFileSync(
|
||||
new URL('../views/' + pages['test-404'], import.meta.url),
|
||||
'utf8'
|
||||
),
|
||||
uvError = readFileSync(
|
||||
new URL('../views/' + pages['uverror'], import.meta.url),
|
||||
'utf8'
|
||||
),
|
||||
sjError = readFileSync(
|
||||
new URL('../views/' + pages['sjerror'], import.meta.url),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
if (!config.usingSEO) {
|
||||
useAltPaths(altPaths, pages);
|
||||
useAltPaths(altPaths, externalPages);
|
||||
delete pages['robots.txt'];
|
||||
delete pages['sitemap.xml'];
|
||||
}
|
||||
|
||||
const cookingInserts = insert.content,
|
||||
vegetables = insert.keywords,
|
||||
charRandom = insert.chars,
|
||||
delimiter = insert.delimiter,
|
||||
textMasks = insert.textMasks,
|
||||
splashRandom = insert.splash,
|
||||
versionValue = insert.version,
|
||||
VersionValue = insert.version,
|
||||
cacheBustList = {
|
||||
'styles.css': 'styles-1755147161.css',
|
||||
'common.js': 'common-1735118314.js',
|
||||
'styles.css': 'styles-1644738239.css',
|
||||
'common.js': 'common-16451543478.js',
|
||||
};
|
||||
|
||||
export {
|
||||
config,
|
||||
serverUrl,
|
||||
export default {
|
||||
pages,
|
||||
externalPages,
|
||||
flatAltPaths,
|
||||
getAltPrefix,
|
||||
text404,
|
||||
uvError,
|
||||
sjError,
|
||||
cookingInserts,
|
||||
vegetables,
|
||||
charRandom,
|
||||
delimiter,
|
||||
textMasks,
|
||||
splashRandom,
|
||||
versionValue,
|
||||
VersionValue,
|
||||
cacheBustList,
|
||||
};
|
||||
|
|
|
|||
415
src/server.mjs
|
|
@ -1,41 +1,49 @@
|
|||
import Fastify from 'fastify';
|
||||
import { createServer } from 'node:http';
|
||||
import { server as wisp, logging } from "@mercuryworkshop/wisp-js/server";
|
||||
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 fastifyHelmet from '@fastify/helmet';
|
||||
import fastifyStatic from '@fastify/static';
|
||||
import {
|
||||
config,
|
||||
serverUrl,
|
||||
pages,
|
||||
externalPages,
|
||||
getAltPrefix,
|
||||
} from './routes.mjs';
|
||||
import { tryReadFile, preloaded404 } from './templates.mjs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import pageRoutes from './routes.mjs';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { paintSource, preloaded404, tryReadFile } from './randomization.mjs';
|
||||
import loadTemplates from './templates.mjs';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
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)))
|
||||
),
|
||||
ecosystemConfig = Object.freeze(
|
||||
ecosystem.apps.find((app) => app.name === 'HolyUBLTS') || ecosystem.apps[0]
|
||||
),
|
||||
{ pages, externalPages } = pageRoutes,
|
||||
__dirname = path.resolve();
|
||||
|
||||
/* 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) => {
|
||||
try {
|
||||
base = new URL(config.host);
|
||||
} catch (e) {
|
||||
base = new URL('http://a');
|
||||
base.host = config.host;
|
||||
}
|
||||
base.port =
|
||||
ecosystemConfig[config.production ? 'env_production' : 'env'].PORT;
|
||||
return Object.freeze(base);
|
||||
})();
|
||||
console.log(serverUrl);
|
||||
|
||||
// Wisp Configuration: Refer to the documentation at https://www.npmjs.com/package/@mercuryworkshop/wisp-js
|
||||
|
||||
logging.set_level(logging.NONE);
|
||||
wisp.options.allow_udp_streams = false;
|
||||
wisp.options.allow_loopback_ips = true;
|
||||
|
||||
// For security reasons only allow these ports. Any additional regional proxies or default sandboxed Tor ports should be added here.
|
||||
wisp.options.port_whitelist = [
|
||||
80,
|
||||
443,
|
||||
9050,
|
||||
7000,
|
||||
7001
|
||||
];
|
||||
|
||||
// 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));
|
||||
|
|
@ -57,11 +65,9 @@ const rammerheadScopes = [
|
|||
'/syncLocalStorage',
|
||||
'/api/shuffleDict',
|
||||
'/mainport',
|
||||
].map((pathname) => pathname.replace('/', serverUrl.pathname));
|
||||
];
|
||||
|
||||
const rammerheadSession = new RegExp(
|
||||
`^${serverUrl.pathname.replaceAll('.', '\\.')}[a-z0-9]{32}`
|
||||
),
|
||||
const rammerheadSession = /^\/[a-z0-9]{32}/,
|
||||
shouldRouteRh = (req) => {
|
||||
try {
|
||||
const url = new URL(req.url, serverUrl);
|
||||
|
|
@ -74,15 +80,13 @@ const rammerheadSession = new RegExp(
|
|||
}
|
||||
},
|
||||
routeRhRequest = (req, res) => {
|
||||
req.url = req.url.slice(serverUrl.pathname.length - 1);
|
||||
rh.emit('request', req, res);
|
||||
},
|
||||
routeRhUpgrade = (req, socket, head) => {
|
||||
req.url = req.url.slice(serverUrl.pathname.length - 1);
|
||||
rh.emit('upgrade', req, socket, head);
|
||||
};
|
||||
|
||||
// Create a server factory for Rammerhead and Wisp
|
||||
// Create a server factory for RH, and wisp (and bare if you please).
|
||||
const serverFactory = (handler) => {
|
||||
return createServer()
|
||||
.on('request', (req, res) => {
|
||||
|
|
@ -91,17 +95,14 @@ const serverFactory = (handler) => {
|
|||
})
|
||||
.on('upgrade', (req, socket, head) => {
|
||||
if (shouldRouteRh(req)) routeRhUpgrade(req, socket, head);
|
||||
else if (req.url.endsWith(getAltPrefix('wisp', serverUrl.pathname)))
|
||||
wisp.routeRequest(req, socket, head);
|
||||
else if (req.url.endsWith('/wisp/')) wisp.routeRequest(req, socket, head);
|
||||
});
|
||||
};
|
||||
|
||||
// Set logger to true for logs.
|
||||
const app = Fastify({
|
||||
routerOptions: {
|
||||
ignoreDuplicateSlashes: true,
|
||||
ignoreTrailingSlash: true,
|
||||
},
|
||||
ignoreDuplicateSlashes: true,
|
||||
ignoreTrailingSlash: true,
|
||||
logger: false,
|
||||
serverFactory: serverFactory,
|
||||
});
|
||||
|
|
@ -114,154 +115,132 @@ app.register(fastifyHelmet, {
|
|||
|
||||
// Assign server file paths to different paths, for serving content on the website.
|
||||
app.register(fastifyStatic, {
|
||||
root: fileURLToPath(new URL('../views/dist/pages', import.meta.url)),
|
||||
prefix: serverUrl.pathname,
|
||||
root: fileURLToPath(new URL('../views/pages', import.meta.url)),
|
||||
decorateReply: false,
|
||||
});
|
||||
|
||||
// All entries in the dist folder are created with source rewrites.
|
||||
// Minified scripts are also served here, if minification is enabled.
|
||||
[
|
||||
'assets',
|
||||
'archive',
|
||||
'uv',
|
||||
'scram',
|
||||
'epoxy',
|
||||
'libcurl',
|
||||
'baremux',
|
||||
'chii',
|
||||
].forEach((prefix) => {
|
||||
app.register(fastifyStatic, {
|
||||
root: fileURLToPath(new URL('../views/dist/' + prefix, import.meta.url)),
|
||||
prefix: getAltPrefix(prefix, serverUrl.pathname),
|
||||
decorateReply: false,
|
||||
});
|
||||
app.register(fastifyStatic, {
|
||||
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: '/archive/',
|
||||
decorateReply: false,
|
||||
});
|
||||
|
||||
app.register(fastifyStatic, {
|
||||
root: fileURLToPath(new URL('../views/archive/gfiles/rarch', import.meta.url)),
|
||||
prefix: '/serving/',
|
||||
decorateReply: false,
|
||||
});
|
||||
|
||||
app.register(fastifyStatic, {
|
||||
root: fileURLToPath(new URL('../views/archive/gfiles/rarch/cores', import.meta.url)),
|
||||
prefix: '/cores/',
|
||||
decorateReply: false,
|
||||
});
|
||||
|
||||
app.register(fastifyStatic, {
|
||||
root: fileURLToPath(new URL('../views/archive/gfiles/rarch/info', import.meta.url)),
|
||||
prefix: '/info/',
|
||||
decorateReply: false,
|
||||
});
|
||||
|
||||
app.register(fastifyStatic, {
|
||||
root: fileURLToPath(new URL('../views/archive/gfiles/rarch/cores', import.meta.url)),
|
||||
prefix: '/uauth/',
|
||||
decorateReply: false,
|
||||
});
|
||||
|
||||
// NEVER commit roms due to piracy concerns
|
||||
app.register(fastifyStatic, {
|
||||
root: fileURLToPath(new URL('../views/archive/gfiles/rarch/roms', import.meta.url)),
|
||||
prefix: '/roms/',
|
||||
decorateReply: false,
|
||||
});
|
||||
|
||||
app.register(fastifyStatic, {
|
||||
root: fileURLToPath(
|
||||
new URL('../views/dist/archive/gfiles/rarch', import.meta.url)
|
||||
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: getAltPrefix('serving', serverUrl.pathname),
|
||||
prefix: '/assets/js/',
|
||||
decorateReply: false,
|
||||
});
|
||||
|
||||
// You should NEVER commit roms, due to piracy concerns.
|
||||
['cores', 'info', 'roms'].forEach((prefix) => {
|
||||
app.register(fastifyStatic, {
|
||||
root: fileURLToPath(
|
||||
new URL('../views/dist/archive/gfiles/rarch/' + prefix, import.meta.url)
|
||||
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,
|
||||
});
|
||||
|
||||
// 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/network' : '../views/network',
|
||||
import.meta.url
|
||||
)
|
||||
),
|
||||
prefix: getAltPrefix(prefix, serverUrl.pathname),
|
||||
decorateReply: false,
|
||||
});
|
||||
uvPath,
|
||||
],
|
||||
prefix: '/network/',
|
||||
decorateReply: true,
|
||||
});
|
||||
|
||||
// Register proxy paths to the website.
|
||||
app.register(fastifyStatic, {
|
||||
root: fileURLToPath(
|
||||
new URL('../views/dist/archive/gfiles/rarch/cores', import.meta.url)
|
||||
),
|
||||
prefix: getAltPrefix('uauth', serverUrl.pathname),
|
||||
root: epoxyPath,
|
||||
prefix: '/epoxy/',
|
||||
decorateReply: false,
|
||||
});
|
||||
|
||||
/* If you are trying to add pages or assets in the root folder and
|
||||
* NOT entire folders, check ./src/routes.mjs and add it manually.
|
||||
*
|
||||
* All website files are stored in the /views directory.
|
||||
app.register(fastifyStatic, {
|
||||
root: libcurlPath,
|
||||
prefix: '/libcurl/',
|
||||
decorateReply: false,
|
||||
});
|
||||
|
||||
app.register(fastifyStatic, {
|
||||
root: bareModulePath,
|
||||
prefix: '/bareasmodule/',
|
||||
decorateReply: false,
|
||||
});
|
||||
|
||||
app.register(fastifyStatic, {
|
||||
root: baremuxPath,
|
||||
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/dist/pages/surf.html
|
||||
* Paths like /browsing are converted into paths like /views/pages/surf.html
|
||||
* back here. Which path converts to what is defined in routes.mjs.
|
||||
*/
|
||||
|
||||
const supportedTypes = {
|
||||
default: config.disguiseFiles ? 'image/vnd.microsoft.icon' : 'text/html',
|
||||
html: 'text/html',
|
||||
txt: 'text/plain',
|
||||
xml: 'application/xml',
|
||||
ico: 'image/vnd.microsoft.icon',
|
||||
},
|
||||
disguise = 'ico';
|
||||
|
||||
if (config.disguiseFiles) {
|
||||
const getActualPath = (path) =>
|
||||
path.slice(0, path.length - 1 - disguise.length),
|
||||
shouldNotHandle = new RegExp(`\\.(?!html$|${disguise}$)[\\w-]+$`, 'i'),
|
||||
loaderFile = tryReadFile(
|
||||
'../views/dist/pages/misc/deobf/loader.html',
|
||||
import.meta.url,
|
||||
false
|
||||
);
|
||||
let exemptDirs = [
|
||||
'assets',
|
||||
'uv',
|
||||
'scram',
|
||||
'epoxy',
|
||||
'libcurl',
|
||||
'baremux',
|
||||
'wisp',
|
||||
'chii',
|
||||
].map((dir) => getAltPrefix(dir, serverUrl.pathname).slice(1, -1)),
|
||||
exemptPages = ['login', 'test-shutdown', 'favicon.ico'];
|
||||
for (const [key, value] of Object.entries(externalPages))
|
||||
if ('string' === typeof value) exemptPages.push(key);
|
||||
else exemptDirs.push(key);
|
||||
for (const path of rammerheadScopes)
|
||||
if (!shouldNotHandle.test(path)) exemptDirs.push(path.slice(1));
|
||||
exemptPages = exemptPages.concat(exemptDirs);
|
||||
if (pages.default === 'login') exemptPages.push('');
|
||||
|
||||
app.addHook('preHandler', (req, reply, done) => {
|
||||
if (req.params.modified) return done();
|
||||
const reqPath = new URL(req.url, serverUrl).pathname.slice(
|
||||
serverUrl.pathname.length
|
||||
);
|
||||
if (
|
||||
shouldNotHandle.test(reqPath) ||
|
||||
exemptDirs.some((dir) => reqPath.indexOf(dir + '/') === 0) ||
|
||||
exemptPages.includes(reqPath) ||
|
||||
rammerheadSession.test(serverUrl.pathname + reqPath)
|
||||
)
|
||||
return done();
|
||||
|
||||
if (!reqPath.endsWith('.' + disguise)) {
|
||||
reply.type(supportedTypes.html).send(loaderFile);
|
||||
reply.hijack();
|
||||
return done();
|
||||
} else if (!(reqPath in pages) && !reqPath.endsWith('favicon.ico')) {
|
||||
req.params.modified = true;
|
||||
req.raw.url = getActualPath(req.raw.url);
|
||||
if (req.params.path) req.params.path = getActualPath(req.params.path);
|
||||
if (req.params['*']) req.params['*'] = getActualPath(req.params['*']);
|
||||
reply.type(supportedTypes[disguise]);
|
||||
reply.header('Access-Control-Allow-Origin', 'null');
|
||||
}
|
||||
return done();
|
||||
});
|
||||
}
|
||||
|
||||
app.get(serverUrl.pathname + ':path', (req, reply) => {
|
||||
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(
|
||||
'cookie:',
|
||||
req.raw.rawHeaders[req.raw.rawHeaders.indexOf('Cookie') + 1]
|
||||
);
|
||||
*/
|
||||
console.log(req.raw.rawHeaders[req.raw.rawHeaders.indexOf('Cookie') + 1]);
|
||||
|
||||
const reqPath = req.params.path;
|
||||
|
||||
// Ignore browsers' automatic requests to favicon.ico, since it does not exist.
|
||||
// This approach is needed for certain pages to not have an icon.
|
||||
if (reqPath === 'favicon.ico') {
|
||||
reply.send();
|
||||
return reply.hijack();
|
||||
}
|
||||
|
||||
if (reqPath in externalPages) {
|
||||
if (req.params.modified)
|
||||
return reply.code(404).type(supportedTypes.html).send(preloaded404);
|
||||
let externalRoute = externalPages[reqPath];
|
||||
if (typeof externalRoute !== 'string')
|
||||
externalRoute = externalRoute.default;
|
||||
|
|
@ -279,46 +258,98 @@ app.get(serverUrl.pathname + ':path', (req, reply) => {
|
|||
|
||||
// Return the error page if the query is not found in routes.mjs.
|
||||
if (reqPath && !(reqPath in pages))
|
||||
return reply.code(404).type(supportedTypes.default).send(preloaded404);
|
||||
return reply.code(404).type('text/html').send(preloaded404);
|
||||
|
||||
// Serve the default page if the path is the default path.
|
||||
const fileName = reqPath ? pages[reqPath] : pages[pages.default],
|
||||
type =
|
||||
supportedTypes[fileName.slice(fileName.lastIndexOf('.') + 1)] ||
|
||||
supportedTypes.default;
|
||||
|
||||
if (req.params.modified) reply.type(supportedTypes[disguise]);
|
||||
else reply.type(type);
|
||||
reply.send(tryReadFile('../views/dist/' + fileName, import.meta.url));
|
||||
reply.type('text/html').send(
|
||||
paintSource(
|
||||
loadTemplates(
|
||||
tryReadFile(
|
||||
'../views/' +
|
||||
// Set the index the as the default page.
|
||||
(reqPath ? pages[reqPath] : pages.index),
|
||||
import.meta.url
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
app.get(serverUrl.pathname + '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(supportedTypes.default).send(preloaded404);
|
||||
else reply.code(404).type('text/html').send(preloaded404);
|
||||
});
|
||||
|
||||
if (serverUrl.pathname === '/')
|
||||
// Set an error page for invalid paths outside the query string system.
|
||||
// If the server URL has a prefix, then avoid doing this for stealth reasons.
|
||||
app.setNotFoundHandler((req, reply) => {
|
||||
reply.code(404).type(supportedTypes.default).send(preloaded404);
|
||||
});
|
||||
else {
|
||||
// Apply the following patch(es) if the server URL has a prefix.
|
||||
const encodingTable = (() => {
|
||||
let yummyOneBytes = '';
|
||||
for (let i = 0; i < 128; i++)
|
||||
if (
|
||||
JSON.stringify(JSON.stringify(String.fromCodePoint(i)).slice(1, -1))
|
||||
.length < 6
|
||||
)
|
||||
yummyOneBytes += String.fromCodePoint(i);
|
||||
return yummyOneBytes;
|
||||
})(),
|
||||
randomValue = crypto
|
||||
.randomUUID()
|
||||
.split('-')
|
||||
.map((gibberish) => {
|
||||
let randomNumber = parseInt(gibberish, 16),
|
||||
output = '';
|
||||
while (randomNumber >= encodingTable.length) {
|
||||
output +=
|
||||
encodingTable[Math.floor(randomNumber) % encodingTable.length];
|
||||
randomNumber = randomNumber / encodingTable.length;
|
||||
}
|
||||
return output + Math.floor(randomNumber);
|
||||
})
|
||||
.join(''),
|
||||
randomizeGlobal = config.randomizeIdentifiers
|
||||
? (file) =>
|
||||
tryReadFile(file, import.meta.url).replace(
|
||||
/(["'`])\{\{__uv\$config\}\}\1/g,
|
||||
JSON.stringify(randomValue)
|
||||
)
|
||||
: (file) =>
|
||||
tryReadFile(file, import.meta.url).replace(
|
||||
/(["'`])\{\{__uv\$config\}\}\1/g,
|
||||
JSON.stringify('__uv$config')
|
||||
);
|
||||
|
||||
// Patch to fix serving index.html.
|
||||
app.get(serverUrl.pathname, (req, reply) => {
|
||||
reply
|
||||
.type(supportedTypes.default)
|
||||
.send(tryReadFile('../views/dist/' + pages.index, import.meta.url));
|
||||
});
|
||||
}
|
||||
app.get('/assets/js/common-16451543478.js', (req, reply) => {
|
||||
reply
|
||||
.type('text/javascript')
|
||||
.send(
|
||||
randomizeGlobal(
|
||||
'../views' + (config.minifyScripts ? '/dist' : '') + req.url
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
app.get('/network/:file.js', (req, reply) => {
|
||||
const destination = existsSync(
|
||||
fileURLToPath(new URL('../views' + req.url, import.meta.url))
|
||||
)
|
||||
? '../views' + (config.minifyScripts ? '/dist' : '') + req.url
|
||||
: pathToFileURL(uvPath) + `/${req.params.file}.js`;
|
||||
reply
|
||||
.type('text/javascript')
|
||||
.send(
|
||||
randomizeGlobal(destination).replace(
|
||||
/(["'`])\{\{ultraviolet-error\}\}\1/g,
|
||||
JSON.stringify(
|
||||
tryReadFile(
|
||||
'../views/pages/proxnav/ultraviolet-error.html',
|
||||
import.meta.url
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
app.setNotFoundHandler((req, reply) => {
|
||||
reply.code(404).type('text/html').send(preloaded404);
|
||||
});
|
||||
|
||||
app.listen({ port: serverUrl.port, host: serverUrl.hostname });
|
||||
console.log(`Holy Unblocker is listening on port ${serverUrl.port}.`);
|
||||
console.log(`When hosting with a reverse proxy please ensure you are using NGINX only.\nCaddy and Apache are not supported and have security risks due to wisp-js and loopbacks.\nPorts are whitelisted and security is maintained with NGINX only.`);
|
||||
if (config.disguiseFiles)
|
||||
console.log(
|
||||
'disguiseFiles is enabled. Visit src/routes.mjs to see the entry point, listed within the pages variable.'
|
||||
);
|
||||
console.log(`Holy Unblocker is listening on port ${serverUrl.port}.`);
|
||||
|
|
@ -1,284 +0,0 @@
|
|||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import {
|
||||
config,
|
||||
serverUrl,
|
||||
flatAltPaths,
|
||||
cookingInserts,
|
||||
vegetables,
|
||||
charRandom,
|
||||
delimiter,
|
||||
textMasks,
|
||||
splashRandom,
|
||||
cacheBustList,
|
||||
versionValue,
|
||||
uvError,
|
||||
sjError,
|
||||
} from './routes.mjs';
|
||||
export { paintSource as default };
|
||||
|
||||
/* Below are lots of function definitions used to obfuscate the website.
|
||||
* This makes the website harder to properly categorize, as its source code
|
||||
* changes with each time it is compiled using npm run build.
|
||||
*
|
||||
* For customizing source code transformation and more, see the config.json file.
|
||||
* For automatically recompiling in production mode, see ecosystem.config.js.
|
||||
*/
|
||||
const regExpEscape = /[-[\]{}()*+?.,\\^$#\s]/g,
|
||||
basicStrEscape = /["'`$\\]/g,
|
||||
charset = /­|​|­|<wbr>/gi,
|
||||
subtermsByCaps = /[A-Z]?[^A-Z]+|[A-Z]/g,
|
||||
subtermsByVowels = /(?<=[AEIOUYaeiouy])(?!$)/g,
|
||||
termsBySpaces = /\S+/g,
|
||||
containsMask = /&#\d+;|&#x[A-z\d]+;|&[A-z]+;/,
|
||||
getEndPoint = /((?<![^\/])github\/)?[^\/]+$/,
|
||||
getPaths = /[^\/]+(?=\/)/g,
|
||||
getAbsoluteRoot = /^~?\/+|^~$|^(?!\.\/)/,
|
||||
getRoutePath = /(?<={{route}}{{\s*)[^}\s]+(?=\s*}})/,
|
||||
getAttrPath = /(?<=(?:src|href)=(["']?))[\w\.~:\/\?#[\]@!$&()*+,;%=-]+(?=\1)/,
|
||||
getAttrValues = /=(['"])(?:(?!\1)[^])+\1/g,
|
||||
getNodesByLine = /(?<=^\s*)\S.*?(?=\s*$)/gm,
|
||||
routeConditions = {
|
||||
inline: config.disguiseFiles && config.minifyScripts,
|
||||
},
|
||||
applyInsert = (str, insertFunction, numArgs = 0) => {
|
||||
const mode = 'function' === typeof insertFunction,
|
||||
keyword = mode ? insertFunction.name : insertFunction,
|
||||
replaceParams1 = new RegExp(
|
||||
`[^\\S\\n\\r]*{{${keyword}}}\\s*` +
|
||||
'\\s*{{\\s*\\n\\r?((?:(?!}})[^])*\\n\\r?)\\s*}}\\s*?\\n?\\r?'.repeat(
|
||||
numArgs
|
||||
),
|
||||
'g'
|
||||
),
|
||||
replaceParams2 = new RegExp(
|
||||
`{{${keyword}}}` + '{{((?:(?!}})[^])*?)}}'.repeat(numArgs),
|
||||
'g'
|
||||
),
|
||||
replaceFunc = mode
|
||||
? (text, ...captures) => insertFunction(...captures.splice(0, numArgs))
|
||||
: (text) => flatAltPaths[keyword] || text;
|
||||
return numArgs > 0
|
||||
? str
|
||||
.replace(replaceParams1, replaceFunc)
|
||||
.replace(replaceParams2, replaceFunc)
|
||||
: str.replace(replaceParams2, replaceFunc);
|
||||
},
|
||||
applyMassInsert = (str, flatPathObject, shouldIgnore = false) => {
|
||||
const replaceParams = new RegExp(
|
||||
`{{(${Object.keys(flatPathObject).join('|').replace(regExpEscape, '\\$&')})}}`,
|
||||
'g'
|
||||
),
|
||||
replaceFunc = shouldIgnore
|
||||
? (text, capture) => capture
|
||||
: (text, capture) => flatPathObject[capture] || text;
|
||||
return str.replace(replaceParams, replaceFunc);
|
||||
},
|
||||
ifSEO = (text) => (config.usingSEO ? text : ''),
|
||||
ifDisguise = (text) => (config.disguiseFiles ? text : ''),
|
||||
randomListItem = (lis) => () => lis[(Math.random() * lis.length) | 0],
|
||||
getRandomChar = randomListItem(charRandom),
|
||||
/* Text masks, found in src/data.json, are meant to be variations of the
|
||||
* same term. Using a different term as a mask will break the spelling.
|
||||
* HTML entities may also break if their names are used as terms.
|
||||
*/
|
||||
parsedTextMasks = Object.freeze(
|
||||
Object.entries(textMasks).map((entry) => [
|
||||
entry[0],
|
||||
randomListItem(entry[1]),
|
||||
entry[0].match(subtermsByCaps),
|
||||
])
|
||||
),
|
||||
matchTextMasks = new RegExp(
|
||||
Object.keys(textMasks)
|
||||
.sort((term1, term2) => term2.length - term1.length)
|
||||
.join('|')
|
||||
.replace(regExpEscape, '\\$&'),
|
||||
'gi'
|
||||
),
|
||||
maskTerm = (term) => {
|
||||
if (config.usingSEO) return term;
|
||||
const altList = parsedTextMasks.find(
|
||||
(entry) => entry[0].toLowerCase() === term.toLowerCase()
|
||||
);
|
||||
let capitals = altList[2].map((word) => {
|
||||
const letter = term[0];
|
||||
term = term.slice(word.length);
|
||||
return letter;
|
||||
});
|
||||
return altList[1]()
|
||||
.replace(subtermsByCaps, (word) => capitals.shift() + word.slice(1))
|
||||
.replaceAll(delimiter, getRandomChar);
|
||||
},
|
||||
mask = (text) =>
|
||||
config.usingSEO
|
||||
? text
|
||||
: text
|
||||
.replace(matchTextMasks, maskTerm)
|
||||
.replace(termsBySpaces, (term) =>
|
||||
containsMask.test(term)
|
||||
? term
|
||||
: term.replace(subtermsByVowels, getRandomChar)
|
||||
),
|
||||
route = (text, conditionalRoute = false) =>
|
||||
conditionalRoute && routeConditions[conditionalRoute]
|
||||
? text.replace(
|
||||
getEndPoint,
|
||||
(name) => cacheBustList[name] || flatAltPaths['files/' + name] || name
|
||||
)
|
||||
: text
|
||||
.replace(
|
||||
getEndPoint,
|
||||
// cacheBustList is purely for dealing with cached file loading issues.
|
||||
(name, ancestor) =>
|
||||
ancestor
|
||||
? flatAltPaths[name] || name
|
||||
: flatAltPaths['files/' + name] ||
|
||||
cacheBustList[name] ||
|
||||
flatAltPaths[name] ||
|
||||
name
|
||||
)
|
||||
.replace(
|
||||
getPaths,
|
||||
(path) =>
|
||||
flatAltPaths['prefixes/' + path] || flatAltPaths[path] || path
|
||||
)
|
||||
.replace(getAbsoluteRoot, serverUrl.pathname),
|
||||
inlineElement = (htmlStr) => {
|
||||
let relPath = htmlStr.match(getRoutePath) || htmlStr.match(getAttrPath),
|
||||
wrapper = [],
|
||||
fileType;
|
||||
if (relPath)
|
||||
try {
|
||||
relPath = new URL(
|
||||
'../views/dist' +
|
||||
new URL(relPath[0], 'https://www.example.com').pathname,
|
||||
import.meta.url
|
||||
);
|
||||
fileType = relPath.pathname
|
||||
.slice(relPath.pathname.lastIndexOf('.') + 1)
|
||||
.toLowerCase();
|
||||
switch (fileType) {
|
||||
case 'css': {
|
||||
wrapper = ['<style>', '</style>'];
|
||||
break;
|
||||
}
|
||||
case 'js': {
|
||||
const parsedNode = htmlStr
|
||||
.replace(getAttrValues, ' ')
|
||||
.toLowerCase();
|
||||
if (
|
||||
parsedNode.indexOf(' defer ') !== -1 ||
|
||||
parsedNode.indexOf(' defer>') !== -1
|
||||
)
|
||||
wrapper = ['<script defer>', '</script>'];
|
||||
else wrapper = ['<script>', '</script>'];
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
relPath = '';
|
||||
console.log(e);
|
||||
}
|
||||
return relPath && wrapper.length && existsSync(relPath)
|
||||
? wrapper[0] +
|
||||
readFileSync(relPath, 'utf8').trim() +
|
||||
(wrapper[1] || wrapper[0])
|
||||
: htmlStr;
|
||||
},
|
||||
inline = (htmlStr) =>
|
||||
routeConditions.inline
|
||||
? htmlStr.replace(getNodesByLine, inlineElement)
|
||||
: htmlStr,
|
||||
insertCharset = (str) => str.replace(charset, getRandomChar),
|
||||
getSplash = () => randomListItem(splashRandom)(),
|
||||
getCookingText = () =>
|
||||
`<span style="display:none" data-fact="${randomListItem(vegetables)()}">${randomListItem(cookingInserts)()}</span>`,
|
||||
insertCooking = (str) =>
|
||||
str.replaceAll(
|
||||
'<!-- IMPORTANT-HUCOOKINGINSERT-DONOTDELETE -->',
|
||||
getCookingText
|
||||
),
|
||||
encodingTable = (() => {
|
||||
let yummyOneBytes = '';
|
||||
for (let i = 0; i < 128; i++)
|
||||
if (
|
||||
JSON.stringify(JSON.stringify(String.fromCodePoint(i)).slice(1, -1))
|
||||
.length < 6
|
||||
)
|
||||
yummyOneBytes += String.fromCodePoint(i);
|
||||
return yummyOneBytes;
|
||||
})(),
|
||||
createRandomID = () =>
|
||||
crypto
|
||||
.randomUUID()
|
||||
.split('-')
|
||||
.map((gibberish) => {
|
||||
let randomNumber = parseInt(gibberish, 16),
|
||||
output = '';
|
||||
while (randomNumber >= encodingTable.length) {
|
||||
output +=
|
||||
encodingTable[Math.floor(randomNumber) % encodingTable.length];
|
||||
randomNumber = randomNumber / encodingTable.length;
|
||||
}
|
||||
return output + Math.floor(randomNumber);
|
||||
})
|
||||
.join('')
|
||||
.replaceAll('{', '')
|
||||
.replaceAll('}', ''),
|
||||
// To be used for {{insertions}} that are also encased in string literals.
|
||||
escapeStr = (str) =>
|
||||
str
|
||||
.replace(basicStrEscape, '\\$&')
|
||||
.replaceAll('\r', '\\r')
|
||||
.replaceAll('\n', '\\n'),
|
||||
orderedTransforms = [
|
||||
[getSplash, 0],
|
||||
[route, 2],
|
||||
[route, 1],
|
||||
[ifSEO, 1],
|
||||
[ifDisguise, 1],
|
||||
[mask, 1],
|
||||
[inline, 1],
|
||||
],
|
||||
namedEntries = Object.freeze({
|
||||
__uv$config: escapeStr(
|
||||
config.randomizeIdentifiers ? createRandomID() : '__uv$config'
|
||||
),
|
||||
version: versionValue,
|
||||
cacheVal: crypto.getRandomValues(new Uint32Array(1))[0],
|
||||
defaultSearch: '{{DuckDuckGo}}',
|
||||
}),
|
||||
// List of manual censors for unavoidable cases.
|
||||
manualCensors = Object.freeze({
|
||||
Google: 'Google',
|
||||
Bing: 'Bing',
|
||||
Brave: 'Brave',
|
||||
DuckDuckGo: 'DuckDuckGo',
|
||||
Startpage: 'Startpage',
|
||||
'wisp-transport': 'wst',
|
||||
libcurl: 'unix',
|
||||
epoxy: 'epoch',
|
||||
'hu-lts': 'net-time',
|
||||
}),
|
||||
// Apply most obfuscation changes to an entire file's text content.
|
||||
prePaint = (str) => {
|
||||
let paintedSource = insertCharset(insertCooking(str));
|
||||
paintedSource = applyMassInsert(
|
||||
applyMassInsert(paintedSource, namedEntries),
|
||||
manualCensors,
|
||||
config.usingSEO
|
||||
);
|
||||
for (let i = 0, total = orderedTransforms.length; i < total; i++)
|
||||
paintedSource = applyInsert(paintedSource, ...orderedTransforms[i]);
|
||||
return paintedSource;
|
||||
},
|
||||
// Functionally similar to templates.mjs, but requires more situational formatting.
|
||||
specialTemplates = Object.freeze({
|
||||
'ultraviolet-error': escapeStr(prePaint(uvError)),
|
||||
'scramjet-error': escapeStr(prePaint(sjError)),
|
||||
}),
|
||||
// Apply final changes to a given file's text content.
|
||||
paintSource = (str) => applyMassInsert(prePaint(str), specialTemplates);
|
||||
|
|
@ -1,62 +1,24 @@
|
|||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { config, text404 } from './routes.mjs';
|
||||
import paintSource from './source-rewrites.mjs';
|
||||
export { loadTemplates, tryReadFile, preloaded404 };
|
||||
import { tryReadFile } from './randomization.mjs';
|
||||
export { loadTemplates as default };
|
||||
|
||||
const __dirname = '../views/pages/misc/deobf',
|
||||
getLineHeads = /^/gm,
|
||||
regExpEscape2 = /[-[\]{}()*+?.,\\^$|#\s]/g,
|
||||
isImage = /\.(?:ico|png|jpg|jpeg)$/,
|
||||
templateNames = [
|
||||
'anti-exfil',
|
||||
'head-content',
|
||||
'header',
|
||||
'footer',
|
||||
'docs',
|
||||
'faq',
|
||||
'tos',
|
||||
'settings',
|
||||
'proxnav-settings',
|
||||
],
|
||||
readTemplate = (identifier) =>
|
||||
readFileSync(
|
||||
new URL(__dirname + `/${identifier}.html`, import.meta.url),
|
||||
'utf8'
|
||||
),
|
||||
locateTemplate = (key) =>
|
||||
new RegExp(
|
||||
`([^\\S\\n\\r]*)<!--(${key.replace(regExpEscape2, '\\$&')})-->`,
|
||||
'gm'
|
||||
),
|
||||
preserveIndentation = (template) => (line, leadingSpaces) =>
|
||||
template.replace(getLineHeads, leadingSpaces),
|
||||
templates = templateNames.map((name) => [
|
||||
locateTemplate(name.toUpperCase()),
|
||||
preserveIndentation(readTemplate(name).replace(/\s+$/, '')),
|
||||
]),
|
||||
const __dirname = '../views/pages/misc/deobf';
|
||||
|
||||
const header = tryReadFile(__dirname + '/header.html', import.meta.url),
|
||||
footer = tryReadFile(__dirname + '/footer.html', import.meta.url),
|
||||
documentation = tryReadFile(__dirname + '/docs.html', import.meta.url),
|
||||
faq = tryReadFile(__dirname + '/faq.html', import.meta.url),
|
||||
terms = tryReadFile(__dirname + '/tos.html', import.meta.url),
|
||||
settings = tryReadFile(__dirname + '/settings.html', import.meta.url),
|
||||
loadTemplates = (str) =>
|
||||
templates.reduce(
|
||||
(updatedStr, [key, template]) => updatedStr.replace(key, template),
|
||||
str
|
||||
),
|
||||
preformatted404 = paintSource(loadTemplates(text404)),
|
||||
preloaded404 = config.disguiseFiles
|
||||
? Buffer.from(
|
||||
await new Response(
|
||||
new Blob([preformatted404])
|
||||
.stream()
|
||||
.pipeThrough(new CompressionStream('gzip'))
|
||||
).arrayBuffer()
|
||||
)
|
||||
: preformatted404,
|
||||
// Grab the text content of a file. Use the root directory if no base is supplied.
|
||||
tryReadFile = (
|
||||
file,
|
||||
baseUrl = new URL('../', import.meta.url),
|
||||
isBuffer = config.disguiseFiles
|
||||
) => {
|
||||
file = new URL(file, baseUrl);
|
||||
return existsSync(file)
|
||||
? readFileSync(file, isImage.test(file) || isBuffer ? undefined : 'utf8')
|
||||
: preloaded404;
|
||||
};
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
# Games Information for Self-Hosting
|
||||
|
||||
### All respective games for this project have been moved to https://github.com/QuiteAFancyEmerald/HU-Archive
|
||||
|
||||
- Simply download the latest release and unzip in a folder named "archive"; full path will be `./views/archive/[RESPECTIVE FILES HERE]`
|
||||
|
||||
### For inquires or takedowns simply contact via d9tcv6vgx@mozmail.com
|
||||
1
views/archive
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit ba041c0299f34a83959dc3dc34427d34b94cbe70
|
||||
BIN
views/assets/fonts/NeueMontreal-Light.ttf
Normal file
BIN
views/assets/fonts/NeueMontreal-Light.woff
Normal file
BIN
views/assets/fonts/NeueMontreal-Light.woff2
Normal file
BIN
views/assets/fonts/NeueMontreal-Medium.ttf
Normal file
BIN
views/assets/fonts/NeueMontreal-Medium.woff
Normal file
BIN
views/assets/fonts/NeueMontreal-Medium.woff2
Normal file
BIN
views/assets/fonts/NeueMontreal-Regular.ttf
Normal file
BIN
views/assets/fonts/NeueMontreal-Regular.woff
Normal file
BIN
views/assets/fonts/NeueMontreal-Regular.woff2
Normal file
|
Before Width: | Height: | Size: 9 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 7 KiB |
|
Before Width: | Height: | Size: 9 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 3 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
|
@ -1,41 +0,0 @@
|
|||
{
|
||||
"name": "App",
|
||||
"icons": [
|
||||
{
|
||||
"src": "\/android-icon-36x36.png",
|
||||
"sizes": "36x36",
|
||||
"type": "image\/png",
|
||||
"density": "0.75"
|
||||
},
|
||||
{
|
||||
"src": "\/android-icon-48x48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image\/png",
|
||||
"density": "1.0"
|
||||
},
|
||||
{
|
||||
"src": "\/android-icon-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image\/png",
|
||||
"density": "1.5"
|
||||
},
|
||||
{
|
||||
"src": "\/android-icon-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image\/png",
|
||||
"density": "2.0"
|
||||
},
|
||||
{
|
||||
"src": "\/android-icon-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image\/png",
|
||||
"density": "3.0"
|
||||
},
|
||||
{
|
||||
"src": "\/android-icon-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image\/png",
|
||||
"density": "4.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Before Width: | Height: | Size: 9 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
1
views/assets/img/apple-icon.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" viewBox="0 0 87.1 77.8"><ellipse cx="43.572" cy="51.352" rx="41.472" ry="24.375" style="paint-order:stroke;stroke-width:4px;fill:#4c566a;stroke:#edf0f5"></ellipse><path d="m68.755 14.387.017 36.603s-.017 1.001-.017 1.514c0 6.786-11.275 12.287-25.183 12.287S18.389 59.29 18.389 52.504V14.387C18.389 7.601 29.664 2.1 43.572 2.1s25.183 5.501 25.183 12.287Z" style="paint-order:stroke;stroke-width:4px;stroke:#edf0f5;fill:#edf0f5"></path><path d="M18.372 20.091c10.042 11.58 40.694 11.16 50.4 0V50.99s-.017 1.001-.017 1.514c0 6.786-11.275 12.287-25.183 12.287S18.389 59.29 18.389 52.504z" style="paint-order:stroke;stroke-width:4px;stroke:#edf0f5;fill:#2e3440"></path><ellipse cx="43.572" cy="14.387" rx="25.183" ry="12.287" style="paint-order:stroke;stroke-width:4px;fill:#4c566a"></ellipse><ellipse cx="33.142" cy="42.26" rx="5.84" ry="7.949" style="paint-order:stroke;stroke-width:4px;stroke:#edf0f5;fill:#4c566a"></ellipse><ellipse cx="54.002" cy="42.26" rx="5.84" ry="7.949" style="paint-order:stroke;stroke-width:4px;stroke:#edf0f5;fill:#4c566a"></ellipse><path d="M11.746 16.194h46.295v18.34H11.746z" style="fill:#4c566a;stroke:#edf0f5;stroke-width:1.43739px" transform="matrix(1.33778 0 0 1.44503 8.486 26.775)"></path><text x="42.449" y="70.848" font-size=".999em" style="fill:#edf0f5;font-family:Arial,sans-serif;font-weight:700;stroke-width:1.70318px;white-space:pre-wrap;text-align:center;text-anchor:middle" transform="matrix(1.34372 0 0 1.50187 -1.874 -35.181)">BETA</text></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
BIN
views/assets/img/apps.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
BIN
views/assets/img/config.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
views/assets/img/config2.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
BIN
views/assets/img/emu/gb.png
Normal file
|
After Width: | Height: | Size: 749 B |
|
Before Width: | Height: | Size: 782 B |
BIN
views/assets/img/emu/gba.png
Normal file
|
After Width: | Height: | Size: 885 B |
|
Before Width: | Height: | Size: 1 KiB |
BIN
views/assets/img/emu/gbc.png
Normal file
|
After Width: | Height: | Size: 748 B |
|
Before Width: | Height: | Size: 890 B |
BIN
views/assets/img/emu/genesis.png
Normal file
|
After Width: | Height: | Size: 948 B |
|
Before Width: | Height: | Size: 816 B |
BIN
views/assets/img/emu/nes.png
Normal file
|
After Width: | Height: | Size: 859 B |
|
Before Width: | Height: | Size: 1.1 KiB |
BIN
views/assets/img/emu/nintendo64.png
Normal file
|
After Width: | Height: | Size: 836 B |
|
Before Width: | Height: | Size: 708 B |
BIN
views/assets/img/emu/nintendods.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 838 B |
BIN
views/assets/img/emu/snes.png
Normal file
|
After Width: | Height: | Size: 809 B |