diff --git a/README.md b/README.md index c2104ac3..278213ae 100644 --- a/README.md +++ b/README.md @@ -201,7 +201,7 @@ This is an example of DNS records involving Heroku. Self-hosting will require `A As stated previously, Holy Unblocker is hosted locally with Ultraviolet. #### Freenom/Domain Steps -For beginners, Freenom is a good provider for obtaining domains for free. However the catch is that you can only use properly "Freenom" domains for free being .cf, .ml, .gq, ga and .tk. However these can be blocked rather easily. +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. diff --git a/src/randomization.mjs b/src/randomization.mjs index fc2e3d22..94e55c57 100644 --- a/src/randomization.mjs +++ b/src/randomization.mjs @@ -6,22 +6,21 @@ export { insertText, paintSource, tryReadFile }; /* // Try this instead of the .replace method. Might be more performant. // Will edit str by replacing all matches of lis with newText. -// Usage: insertText(["", ""], -// " Big Giant Paragraph Smol Paragraph", +// Usage: insertText(['', ''], +// ' Big Giant Paragraph Smol Paragraph', // stringOrFunctionToGenerateNewText); */ const insertText = (lis, str, newText) => { -// The lis argument should be a list of strings containing placeholders. -// This will put other relevant argument types, like a string, into a list. - lis = [].concat(lis); - let position; -// Loop through each of the placeholder strings. - for (let placeholder of lis) { + +// The lis argument should be a list of strings containing placeholders. +// Ensure lis is formatted as a list, and loop through each of the +// placeholder strings. + for (let placeholder of [].concat(lis)) { // Find all matches of a placeholder string and insert new text there. while ((position = str.indexOf(placeholder)) >= 0) str = str.slice(0, position) - + (typeof newText == "function" ? newText() : newText) + + (typeof newText == 'function' ? newText() : newText) + str.slice(position + placeholder.length); } return str; @@ -34,7 +33,7 @@ const insertText = (lis, str, newText) => { // changes with each time it is loaded. const randomListItem = lis => () => lis[Math.random() * lis.length | 0], -charset = ["­", "​", "­", ""], +charset = ['­', '​', '­', ''], getRandomChar = randomListItem(charRandom), insertCharset = str => insertText( charset, @@ -44,14 +43,14 @@ insertCharset = str => insertText( getRandomSplash = randomListItem(splashRandom), hutaoInsert = str => insertText( - "", + '', str, getRandomSplash ), getCookingText = () => `${randomListItem(cookingInserts)()}`, insertCooking = str => insertText( - "", + '', str, getCookingText ), @@ -67,7 +66,7 @@ cacheBusting = str => { paintSource = str => insertCharset(hutaoInsert(insertCooking(cacheBusting(str)))), // Grabs the text content of a file. -tryReadFile = file => existsSync(file) ? readFileSync(file, "utf8") : text404; +tryReadFile = file => existsSync(file) ? readFileSync(file, 'utf8') : text404; /* // All of this is now old code. diff --git a/src/server.mjs b/src/server.mjs index 5f002700..7d6ab00a 100644 --- a/src/server.mjs +++ b/src/server.mjs @@ -8,10 +8,10 @@ import helmet from 'helmet'; import http from 'http'; import createRammerhead from 'rammerhead/src/server/index.js'; import { createBareServer } from '@tomphttp/bare-server-node'; -import wisp from "wisp-server-node"; -import { epoxyPath } from "@mercuryworkshop/epoxy-transport"; -import { baremuxPath } from "@mercuryworkshop/bare-mux/node"; -import { uvPath } from "@titaniumnetwork-dev/ultraviolet"; +import wisp from 'wisp-server-node'; +import { epoxyPath } from '@mercuryworkshop/epoxy-transport'; +import { baremuxPath } from '@mercuryworkshop/bare-mux/node'; +import { uvPath } from '@titaniumnetwork-dev/ultraviolet'; const config = JSON.parse(await readFile(new URL('./config.json', import.meta.url))); const { pages, text404 } = pkg; @@ -104,9 +104,9 @@ router.get('/', async (req, res) => res.send(paintSource(loadTemplates(tryReadFi 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("/baremux/", express.static(baremuxPath)); +app.use('/uv/', express.static(uvPath)); +app.use('/epoxy/', express.static(epoxyPath)); +app.use('/baremux/', express.static(baremuxPath)); app.disable('x-powered-by'); diff --git a/src/templates.mjs b/src/templates.mjs index 44dbe021..64d7c838 100644 --- a/src/templates.mjs +++ b/src/templates.mjs @@ -20,19 +20,19 @@ terms = tryReadFile(path.normalize(__dirname + '/views/pages/misc/deobf/tos.html settings = tryReadFile(path.normalize(__dirname + '/views/pages/misc/deobf/settings.html')), loadTemplates = str => { - str = insertText("", str, header); - str = insertText("", str, footer); + str = insertText('', str, header); + str = insertText('', str, footer); // Never used -// str = insertText("", str, description); +// str = insertText('', str, description); // Used only on docs.html - str = insertText("", str, documentation); + str = insertText('', str, documentation); // Used only on faq.html - str = insertText("", str, faq); + str = insertText('', str, faq); // Used only on terms.html - str = insertText("", str, terms); + str = insertText('', str, terms); // Used only on csel.html - str = insertText("", str, settings); + str = insertText('', str, settings); return str; }; \ No newline at end of file diff --git a/views/assets/css/styles-1644738239.css b/views/assets/css/styles-1644738239.css index 1cd2ea2e..b481110a 100644 --- a/views/assets/css/styles-1644738239.css +++ b/views/assets/css/styles-1644738239.css @@ -1016,7 +1016,7 @@ details[open] summary { height: 100%; background-color: var(--nord1); overflow: hidden; - display: block; + display: none; z-index: 1; } diff --git a/views/assets/js/card.js b/views/assets/js/card.js index e10140ac..1b13e8fd 100644 --- a/views/assets/js/card.js +++ b/views/assets/js/card.js @@ -6,22 +6,27 @@ const shimmerEffects = document.querySelectorAll(".box-card"); - +// Attach CSS variables, mouse-x and mouse-y, to elements that will be +// given shimmer effects, by adding or modifying the style attribute. +// CSS calculates and renders the actual shimmer effect from there. shimmerEffects.forEach(shimmerEffect => { shimmerEffect.addEventListener("mousemove", handleMouseMove); shimmerEffect.addEventListener("mouseleave", handleMouseLeave); }); -function handleMouseMove(e) { +// Track the cursor position with respect to the top left of the card. +// The "this" keyword gets the element that invoked the event listener. +const handleMouseMove = e => { const rect = this.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; this.style.setProperty("--mouse-x", `${x}px`); this.style.setProperty("--mouse-y", `${y}px`); -} +}; -function handleMouseLeave() { +// Reset the cursor tracking variables when the cursor leaves the card. +const handleMouseLeave = () => { this.style.setProperty("--mouse-x", `50%`); this.style.setProperty("--mouse-y", `50%`); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/views/assets/js/common-16451543478.js b/views/assets/js/common-16451543478.js index ee946df7..893a06d1 100644 --- a/views/assets/js/common-16451543478.js +++ b/views/assets/js/common-16451543478.js @@ -4,66 +4,43 @@ /* MAIN Holy Unblocker LTS Common Script /* ----------------------------------------------- */ -function tryGetElement(id) { - return document.getElementById(id) || {}; -} +// Used in scripts outside this file. +const tryGetElement = id => document.getElementById(id) || {}; /** * Get the preferred apex domain name. * Not exactly apex, as any subdomain other than those listed will be ignored. **/ -function getDomain() { - return location.host.replace(/^(www|edu|cooking|beta)\./, ""); -} +const getDomain = () => location.host.replace(/^(www|edu|cooking|beta)\./, ""); /* STEALTH FRAME */ -function goFrame(url) { +const goFrame = url => { localStorage.setItem("huframesrc", url); - window.location.href = "?s"; -} + location.href = "?s"; +}; -function goToUrl(url, stealth, nolag) { - if (stealth) { - goFrame(url, nolag); - } else { - window.location.href = url; - } -} +const goToUrl = (url, stealth, nolag) => { + stealth ? goFrame(url, nolag) : location.href = url; +}; /* COOKIE AUTH DEMO */ -function setAuthCookie(s, lax) { - document.cookie = - s + - "; expires=" + - (Date.now() + 259200) + - "; SameSite=" + - (lax ? "Lax" : "None") + - "; domain=." + - getDomain() + - "; path=/; Secure;"; -} +const setAuthCookie = (s, lax) => { + document.cookie = s + `; expires=${Date.now() + 259200}; SameSite=${lax ? "Lax" : "None"}; domain=.${getDomain()}; path=/; Secure;`; +}; /* OMNIBOX */ const sx = "bing.com" + "/search?q="; -function omnibox(url) { - if (url.substring(0, 4) == "http") { - return url; - } else if (url.includes("." || "")) { - return "https://" + url; - } else { - return "https://" + sx + url; - } -} +const omnibox = url => + (url.indexOf("http") + ? "https://" + (url.indexOf(".") < 1 ? sx : "") + : "") + + url; -function uvUrl(url) { - return ( - location.origin + __uv$config.prefix + __uv$config.encodeUrl(omnibox(url)) - ); -} +const uvUrl = url => location.origin + __uv$config.prefix + __uv$config.encodeUrl(omnibox(url)); /* RAMMERHEAD CONFIGURATION */ diff --git a/views/assets/js/csel.js b/views/assets/js/csel.js index 1aa3458f..a3678aea 100644 --- a/views/assets/js/csel.js +++ b/views/assets/js/csel.js @@ -1,9 +1,137 @@ /* ----------------------------------------------- -/* Authors: OlyB +/* Authors: OlyB and Yoct /* GNU Affero General Public License v3.0: https://www.gnu.org/licenses/agpl-3.0.en.html +/* Adapted and modified by Yoct. /* Settings Menu /* ----------------------------------------------- */ + +// Determine the expiration date of a new cookie. +let date = new Date(); +date.setFullYear(date.getFullYear() + 100); +date = date.toUTCString(); + +// All cookies should be secure and are intended to work in iframes. +const setCookie = (name, value) => { + document.cookie = name + `=${encodeURIComponent(value)}; expires=${date}; SameSite=None; Secure;`; +}, + +removeCookie = name => { + document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:01 GMT; "; +}, + +readCookie = async name => { + for (let cookie of document.cookie.split("; ")) +// Get the first cookie that has the same name. + if (!cookie.indexOf(name + "=")) +// Return the cookie's stored content. + return decodeURIComponent(cookie.slice(name.length + 1)); +}, + +// Customize the page's title. +pageTitle = value => { + let tag = document.getElementsByTagName("title")[0] || document.createElement("title"); + tag.innerHTML = value; + document.head.appendChild(tag); +}, + +// Set the page's favicon to a new URL. +pageIcon = value => { + let tag = document.querySelector("link[rel*='icon']") || document.createElement("link"); + tag.rel = "icon"; + tag.href = value; + document.head.appendChild(tag); +}, + +// Make a small stylesheet to override a setting from the main stylesheet. +pageShowAds = () => { + let advertising = document.createElement("style"); + advertising.id = "advertising"; + advertising.innerText = ".ad { display:block; }"; + (document.head || document.body || document.documentElement || document).appendChild(advertising); +}, + +// Remove the stylesheet made by the function above, if it exists. +pageHideAds = () => { + (document.getElementById("advertising")||new Text()).remove(); +}; + + +// Load a custom page title and favicon if it was previously stored. +readCookie("HBTitle").then(s => (s != undefined) && pageTitle(s)); +readCookie("HBIcon").then(s => (s != undefined) && pageIcon(s)); + +// Ads are disabled by default. Load ads if ads were enabled previously. +readCookie("HBHideAds").then(s => (s != "false") ? pageHideAds() : pageShowAds((document.getElementById("hideads") || {}).checked = 0)); + +// All code below is used by the Settings UI in the navigation bar. +if (document.getElementById("csel")) { + +// Allow users to set a custom title with the UI. + document.getElementById("titleform").addEventListener("submit", e => { + e.preventDefault(); + e = this.firstElementChild; + if (e.value) { + pageTitle(e.value); + setCookie("HBTitle", e.value); + e.value = ""; + } else { + alert("Please provide a title."); + } + }, false); + +// Allow users to set a custom favicon with the UI. + document.getElementById("iconform").addEventListener("submit", e => { + e.preventDefault(); + e = this.firstElementChild; + if (e.value) { + pageIcon(e.value); + setCookie("HBIcon", e.value); + e.value = ""; + } else { + alert("Please provide an icon URL."); + } + }, false); + +// Allow users to reset the title and favicon to default with the UI. + document.getElementById("cselreset").addEventListener("click", () => { + if (confirm("Reset the title and icon to default?")) { + removeCookie("HBTitle"); + removeCookie("HBIcon"); + pageTitle("Holy Unblocker"); + pageIcon("assets/img/icon.png"); + } + }, false); + +// Allow users to make a new about:blank tab and view the site from there. +// An iframe of the current page is inserted into the new tab. + document.getElementById("cselab").addEventListener("click", () => { + let win = window.open(); + let iframe = win.document.createElement("iframe"); + iframe.style = "width: 100%; height: 100%; border: none; overflow: hidden; margin: 0; padding: 0; position: fixed; top: 0; left: 0"; + iframe.src = location.href; + win.document.body.appendChild(iframe); + }); + +// Allow users to enable or disable ads with the UI. + document.getElementById("hideads").addEventListener("change", e => { + if (e.target.checked) { + pageHideAds(); + setCookie("HBHideAds", "true"); + } else { + pageShowAds(); + setCookie("HBHideAds", "false"); + } + }, false); +} + + + +/* ----------------------------------------------- +/* Original code written by OlyB +/* ----------------------------------------------- + + (function() { let date = new Date(); date.setFullYear(date.getFullYear() + 100); @@ -133,4 +261,5 @@ decodeURIComponent(atob("JTNDcCUyMGNsYXNzJTNEJTIyY3NlbHRpdGxlJTIyJTNFVGFiJTIwQ2x e.target.checked ? hideAds() : showAds(); }, false); } -})(); \ No newline at end of file +})(); +*/ \ No newline at end of file diff --git a/views/pages/misc/deobf/settings.html b/views/pages/misc/deobf/settings.html index ca9bfa34..d4e8a032 100644 --- a/views/pages/misc/deobf/settings.html +++ b/views/pages/misc/deobf/settings.html @@ -1,16 +1,16 @@ -

Tab Cloak

-

Change the title:

-
- +

Tab Cloak

+

Change the title:

+ +
-

Change the icon:

-
- +

Change the icon:

+ +
- - -

- + + +

+ Hide Ads

Ads are disabled forever.

\ No newline at end of file