Merge pull request #75 from cohenerickson/main

Format using prettier & bump NodeJS version requirements. [hyper epic !]
This commit is contained in:
Green! 2023-02-05 21:49:29 -05:00 committed by GitHub
commit 08afaff9f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 4791 additions and 4435 deletions

View file

@ -1,3 +0,0 @@
{
"files": {}
}

View file

@ -1,9 +1,9 @@
// See https://containers.dev/implementors/json_reference/ for configuration reference // See https://containers.dev/implementors/json_reference/ for configuration reference
{ {
"name": "Nebula", "name": "Nebula",
"build": { "build": {
"dockerfile": "Dockerfile" "dockerfile": "Dockerfile"
}, },
"remoteUser": "node", "remoteUser": "node",
"postCreateCommand": "npm install" "postCreateCommand": "npm install"
} }

7
.gitignore vendored
View file

@ -1,2 +1,7 @@
# dependencies
/node_modules /node_modules
.DS_Store
# System Files
.DS_Store
Thumbs.db
.breakpoints

1
.prettierignore Normal file
View file

@ -0,0 +1 @@
node_modules

6
.prettierrc Normal file
View file

@ -0,0 +1,6 @@
{
"tabWidth": 2,
"useTabs": false,
"singleQuote": false,
"trailingComma": "none"
}

32
.replit
View file

@ -1,19 +1,31 @@
entrypoint = "app.js"
hidden = [".config"] hidden = [".config", "package-lock.json"]
run = "npm start"
[interpreter]
command = [
"prybar-nodejs",
"-q",
"--ps1",
"\u0001\u001b[33m\u0002\u0001\u001b[00m\u0002 ",
"-i"
]
[[hints]] [[hints]]
regex = "Error \\[ERR_REQUIRE_ESM\\]" regex = "Error \\[ERR_REQUIRE_ESM\\]"
message = "We see that you are using require(...) inside your code. We currently do not support this syntax. Please use 'import' instead when using external modules. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)" message = "We see that you are using require(...) inside your code. We currently do not support this syntax. Please use 'import' instead when using external modules. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)"
[nix] [nix]
channel = "stable-21_11" channel = "stable-22_11"
[env] [env]
XDG_CONFIG_HOME = "/home/runner/.config" XDG_CONFIG_HOME = "/home/runner/.config"
PATH = "/home/runner/$REPL_SLUG/.config/npm/node_global/bin:/home/runner/$REPL_SLUG/node_modules/.bin" PATH = "/home/runner/$REPL_SLUG/.config/npm/node_global/bin:/home/runner/$REPL_SLUG/node_modules/.bin"
npm_config_prefix = "/home/runner/$REPL_SLUG/.config/npm/node_global" npm_config_prefix = "/home/runner/$REPL_SLUG/.config/npm/node_global"
[gitHubImport]
requiredFiles = [".replit", "replit.nix", ".config", "package.json", "package-lock.json"]
[packager] [packager]
language = "nodejs" language = "nodejs"
@ -25,12 +37,6 @@ language = "nodejs"
[unitTest] [unitTest]
language = "nodejs" language = "nodejs"
[languages.javascript]
pattern = "**/{*.js,*.jsx,*.ts,*.tsx}"
[languages.javascript.languageServer]
start = [ "typescript-language-server", "--stdio" ]
[debugger] [debugger]
support = true support = true
@ -70,3 +76,11 @@ support = true
sourceMaps = true sourceMaps = true
stopOnEntry = false stopOnEntry = false
type = "pwa-node" type = "pwa-node"
[languages]
[languages.javascript]
pattern = "**/{*.js,*.jsx,*.ts,*.tsx}"
[languages.javascript.languageServer]
start = "typescript-language-server --stdio"

7
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,7 @@
{
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}

195
README.md
View file

@ -1,39 +1,34 @@
# Nebula # Nebula
NebulaWeb is an official flagship of Nebula Services and Nebula Developer Labs. NebulaWeb is a stunning, sleek, and functional web-proxy with support for thousands of popular sites. With NebulaWeb, the sky is the limit. NebulaWeb is an official flagship of Nebula Services and Nebula Developer Labs. NebulaWeb is a stunning, sleek, and functional web-proxy with support for thousands of popular sites. With NebulaWeb, the sky is the limit.
![license](https://img.shields.io/badge/License-GNU%20AGPL%20v3-blue) ![license](https://img.shields.io/badge/License-GNU%20AGPL%20v3-blue)
![chat](https://img.shields.io/badge/chat-1139%20online-brightgreen)
![chat](https://img.shields.io/badge/chat-1139%20online-brightgreen)
## Features ## Features
- Stunning and highly functional UI with multiple themes - Stunning and highly functional UI with multiple themes
- XOR/b64 encoding all traffic - XOR/b64 encoding all traffic
- Hides your IP from sites - Hides your IP from sites
- [List of officially supported sites](https://github.com/NebulaServices/Nebula/blob/main/docs/officially-supported-sites.md) - [List of officially supported sites](https://github.com/NebulaServices/Nebula/blob/main/docs/officially-supported-sites.md)
- *limited* mobile support - _limited_ mobile support
- Stealth Mode (buffed `about:blank` cloaking) - Stealth Mode (buffed `about:blank` cloaking)
- **NEW** Clickoff cloaking - **NEW** Clickoff cloaking
- **NEW** Email OTP verification - **NEW** Email OTP verification
# Deployment # Deployment
Table of contents Table of contents
- Quick & easy deployment - Quick & easy deployment
- Deployment configuration explaination - Deployment configuration explaination
- how to use email OTP Verification mode - how to use email OTP Verification mode
- Advanced Deployment - Advanced Deployment
- Filesystem - Filesystem
## Quick & Easy Deployment Options ## Quick & Easy Deployment Options
[![Deploy to Heroku](https://raw.githubusercontent.com/BinBashBanana/deploy-buttons/master/buttons/remade/heroku.svg)](https://heroku.com/deploy/?template=https://github.com/NebulaServices/Nebula) [![Deploy to Heroku](https://raw.githubusercontent.com/BinBashBanana/deploy-buttons/master/buttons/remade/heroku.svg)](https://heroku.com/deploy/?template=https://github.com/NebulaServices/Nebula)
<br> <br>
[![Run on Replit](https://raw.githubusercontent.com/BinBashBanana/deploy-buttons/master/buttons/remade/replit.svg)](https://replit.com/github/NebulaServices/Nebula) [![Run on Replit](https://raw.githubusercontent.com/BinBashBanana/deploy-buttons/master/buttons/remade/replit.svg)](https://replit.com/github/NebulaServices/Nebula)
@ -51,15 +46,18 @@ Table of contents
[![Deploy To Koyeb](https://binbashbanana.github.io/deploy-buttons/buttons/remade/koyeb.svg)](https://app.koyeb.com/deploy?type=git&repository=github.com/NebulaServices/Nebula&branch=main&name=NebulaProxy) [![Deploy To Koyeb](https://binbashbanana.github.io/deploy-buttons/buttons/remade/koyeb.svg)](https://app.koyeb.com/deploy?type=git&repository=github.com/NebulaServices/Nebula&branch=main&name=NebulaProxy)
--- ---
## Deployment Configuration Guide
(Example configuration with none-json notes) ## Deployment Configuration Guide
(Example configuration with none-json notes)
```json ```json
{ {
"sendgrid_verification": false, "sendgrid_verification": false,
"sendgrid_options": { "sendgrid_options": {
"api_key": "YOUR_SENDGRID_API_KEY", "api_key": "YOUR_SENDGRID_API_KEY",
"sendFromEmail": "THE EMAIL THE CODES WILL BE SENT FROM (MUST BE VERIFIED IN SENDGRID)", "sendFromEmail": "THE EMAIL THE CODES WILL BE SENT FROM (MUST BE VERIFIED IN SENDGRID)",
"to_email": "THE EMAIL YOU WANT THE CODES SENT TO" "to_email": "THE EMAIL YOU WANT THE CODES SENT TO"
}, },
"discord_verification": false, "discord_verification": false,
@ -79,77 +77,86 @@ Table of contents
} }
``` ```
## Email Verification OTP ## Email Verification OTP
### What is this?
Email verification is a new and unique feature that we've implemented in the event that someone wants to keep their deployment of Nebula private and secure. ### What is this?
Email verification is a new and unique feature that we've implemented in the event that someone wants to keep their deployment of Nebula private and secure.
### What does it do ### What does it do
When a user tries to access the website, before allowed access they will be asked for a One time password sent to an email set in the deployment configuration. Once verified, they will have 15 day access to the site.
When a user tries to access the website, before allowed access they will be asked for a One time password sent to an email set in the deployment configuration. Once verified, they will have 15 day access to the site.
#### SendGrid Setup Instructions #### SendGrid Setup Instructions
* Firstly, We need to enable verification within the deployment configuration
* change `"sendgrid_verification":false,` to `"sendgrid_verification":true,` above the SendGrid Section
* _Note: You have to reboot the node app for any changes to take place._ - Firstly, We need to enable verification within the deployment configuration
* Now, we need to use an api to send a message
* Make an account at Sendgrid (https://app.sendgrid.com/) - change `"sendgrid_verification":false,` to `"sendgrid_verification":true,` above the SendGrid Section
* _Note: It is likely that other versions of Nebula will use a different package to send emails._
* Verify the email you want to recieve emails from (Create a sender identity) - _Note: You have to reboot the node app for any changes to take place._
* Go to settings -> Sender authentication and click Verify a Single Sender
* Now, We need to get the API key to connect to the API - Now, we need to use an api to send a message
* Go to settings -> API Keys -> and make an API key. - Make an account at Sendgrid (https://app.sendgrid.com/)
* Complete the information in the deployment config `deployment.config.json` under the `sendgrid_options` section such as: sendFromEmail, to_email and api_key - _Note: It is likely that other versions of Nebula will use a different package to send emails._
- Verify the email you want to recieve emails from (Create a sender identity)
- Go to settings -> Sender authentication and click Verify a Single Sender
- Now, We need to get the API key to connect to the API
- Go to settings -> API Keys -> and make an API key.
- Complete the information in the deployment config `deployment.config.json` under the `sendgrid_options` section such as: sendFromEmail, to_email and api_key
#### Discord Webhook Setup Instructions #### Discord Webhook Setup Instructions
* Set discord_verification to true in the deployment configuration.
* Create a channel in a discord server you have admin in.
* Click the Edit Channel button.
* Click Integrations
* Click create web hook and copy the URL.
* Paste it under the `webhook_url` section in the deployment configuration.
#### SMTP Setup Instructions - Set discord_verification to true in the deployment configuration.
* Set `smtp_verification` to true. - Create a channel in a discord server you have admin in.
* Change `to_email` to the email address you want the codes to be sent to. - Click the Edit Channel button.
* Change `sendFromEmail to the email address that is going to send the codes. - Click Integrations
* Get the host and port from your email provider's documentation. - Click create web hook and copy the URL.
* Fill in your username and password under the `user` and `pass` section under auth. - Paste it under the `webhook_url` section in the deployment configuration.
#### SMTP Setup Instructions
## Advanced Deployment
- Set `smtp_verification` to true.
- Change `to_email` to the email address you want the codes to be sent to.
- Change `sendFromEmail to the email address that is going to send the codes.
- Get the host and port from your email provider's documentation.
- Fill in your username and password under the `user` and `pass` section under auth.
## Advanced Deployment
### Initial configuration ### Initial configuration
credits to @ProgrammerIn-wonderland for writing this wonderful tutorial (which can also be found in the docs :) credits to @ProgrammerIn-wonderland for writing this wonderful tutorial (which can also be found in the docs :)
* Create an account at https://www.cloudflare.com/ - Create an account at https://www.cloudflare.com/
* Create an account at https://www.freenom.com/ (or any registrars) - Create an account at https://www.freenom.com/ (or any registrars)
* Find a free domain name at Freenom - Find a free domain name at Freenom
* Click checkout - Click checkout
* Select (12 Months @ FREE) - Select (12 Months @ FREE)
* Select "Use DNS" - Select "Use DNS"
* Select Use your own DNS - Select Use your own DNS
* Go to cloudflare, click add new site, and enter the free domain name - Go to cloudflare, click add new site, and enter the free domain name
* Select "Free Plan" - Select "Free Plan"
* Click continue, ignore DNS - Click continue, ignore DNS
* Copy the name servers cloudflare gives you - Copy the name servers cloudflare gives you
* Go back to your Freenom tab, enter in the name servers which cloudflare gave you - Go back to your Freenom tab, enter in the name servers which cloudflare gave you
* You can keep IP blank - You can keep IP blank
* Click continue - Click continue
* Click complete order - Click complete order
* Go back to cloudflare tab, click "Check Nameservers" - Go back to cloudflare tab, click "Check Nameservers"
* Select DNS on your right bar - Select DNS on your right bar
* Enter in the IP of the server which will be hosting Nebula - Enter in the IP of the server which will be hosting Nebula
* Target will be `@` - Target will be `@`
* Click Enable proxy (little gray cloud icon, if active its orange) - Click Enable proxy (little gray cloud icon, if active its orange)
* Select SSL/TLS in your right bar - Select SSL/TLS in your right bar
* Click "Flexible" - Click "Flexible"
--- ---
### Server configuration ### Server configuration
* SSH into the server you'll be using, I'll assume its running Ubuntu 22.04 (though the commands are the same for debian 10+ versions, and Ubuntu versions 20.04+) - SSH into the server you'll be using, I'll assume its running Ubuntu 22.04 (though the commands are the same for debian 10+ versions, and Ubuntu versions 20.04+)
* run - run
``` ```
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - \ && curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - \ &&
sudo apt-get install -y nodejs npm sudo apt-get install -y nodejs npm
@ -161,48 +168,46 @@ sudo nohup PORT=80 node . &
``` ```
**Make sure your firewall is configured to let through port 80 traffic!** \ **Make sure your firewall is configured to let through port 80 traffic!** \
*Note: Server will need to run` cd Nebula && sudo nohup PORT=80 node . &` on reboot* _Note: Server will need to run` cd Nebula && sudo nohup PORT=80 node . &` on reboot_
## File Structure ## File Structure
| **File** | Purpose | |
|----------------------------------|----------------------------------------------------------------------------------------------------------|---|
| `static/index.html` | The main frontend visuals for NebulaWEB. | |
| `static/unv.html` | The verification-required frontend/visuals. | |
| `static/options/` | The frontend for Nebula's options, settings, and preferences. | |
| `static/resources/v.js` | Client verification system for the OTP system. | |
| `static/resources/nebulamain.js` | All of the DOM/client code for NebulaWEB. Includes options, themeSystem, cloak, stealthengine, and more. | |
| `app.js` | The backend server for Nebula. Contains Nodestatic, Bare, HTTP, and more. | |
| **File** | Purpose | |
| -------------------------------- | -------------------------------------------------------------------------------------------------------- | --- |
| `static/index.html` | The main frontend visuals for NebulaWEB. | |
| `static/unv.html` | The verification-required frontend/visuals. | |
| `static/options/` | The frontend for Nebula's options, settings, and preferences. | |
| `static/resources/v.js` | Client verification system for the OTP system. | |
| `static/resources/nebulamain.js` | All of the DOM/client code for NebulaWEB. Includes options, themeSystem, cloak, stealthengine, and more. | |
| `app.js` | The backend server for Nebula. Contains Nodestatic, Bare, HTTP, and more. | |
## Tech Stack ## Tech Stack
- HTML, JS, CSS - HTML, JS, CSS
- Partical.JS (Specifically v4, 5, 6.1 &< only) - Partical.JS (Specifically v4, 5, 6.1 &< only)
- UV Backend Proxy - UV Backend Proxy
- Osana Backend Proxy - Osana Backend Proxy
- TompHTTP Bare Server - TompHTTP Bare Server
- node HTTP (No ExpressJS!) - node HTTP (No ExpressJS!)
## Support ## Support
For support, email chloe@nebula.bio or join our discord: discord.gg/unblocker For support, email chloe@nebula.bio or join our discord: discord.gg/unblocker
## Demo ## Demo
[Click here to see a demo of Nebula](https://nebulaproxy.io/) [Click here to see a demo of Nebula](https://nebulaproxy.io/)
## Acknowledgements ## Acknowledgements
- [UV (one of the back-end proxy we use)](https://github.com/titaniumnetwork-dev/Ultraviolet) - [UV (one of the back-end proxy we use)](https://github.com/titaniumnetwork-dev/Ultraviolet)
- [Osana (one of the back-end proxy we use)](https://github.com/NebulaServices/Osana) - [Osana (one of the back-end proxy we use)](https://github.com/NebulaServices/Osana)
- [Bare Server](https://github.com/tomphttp/bare-server-node) - [Bare Server](https://github.com/tomphttp/bare-server-node)
- [Partical.JS (v4, 5, 6.1 &< only)](https://github.com/VincentGarreau/particles.js) - [Partical.JS (v4, 5, 6.1 &< only)](https://github.com/VincentGarreau/particles.js)
## License ## License
(Nebula's license is now GNU AGPL V3 as of v7.10) (Nebula's license is now GNU AGPL V3 as of v7.10)
Copyright Nebula Services 2021 - Present Copyright Nebula Services 2021 - Present
<br> <br>
This project uses the AGLP GNU V3 license. This project uses the AGLP GNU V3 license.

87
app.js
View file

@ -1,9 +1,9 @@
import createBareServer from "@tomphttp/bare-server-node"; import createBareServer from "@tomphttp/bare-server-node";
import http from "http"; import http from "http";
import {createRequire} from "module"; import { createRequire } from "module";
import {dirname, join} from "path"; import { dirname, join } from "path";
import serveStatic from "serve-static"; import serveStatic from "serve-static";
import {fileURLToPath} from "url"; import { fileURLToPath } from "url";
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
const config = require("./deployment.config.json"); const config = require("./deployment.config.json");
import fs from "fs"; import fs from "fs";
@ -12,30 +12,30 @@ import sgTransport from "nodemailer-sendgrid-transport";
import nodemailer from "nodemailer"; import nodemailer from "nodemailer";
import fetch from "node-fetch"; import fetch from "node-fetch";
const options = { const options = {
auth : { auth: {
api_key : config.sendgrid_options.api_key, api_key: config.sendgrid_options.api_key
}, }
}; };
const sendgridMailerAgent = nodemailer.createTransport(sgTransport(options)); const sendgridMailerAgent = nodemailer.createTransport(sgTransport(options));
const smtpMailerAgent = nodemailer.createTransport(config.smtp_options); const smtpMailerAgent = nodemailer.createTransport(config.smtp_options);
function sendVerificationEmail(UUID, OTP) { function sendVerificationEmail(UUID, OTP) {
let email = { let email = {
to : "", to: "",
from : "", from: "",
subject : `NebulaWEB personal access code ${OTP}`, subject: `NebulaWEB personal access code ${OTP}`,
text : ` text: `
####### ACCESS CODE (OTP) ${OTP} ####### ####### ACCESS CODE (OTP) ${OTP} #######
####### DO NOT SHARE THIS CODE! ####### ####### DO NOT SHARE THIS CODE! #######
(this message is automated)`, (this message is automated)`,
html : ` html: `
####### ACCESS CODE (OTP) ${OTP} ####### ####### ACCESS CODE (OTP) ${OTP} #######
####### DO NOT SHARE THIS CODE! ####### ####### DO NOT SHARE THIS CODE! #######
(this message is automated) (this message is automated)
`, `
}; };
if (config.sendgrid_verification == true) { if (config.sendgrid_verification == true) {
email.to = config.sendgrid_options.to_email email.to = config.sendgrid_options.to_email;
email.from = config.sendgrid_options.sendFromEmail email.from = config.sendgrid_options.sendFromEmail;
sendgridMailerAgent.sendMail(email, (err, res) => { sendgridMailerAgent.sendMail(email, (err, res) => {
if (err) { if (err) {
console.log(err); console.log(err);
@ -44,8 +44,8 @@ function sendVerificationEmail(UUID, OTP) {
}); });
} }
if (config.smtp_verification == true) { if (config.smtp_verification == true) {
email.to = config.smtp_options.to_email email.to = config.smtp_options.to_email;
email.from = config.smtp_options.sendFromEmail email.from = config.smtp_options.sendFromEmail;
smtpMailerAgent.sendMail(email, (err, res) => { smtpMailerAgent.sendMail(email, (err, res) => {
if (err) { if (err) {
console.log(err); console.log(err);
@ -55,13 +55,13 @@ function sendVerificationEmail(UUID, OTP) {
} }
if (config.discord_verification == true) { if (config.discord_verification == true) {
fetch(config.webhook_url, { fetch(config.webhook_url, {
method : "POST", method: "POST",
headers : { headers: {
"Content-Type" : "application/json", "Content-Type": "application/json"
}, },
body : JSON.stringify({ body: JSON.stringify({
content : `Your NebulaWEB access code is ${OTP}`, content: `Your NebulaWEB access code is ${OTP}`
}), })
}); });
} }
} }
@ -76,15 +76,17 @@ function getNewCode() {
const PORT = process.env.PORT || 3000; const PORT = process.env.PORT || 3000;
const bareServer = createBareServer("/bare/", { const bareServer = createBareServer("/bare/", {
logErrors : false, logErrors: false,
localAddress : undefined, localAddress: undefined
}); });
const serve = const serve = serveStatic(
serveStatic(join(dirname(fileURLToPath(import.meta.url)), "static/"), { join(dirname(fileURLToPath(import.meta.url)), "static/"),
fallthrough : false, {
maxAge : 5 * 60 * 1000, fallthrough: false,
}); maxAge: 5 * 60 * 1000
}
);
const server = http.createServer(); const server = http.createServer();
@ -97,9 +99,8 @@ server.on("request", (request, response) => {
const url = request.url; const url = request.url;
if (url.startsWith("/sendNewCode")) { if (url.startsWith("/sendNewCode")) {
const OTP = getNewCode(); const OTP = getNewCode();
fs.writeFile("./memory.txt", OTP, function(err) { fs.writeFile("./memory.txt", OTP, function (err) {
if (err) if (err) return console.log(err);
return console.log(err);
console.log(`Wrote OTP code to temp file`); console.log(`Wrote OTP code to temp file`);
}); });
@ -115,33 +116,35 @@ server.on("request", (request, response) => {
base64data = buff.toString("base64"); base64data = buff.toString("base64");
console.log("302"); console.log("302");
response.writeHead(302, { response.writeHead(302, {
location : "/unv.html?c=" + base64data, location: "/unv.html?c=" + base64data
}); });
response.end(); response.end();
}); });
} else if (url.startsWith("/verification")) { } else if (url.startsWith("/verification")) {
var body; var body;
if (config.sendgrid_verification == true || if (
config.discord_verification == true || config.sendgrid_verification == true ||
config.smtp_verificaton == true) { config.discord_verification == true ||
config.smtp_verificaton == true
) {
const body = "true"; const body = "true";
response.writeHead(200, { response.writeHead(200, {
"Content-Length" : Buffer.byteLength(body), "Content-Length": Buffer.byteLength(body),
"Content-Type" : "text/plain", "Content-Type": "text/plain"
}); });
response.end(body); response.end(body);
} else { } else {
const body = "false"; const body = "false";
response.writeHead(200, { response.writeHead(200, {
"Content-Length" : Buffer.byteLength(body), "Content-Length": Buffer.byteLength(body),
"Content-Type" : "text/plain", "Content-Type": "text/plain"
}); });
response.end(body); response.end(body);
} }
} else { } else {
serve(request, response, (err) => { serve(request, response, (err) => {
response.writeHead(err?.statusCode || 500, null, { response.writeHead(err?.statusCode || 500, null, {
"Content-Type" : "text/plain", "Content-Type": "text/plain"
}); });
response.end(err?.stack); response.end(err?.stack);
}); });
@ -149,7 +152,7 @@ server.on("request", (request, response) => {
} }
} catch (e) { } catch (e) {
response.writeHead(500, "Internal Server Error", { response.writeHead(500, "Internal Server Error", {
"Content-Type" : "text/plain", "Content-Type": "text/plain"
}); });
response.end(e.stack); response.end(e.stack);
} }

View file

@ -1,7 +1,7 @@
{ {
"name": "NebulaWEB", "name": "NebulaWEB",
"description": "Explore the web. Freely. ", "description": "Explore the web. Freely. ",
"repository": "https://github.com/NebulaServices/Nebula", "repository": "https://github.com/NebulaServices/Nebula",
"logo": "https://avatars.githubusercontent.com/u/86420004?v=4", "logo": "https://avatars.githubusercontent.com/u/86420004?v=4",
"keywords": ["educational", "science", "math"] "keywords": ["educational", "science", "math"]
} }

View file

@ -1,9 +1,9 @@
{ {
"sendgrid_verification": false, "sendgrid_verification": false,
"sendgrid_options": { "sendgrid_options": {
"api_key": "YOUR_SENDGRID_API_KEY", "api_key": "YOUR_SENDGRID_API_KEY",
"sendFromEmail": "THE EMAIL THE CODES WILL BE SENT FROM (MUST BE VERIFIED IN SENDGRID)", "sendFromEmail": "THE EMAIL THE CODES WILL BE SENT FROM (MUST BE VERIFIED IN SENDGRID)",
"to_email": "THE EMAIL YOU WANT THE CODES SENT TO" "to_email": "THE EMAIL YOU WANT THE CODES SENT TO"
}, },
"discord_verification": false, "discord_verification": false,

View file

@ -1,4 +1,4 @@
version: '3' version: "3"
services: services:
nebula: nebula:
image: nebula:latest image: nebula:latest

View file

@ -1,6 +1,8 @@
module.exports = { module.exports = {
apps: [{ apps: [
name: "Site", {
script: "proxysocks node app.js" name: "Site",
}] script: "proxysocks node app.js"
} }
]
};

6066
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,25 +1,25 @@
{ {
"name": "nebula-web", "name": "nebula-web",
"version": "7.10.0", "version": "7.11.6",
"description": "Explore the web. Freely.", "description": "Explore the web. Freely.",
"type": "module", "type": "module",
"main": "app.js", "main": "app.js",
"scripts": { "scripts": {
"start": "node app.js" "start": "node app.js"
}, },
"keywords": [ "keywords": [
"proxy" "proxy"
], ],
"author": "Nebula Services", "author": "Nebula Services",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"dependencies": { "dependencies": {
"@tomphttp/bare-server-node": "^1.2.2", "@tomphttp/bare-server-node": "^1.2.2",
"node-fetch": "^3.3.0", "node-fetch": "^3.3.0",
"nodemailer": "^6.8.0", "nodemailer": "^6.8.0",
"nodemailer-sendgrid-transport": "^0.2.0", "nodemailer-sendgrid-transport": "^0.2.0",
"serve-static": "^1.15.0" "serve-static": "^1.15.0"
}, },
"engines": { "engines": {
"node": ">=16.0.0" "node": ">=18"
} }
} }

View file

@ -1,8 +1,8 @@
{ pkgs }: { { pkgs }: {
deps = [ deps = [
pkgs.nodejs-16_x pkgs.nodejs-18_x
pkgs.nodePackages.typescript-language-server pkgs.nodePackages.typescript-language-server
pkgs.yarn pkgs.yarn
pkgs.replitPackages.jest pkgs.replitPackages.jest
]; ];
} }

File diff suppressed because one or more lines are too long

View file

@ -59,9 +59,9 @@
<div style='color:black;'> <div style='color:black;'>
Acknowledgements are resources Nebula is using/has used. Acknowledgements are resources Nebula is using/has used.
<ul style='color:black;'> <ul style='color:black;'>
<li><a style='color:black;' href="https://github.com/titaniumnetwork-dev/Ultraviolet">UV (one of the back-end proxy we use)</a></li> <li><a style='color:black;' href="https://github.com/titaniumnetwork-dev/Ultraviolet">Ultraviolet (one of the proxies we use)</a></li>
<li><a style='color:black;' href="https://github.com/NebulaServices/Osana">Osana (one of the back-end proxy we use)</a></li> <li><a style='color:black;' href="https://github.com/NebulaServices/Osana">Osana (one of the proxies we use)</a></li>
<li><a style='color:black;' href="https://github.com/tomphttp/bare-server-node">Bare Server</a></li> <li><a style='color:black;' href="https://github.com/tomphttp/bare-server-node">Bare Server Node</a></li>
<br> <br>
<li><a style='color:black;' href="https://github.com/VincentGarreau/particles.js">Partical.JS (v4, 5, 6.1 &amp;&lt; only)</a></li> <li><a style='color:black;' href="https://github.com/VincentGarreau/particles.js">Partical.JS (v4, 5, 6.1 &amp;&lt; only)</a></li>
</ul> </ul>

View file

@ -4,49 +4,103 @@
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]--> <!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]> <html class="no-js"> <!--<![endif]--> <!--[if gt IE 8]> <html class="no-js"> <!--<![endif]-->
<html> <html>
<head>
<head> <meta charset="utf-8" />
<meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title> <title></title>
<meta name="description" content=""> <meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href=""> <link rel="stylesheet" href="" />
</head> </head>
<body> <body>
<h2>Privacy Policy</h2> <h2>Privacy Policy</h2>
<p>Your privacy is important to us. It is Nebula Services&#39; policy to respect your privacy and comply with any applicable law and regulation regarding any personal information we may collect about you, including across our website, <a href="https://nebula.bio">https://nebula.bio</a>, <p>
and other sites we own and operate. </p> Your privacy is important to us. It is Nebula Services&#39; policy to
<p>This policy is effective as of 8 June 2022 and was last updated on 8 June 2022. </p> respect your privacy and comply with any applicable law and regulation
regarding any personal information we may collect about you, including
across our website, <a href="https://nebula.bio">https://nebula.bio</a>,
and other sites we own and operate.
</p>
<p>
This policy is effective as of 8 June 2022 and was last updated on 8 June
2022.
</p>
<h3>Information We Collect</h3> <h3>Information We Collect</h3>
<p>Information we collect includes both information you knowingly and actively provide us when using or participating in any of our services and promotions, and any information automatically sent by your devices in the course of accessing our products <p>
and services. </p> Information we collect includes both information you knowingly and
actively provide us when using or participating in any of our services and
promotions, and any information automatically sent by your devices in the
course of accessing our products and services.
</p>
<h4>Log Data</h4> <h4>Log Data</h4>
<p>When you visit our website, our servers may automatically log the standard data provided by your web browser. It may include your devices Internet Protocol (IP) address, your browser type and version, the pages you visit, the time and date of your <p>
visit, the time spent on each page, other details about your visit, and technical details that occur in conjunction with any errors you may encounter. </p> When you visit our website, our servers may automatically log the standard
<p>Please be aware that while this information may not be personally identifying by itself, it may be possible to combine it with other data to personally identify individual persons. </p> data provided by your web browser. It may include your devices Internet
Protocol (IP) address, your browser type and version, the pages you visit,
the time and date of your visit, the time spent on each page, other
details about your visit, and technical details that occur in conjunction
with any errors you may encounter.
</p>
<p>
Please be aware that while this information may not be personally
identifying by itself, it may be possible to combine it with other data to
personally identify individual persons.
</p>
<h4>Collection and Use of Information</h4> <h4>Collection and Use of Information</h4>
<p>We may collect personal information from you when you do any of the following on our website: </p> <p>
We may collect personal information from you when you do any of the
following on our website:
</p>
<ul> <ul>
<li>Use a mobile device or web browser to access our content</li> <li>Use a mobile device or web browser to access our content</li>
<li>Contact us via email, social media, or on any similar technologies</li> <li>
<li>When you mention us on social media</li> Contact us via email, social media, or on any similar technologies
</li>
<li>When you mention us on social media</li>
</ul> </ul>
<h3>Childrens Privacy</h3> <h3>Childrens Privacy</h3>
<p>We do not aim any of our products or services directly at children under the age of 13, and we do not knowingly collect personal information about children under 13. </p> <p>
We do not aim any of our products or services directly at children under
the age of 13, and we do not knowingly collect personal information about
children under 13.
</p>
<h3>Use of Cookies</h3> <h3>Use of Cookies</h3>
<p>We use &ldquo;cookies&rdquo; to collect information about you and your activity across our site. A cookie is a small piece of data that our website stores on your computer, and accesses each time you visit, so we can understand how you use our site. <p>
This helps us serve you content based on preferences you have specified. </p> We use &ldquo;cookies&rdquo; to collect information about you and your
activity across our site. A cookie is a small piece of data that our
website stores on your computer, and accesses each time you visit, so we
can understand how you use our site. This helps us serve you content based
on preferences you have specified.
</p>
<h3>Limits of Our Policy</h3> <h3>Limits of Our Policy</h3>
<p>Our website may link to external sites that are not operated by us. Please be aware that we have no control over the content and policies of those sites, and cannot accept responsibility or liability for their respective privacy practices. </p> <p>
Our website may link to external sites that are not operated by us. Please
be aware that we have no control over the content and policies of those
sites, and cannot accept responsibility or liability for their respective
privacy practices.
</p>
<h3>Changes to This Policy</h3> <h3>Changes to This Policy</h3>
<p>At our discretion, we may change our privacy policy to reflect updates to our business processes, current acceptable practices, or legislative or regulatory changes. If we decide to change this privacy policy, we will post the changes here at the <p>
same link by which you are accessing this privacy policy. </p> At our discretion, we may change our privacy policy to reflect updates to
<p>If required by law, we will get your permission or give you the opportunity to opt in to or opt out of, as applicable, any new uses of your personal information. </p> our business processes, current acceptable practices, or legislative or
regulatory changes. If we decide to change this privacy policy, we will
post the changes here at the same link by which you are accessing this
privacy policy.
</p>
<p>
If required by law, we will get your permission or give you the
opportunity to opt in to or opt out of, as applicable, any new uses of
your personal information.
</p>
<h3>Contact Us</h3> <h3>Contact Us</h3>
<p>For any questions or concerns regarding your privacy, you may contact us using the following details: </p> <p>
<p>Chloe B<br /> chloe@nebula.bio </p> For any questions or concerns regarding your privacy, you may contact us
</body> using the following details:
</p>
</html> <p>
Chloe B<br />
chloe@nebula.bio
</p>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -1,161 +1,161 @@
// OPTIONS // OPTIONS
const storedSetTheme = localStorage.getItem('theme') const storedSetTheme = localStorage.getItem("theme");
function switchProxy () { function switchProxy() {
var selecter = document.getElementById('proxySwitcher') var selecter = document.getElementById("proxySwitcher");
var selectedOption = selecter.value var selectedOption = selecter.value;
localStorage.setItem('proxy', selectedOption) localStorage.setItem("proxy", selectedOption);
var storedChoice = localStorage.getItem('proxy') var storedChoice = localStorage.getItem("proxy");
console.log(selectedOption) console.log(selectedOption);
} }
function switchTheme () { function switchTheme() {
var selecter = document.getElementById('themeSwitcher') var selecter = document.getElementById("themeSwitcher");
var selectedOption = selecter.value var selectedOption = selecter.value;
if (selectedOption == 'dark') { if (selectedOption == "dark") {
changeCSS('--background-primary', '#191724', true) changeCSS("--background-primary", "#191724", true);
changeCSS('--navbar-color', '#26233a', true) changeCSS("--navbar-color", "#26233a", true);
changeCSS('--navbar-height', '60px', true) changeCSS("--navbar-height", "60px", true);
changeCSS('--navbar-text-color', '#7967dd', true) changeCSS("--navbar-text-color", "#7967dd", true);
changeCSS('--input-text-color', '#e0def4', true) changeCSS("--input-text-color", "#e0def4", true);
changeCSS('--input-placeholder-color', '#6e6a86', true) changeCSS("--input-placeholder-color", "#6e6a86", true);
changeCSS('--input-background-color', '#1f1d2e', true) changeCSS("--input-background-color", "#1f1d2e", true);
changeCSS('--input-placeholder-color', 'white', true) changeCSS("--input-placeholder-color", "white", true);
changeCSS('--input-border-color', '#eb6f92', true) changeCSS("--input-border-color", "#eb6f92", true);
changeCSS('--input-border-size', '1.3px', true) changeCSS("--input-border-size", "1.3px", true);
changeCSS('--navbar-link-color', '#e0def4', true) changeCSS("--navbar-link-color", "#e0def4", true);
changeCSS('--navbar-font', '"Roboto"', true) changeCSS("--navbar-font", '"Roboto"', true);
changeCSS('--navbar-logo-filter', 'invert(0%)', true) changeCSS("--navbar-logo-filter", "invert(0%)", true);
changeCSS('--text-color-primary', '#e0def4', true) changeCSS("--text-color-primary", "#e0def4", true);
localStorage.setItem('theme', 'dark') localStorage.setItem("theme", "dark");
} }
if (selectedOption == 'light') { if (selectedOption == "light") {
changeCSS('--background-primary', '#d8d8d8', true) changeCSS("--background-primary", "#d8d8d8", true);
changeCSS('--navbar-color', '#a2a2a2', true) changeCSS("--navbar-color", "#a2a2a2", true);
changeCSS('--navbar-height', '4em', true) changeCSS("--navbar-height", "4em", true);
changeCSS('--navbar-text-color', '#000000', true) changeCSS("--navbar-text-color", "#000000", true);
changeCSS('--input-text-color', '#e0def4', true) changeCSS("--input-text-color", "#e0def4", true);
changeCSS('--input-placeholder-color', 'white', true) changeCSS("--input-placeholder-color", "white", true);
changeCSS('--input-background-color', 'black', true) changeCSS("--input-background-color", "black", true);
changeCSS('--input-border-color', '#eb6f92', true) changeCSS("--input-border-color", "#eb6f92", true);
changeCSS('--input-border-size', '1.3px', true) changeCSS("--input-border-size", "1.3px", true);
changeCSS('--navbar-link-color', '#000000', true) changeCSS("--navbar-link-color", "#000000", true);
changeCSS('--navbar-font', '"Roboto"', true) changeCSS("--navbar-font", '"Roboto"', true);
changeCSS('--navbar-logo-filter', 'invert(30%)', true) changeCSS("--navbar-logo-filter", "invert(30%)", true);
changeCSS('--text-color-primary', '#303030', true) changeCSS("--text-color-primary", "#303030", true);
localStorage.setItem('theme', 'light') localStorage.setItem("theme", "light");
} }
if (selectedOption == 'custom') { if (selectedOption == "custom") {
let response = prompt('Please enter the code for a custom theme:', '') let response = prompt("Please enter the code for a custom theme:", "");
alert('This feature is not ready yet. Please try again later.') alert("This feature is not ready yet. Please try again later.");
} }
} }
// onload event // onload event
window.onload = function () { window.onload = function () {
let background = localStorage.getItem('--background-primary') let background = localStorage.getItem("--background-primary");
let navbar = localStorage.getItem('--navbar-color') let navbar = localStorage.getItem("--navbar-color");
let navbarHeight = localStorage.getItem('--navbar-height') let navbarHeight = localStorage.getItem("--navbar-height");
let navbarText = localStorage.getItem('--navbar-text-color') let navbarText = localStorage.getItem("--navbar-text-color");
let inputText = localStorage.getItem('--input-text-color') let inputText = localStorage.getItem("--input-text-color");
let inputPlaceholder = localStorage.getItem('--input-placeholder-color') let inputPlaceholder = localStorage.getItem("--input-placeholder-color");
let inputBackground = localStorage.getItem('--input-background-color') let inputBackground = localStorage.getItem("--input-background-color");
let inputBorder = localStorage.getItem('--input-border-color') let inputBorder = localStorage.getItem("--input-border-color");
let inputBorderSize = localStorage.getItem('--input-border-size') let inputBorderSize = localStorage.getItem("--input-border-size");
let navbarFont = localStorage.getItem('--navbar-font') let navbarFont = localStorage.getItem("--navbar-font");
let navbarLink = localStorage.getItem('--navbar-link-color') let navbarLink = localStorage.getItem("--navbar-link-color");
let navbarLogoFilter = localStorage.getItem('--navbar-logo-filter') let navbarLogoFilter = localStorage.getItem("--navbar-logo-filter");
let textColorPrimary = localStorage.getItem('--text-color-primary') let textColorPrimary = localStorage.getItem("--text-color-primary");
changeCSS('--background-primary', background) changeCSS("--background-primary", background);
changeCSS('--navbar-color', navbar) changeCSS("--navbar-color", navbar);
changeCSS('--navbar-height', navbarHeight) changeCSS("--navbar-height", navbarHeight);
changeCSS('--navbar-text-color', navbarText) changeCSS("--navbar-text-color", navbarText);
changeCSS('--input-text-color', inputText) changeCSS("--input-text-color", inputText);
changeCSS('--input-placeholder-color', inputPlaceholder) changeCSS("--input-placeholder-color", inputPlaceholder);
changeCSS('--input-background-color', inputBackground) changeCSS("--input-background-color", inputBackground);
changeCSS('--input-border-color', inputBorder) changeCSS("--input-border-color", inputBorder);
changeCSS('--input-border-size', inputBorderSize) changeCSS("--input-border-size", inputBorderSize);
changeCSS('--navbar-link-color', navbarLink) changeCSS("--navbar-link-color", navbarLink);
changeCSS('--navbar-font', navbarFont) changeCSS("--navbar-font", navbarFont);
changeCSS('--navbar-logo-filter', navbarLogoFilter) changeCSS("--navbar-logo-filter", navbarLogoFilter);
changeCSS('--text-color-primary', textColorPrimary) changeCSS("--text-color-primary", textColorPrimary);
} };
function changeCSS (variable, value, saveBool) { function changeCSS(variable, value, saveBool) {
document.documentElement.style.setProperty(variable, value) document.documentElement.style.setProperty(variable, value);
if (saveBool === true) { if (saveBool === true) {
saveCSS(variable, value) saveCSS(variable, value);
} }
} }
function saveCSS (variable, value) { function saveCSS(variable, value) {
localStorage.setItem(variable, value) localStorage.setItem(variable, value);
} }
function resetViews () { function resetViews() {
changeCSS('--background-primary', '#191724', true) changeCSS("--background-primary", "#191724", true);
changeCSS('--navbar-color', '#26233a', true) changeCSS("--navbar-color", "#26233a", true);
changeCSS('--navbar-height', '60px', true) changeCSS("--navbar-height", "60px", true);
changeCSS('--navbar-text-color', 'rgb(121 103 221)', true) changeCSS("--navbar-text-color", "rgb(121 103 221)", true);
changeCSS('--navbar-link-color', '#e0def4', true) changeCSS("--navbar-link-color", "#e0def4", true);
changeCSS('--navbar-font', '"Roboto"', true) changeCSS("--navbar-font", '"Roboto"', true);
changeCSS('--input-text-color', '#e0def4', true) changeCSS("--input-text-color", "#e0def4", true);
changeCSS('--input-placeholder-color', '#6e6a86', true) changeCSS("--input-placeholder-color", "#6e6a86", true);
changeCSS('--input-background-color', '#1f1d2e', true) changeCSS("--input-background-color", "#1f1d2e", true);
changeCSS('--input-placeholder-color', 'white', true) changeCSS("--input-placeholder-color", "white", true);
changeCSS('--input-border-color', '#eb6f92', true) changeCSS("--input-border-color", "#eb6f92", true);
changeCSS('--input-border-size', '1.3px', true) changeCSS("--input-border-size", "1.3px", true);
return 'All views reset' return "All views reset";
} }
function saveIc () { function saveIc() {
console.log('Checked') console.log("Checked");
var notification = ` var notification = `
<div class="notification-container" id="notification-container"> <div class="notification-container" id="notification-container">
<div class="notification notification-success"> <div class="notification notification-success">
<strong>Success!</strong> Your settings have been saved! <strong>Success!</strong> Your settings have been saved!
</div> </div>
</div> </div>
` `;
document.getElementById('notifhere').innerHTML = notification document.getElementById("notifhere").innerHTML = notification;
setTimeout(() => { setTimeout(() => {
var NotificationOBJ = document.getElementById('notifhere') var NotificationOBJ = document.getElementById("notifhere");
}, 2000) }, 2000);
} }
function unsavedChanges () { function unsavedChanges() {
var notification = ` var notification = `
<div class="notification-container" id="notification-container"> <div class="notification-container" id="notification-container">
<div class="notification notification-danger" id="notification-container"> <div class="notification notification-danger" id="notification-container">
<strong>Danger!</strong> You have unsaved changes! <strong>Danger!</strong> You have unsaved changes!
</div> </div>
</div> </div>
` `;
document.getElementById('notifhere').innerHTML = notification document.getElementById("notifhere").innerHTML = notification;
setTimeout(() => { setTimeout(() => {
var NotificationOBJ = document.getElementById('notifhere') var NotificationOBJ = document.getElementById("notifhere");
}, 2000) }, 2000);
} }
var option = localStorage.getItem('nogg') var option = localStorage.getItem("nogg");
function toggleNoGG () { function toggleNoGG() {
if (option === 'on') { if (option === "on") {
option = 'off' option = "off";
localStorage.setItem('nogg', 'off') localStorage.setItem("nogg", "off");
} else { } else {
option = 'on' option = "on";
localStorage.setItem('nogg', 'on') localStorage.setItem("nogg", "on");
} }
} }
var option2 = localStorage.getItem('ADVcloak') var option2 = localStorage.getItem("ADVcloak");
function toggleClickoff () { function toggleClickoff() {
if (option2 === 'on') { if (option2 === "on") {
option2 = 'off' option2 = "off";
localStorage.setItem('ADVcloak', 'off') localStorage.setItem("ADVcloak", "off");
} else { } else {
option2 = 'on' option2 = "on";
localStorage.setItem('ADVcloak', 'on') localStorage.setItem("ADVcloak", "on");
} }
} }

File diff suppressed because one or more lines are too long

View file

@ -1,174 +1,174 @@
@import url("https://fonts.googleapis.com/css2?family=Dongle&family=Roboto:wght@100&display=swap"); @import url("https://fonts.googleapis.com/css2?family=Dongle&family=Roboto:wght@100&display=swap");
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@1,100&display=swap'); @import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@1,100&display=swap");
:root { :root {
--background-primary: #191724; --background-primary: #191724;
--navbar-color: #26233a; --navbar-color: #26233a;
--navbar-height: 60px; --navbar-height: 60px;
--navbar-text-color: #7967dd; --navbar-text-color: #7967dd;
--navbar-link-color: #e0def4; --navbar-link-color: #e0def4;
--navbar-font: "Roboto"; --navbar-font: "Roboto";
--input-text-color: #e0def4; --input-text-color: #e0def4;
--input-placeholder-color: white; --input-placeholder-color: white;
--input-background-color: #1f1d2e; --input-background-color: #1f1d2e;
--input-border-color: #eb6f92; --input-border-color: #eb6f92;
--input-border-size: 1.3px; --input-border-size: 1.3px;
--navbar-logo-filter: none; --navbar-logo-filter: none;
} }
::-webkit-input-placeholder { ::-webkit-input-placeholder {
text-align: center; text-align: center;
font-family: 'Roboto'; font-family: "Roboto";
} }
:-moz-placeholder { :-moz-placeholder {
text-align: center; text-align: center;
} }
#navbar { #navbar {
height: var(--navbar-height); height: var(--navbar-height);
text-align: center; text-align: center;
align-items: center; align-items: center;
display: flex; display: flex;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
background-color: var(--navbar-color); background-color: var(--navbar-color);
} }
.sidenav-btn { .sidenav-btn {
display: none; display: none;
} }
.sidenav { .sidenav {
height: 100%; height: 100%;
width: 0; width: 0;
position: fixed; position: fixed;
z-index: 1; z-index: 1;
top: 0; top: 0;
left: 0; left: 0;
background-color: #232133; background-color: #232133;
padding-top: 60px; padding-top: 60px;
-webkit-transition: 0.5s; -webkit-transition: 0.5s;
transition: 0.5s; transition: 0.5s;
overflow: hidden; overflow: hidden;
} }
.sidenav a { .sidenav a {
padding: 8px 16px 16px 32px; padding: 8px 16px 16px 32px;
text-decoration: none; text-decoration: none;
width: 100vw; width: 100vw;
font-size: 24px; font-size: 24px;
color: #cfcfcf; color: #cfcfcf;
display: block; display: block;
transition: 0.3s; transition: 0.3s;
} }
.sidenav .closebtn { .sidenav .closebtn {
position: absolute; position: absolute;
top: 0; top: 0;
right: 25px; right: 25px;
font-size: 36px; font-size: 36px;
margin-left: 50px; margin-left: 50px;
z-index: 2; z-index: 2;
left: 140px; left: 140px;
} }
@media only screen and (max-width: 690px) { @media only screen and (max-width: 690px) {
/* funny number */ /* funny number */
#navbar>ul>li { #navbar > ul > li {
display: none; display: none;
} }
.sidenav-btn { .sidenav-btn {
display: flex; display: flex;
align-items: center; align-items: center;
position: absolute; position: absolute;
left: 90vw; left: 90vw;
width: var(--navbar-height); width: var(--navbar-height);
height: var(--navbar-height); height: var(--navbar-height);
} }
.sidenav-btn>svg { .sidenav-btn > svg {
width: 50px; width: 50px;
height: 50px; height: 50px;
} }
#digitalCLOContainerLI { #digitalCLOContainerLI {
display: none; display: none;
} }
#navbar>ul>li>a>svg { #navbar > ul > li > a > svg {
min-width: 24px; min-width: 24px;
} }
} }
a { a {
color: var(--navbar-link-color); color: var(--navbar-link-color);
text-decoration: none !important; text-decoration: none !important;
font-family: 'Roboto'; font-family: "Roboto";
} }
a:hover { a:hover {
color: grey; color: grey;
transition: 0.5s; transition: 0.5s;
cursor: pointer; cursor: pointer;
} }
.down { .down {
background-color: rgb(90, 24, 154); background-color: rgb(90, 24, 154);
left: inherit !important; left: inherit !important;
font-family: 'Helvetica'; font-family: "Helvetica";
background-color: var(--navbar-color); background-color: var(--navbar-color);
/* box-shadow: 2px 2px rgb(0 0 0 / 20%); */ /* box-shadow: 2px 2px rgb(0 0 0 / 20%); */
color: white; color: white;
display: none; display: none;
visibility: hidden; visibility: hidden;
opacity: 0; opacity: 0;
list-style-type: none; list-style-type: none;
position: fixed; position: fixed;
border-bottom-right-radius: 10px; border-bottom-right-radius: 10px;
border-bottom-left-radius: 10px; border-bottom-left-radius: 10px;
list-style-type: none; list-style-type: none;
} }
#navbar ul:not(.down) { #navbar ul:not(.down) {
font-family: 'Helvetica'; font-family: "Helvetica";
/* box-shadow: 2px 2px rgb(0 0 0 / 20%); */ /* box-shadow: 2px 2px rgb(0 0 0 / 20%); */
color: white; color: white;
margin-left: auto; margin-left: auto;
list-style-type: none; list-style-type: none;
float: right !important; float: right !important;
margin-right: 2.3%; margin-right: 2.3%;
display: flex; display: flex;
align-items: center; align-items: center;
} }
#navbar ul li { #navbar ul li {
float: left; float: left;
padding-top: 1em; padding-top: 1em;
padding-bottom: 1em; padding-bottom: 1em;
padding-right: 1em; padding-right: 1em;
padding-left: 1em; padding-left: 1em;
padding: 1rem; padding: 1rem;
} }
::placeholder, ::placeholder,
input[type='text'] { input[type="text"] {
color: var(--input-placeholder-color); color: var(--input-placeholder-color);
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;
font-family: 'Roboto'; font-family: "Roboto";
} }
#navbar ul p, #navbar ul p,
ul a { ul a {
font-weight: bold; font-weight: bold;
display: flex; display: flex;
align-items: center; align-items: center;
} }
*/ */
@ -179,328 +179,322 @@ ul a {
*/ */
#navbar ul li ul { #navbar ul li ul {
border-bottom-right-radius: 10px; border-bottom-right-radius: 10px;
border-bottom-left-radius: 10px; border-bottom-left-radius: 10px;
visibility: hidden; visibility: hidden;
opacity: 0; opacity: 0;
margin-top: 1rem; margin-top: 1rem;
left: 0; left: 0;
display: none; display: none;
} }
#navbar ul li:hover ul, #navbar ul li:hover ul,
ul li ul:hover { ul li ul:hover {
visibility: visible; visibility: visible;
opacity: 1; opacity: 1;
display: block; display: block;
} }
#navbar ul li p { #navbar ul li p {
color: white; color: white;
font-family: 'Calibri'; font-family: "Calibri";
z-index: 3 !important; z-index: 3 !important;
} }
#navbar ul li ul li { #navbar ul li ul li {
clear: both; clear: both;
width: 100%; width: 100%;
} }
#content { #content {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 98%; height: 98%;
color: white; color: white;
flex-direction: column; flex-direction: column;
font-family: 'Roboto'; font-family: "Roboto";
} }
#content h1 { #content h1 {
padding-bottom: 0.5em; padding-bottom: 0.5em;
font-weight: 100; font-weight: 100;
text-align: center; text-align: center;
} }
#content img { #content img {
padding-left: .5em; padding-left: 0.5em;
filter: brightness(0) invert(1); filter: brightness(0) invert(1);
} }
#content input { #content input {
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;
font-family: 'Calibri'; font-family: "Calibri";
border-style: solid !important; border-style: solid !important;
border: var(--input-border-size) solid var(--input-border-color); border: var(--input-border-size) solid var(--input-border-color);
border-width: 1px; border-width: 1px;
border-radius: 15px; border-radius: 15px;
background-color: var(--input-background-color); background-color: var(--input-background-color);
color: var(--input-text-color); color: var(--input-text-color);
width: 300px; width: 300px;
height: 50px; height: 50px;
box-shadow: none !important; box-shadow: none !important;
outline: none; outline: none;
text-align: center; text-align: center;
font-family: 'Roboto'; font-family: "Roboto";
} }
#content input:focus { #content input:focus {
outline: none; outline: none;
box-shadow: none !important; box-shadow: none !important;
} }
@keyframes inputwide { @keyframes inputwide {
0% { 0% {
width: 0px; width: 0px;
transition-duration: 0.5s; transition-duration: 0.5s;
} }
100% { 100% {
width: 300px; width: 300px;
transition-duration: 0.5s; transition-duration: 0.5s;
} }
} }
.loader { .loader {
width: 283px; width: 283px;
text-align: center; text-align: center;
display: none; display: none;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
flex-direction: row; flex-direction: row;
transition: .1s; transition: 0.1s;
} }
svg path, svg path,
svg rect { svg rect {
fill: #eb6f92; fill: #eb6f92;
} }
.connector { .connector {
color: white; color: white;
margin-left: 10px; margin-left: 10px;
font-size: 15px; font-size: 15px;
} }
@keyframes popout { @keyframes popout {
0% { 0% {
height: -20px; height: -20px;
} }
100% { 100% {
height: 0px; height: 0px;
} }
} }
.nebHeader { .nebHeader {
font-family: var(--navbar-font); font-family: var(--navbar-font);
color: var(--navbar-text-color); color: var(--navbar-text-color);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
align-content: center; align-content: center;
flex-wrap: nowrap; flex-wrap: nowrap;
flex-direction: row; flex-direction: row;
margin-left: .5%; margin-left: 0.5%;
} }
html, html,
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
height: 100%; height: 100%;
} }
body { body {
background-color: var(--background-primary); background-color: var(--background-primary);
color: var(--text-color-primary); color: var(--text-color-primary);
animation: fadeInAnimation ease 1s; animation: fadeInAnimation ease 1s;
animation-iteration-count: 1; animation-iteration-count: 1;
animation-fill-mode: forwards; animation-fill-mode: forwards;
} }
@keyframes fadeInAnimation { @keyframes fadeInAnimation {
0% { 0% {
opacity: 0; opacity: 0;
} }
100% { 100% {
opacity: 1; opacity: 1;
} }
} }
input:focus::placeholder { input:focus::placeholder {
color: transparent; color: transparent;
} }
#navbar #thumbImg { #navbar #thumbImg {
transition: width 2s, height 2s, transform 2s; transition: width 2s, height 2s, transform 2s;
filter: var(--navbar-logo-filter); filter: var(--navbar-logo-filter);
} }
#navbar #thumbImg:hover { #navbar #thumbImg:hover {
transform: rotate(360deg); transform: rotate(360deg);
} }
.stamp { .stamp {
text-align: right; text-align: right;
position: fixed; position: fixed;
bottom: 0; bottom: 0;
font-family: 'Montserrat', sans-serif; font-family: "Montserrat", sans-serif;
font-style: italic; font-style: italic;
font-weight: lighter; font-weight: lighter;
color: whitesmoke; color: whitesmoke;
opacity: 90%; opacity: 90%;
user-select: none; user-select: none;
font-size: 13px; font-size: 13px;
padding-left: 5px; padding-left: 5px;
padding-bottom: 1px; padding-bottom: 1px;
cursor: default; cursor: default;
} }
.stamp:hover { .stamp:hover {
text-align: right; text-align: right;
position: fixed; position: fixed;
bottom: 0; bottom: 0;
font-family: 'Montserrat', sans-serif; font-family: "Montserrat", sans-serif;
font-style: italic; font-style: italic;
font-weight: lighter; font-weight: lighter;
color: whitesmoke; color: whitesmoke;
opacity: 38%; opacity: 38%;
user-select: none; user-select: none;
font-size: 13px; font-size: 13px;
padding-left: 5px; padding-left: 5px;
padding-bottom: 1px; padding-bottom: 1px;
cursor: default; cursor: default;
} }
.github { .github {
position: fixed; position: fixed;
right: 0; right: 0;
bottom: 0; bottom: 0;
padding-right: 10px; padding-right: 10px;
} }
.tos { .tos {
position: fixed; position: fixed;
right: 67px; right: 67px;
bottom: 0; bottom: 0;
padding-right: 15px; padding-right: 15px;
} }
.privacy { .privacy {
position: fixed; position: fixed;
right: 114px; right: 114px;
bottom: 0; bottom: 0;
padding-right: 15px; padding-right: 15px;
} }
.modal-window { .modal-window {
position: fixed; position: fixed;
background-color: rgba(255, 255, 255, 0.25); background-color: rgba(255, 255, 255, 0.25);
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: 999; z-index: 999;
visibility: hidden; visibility: hidden;
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
transition: all 0.3s; transition: all 0.3s;
font-family: 'Montserrat', sans-serif; font-family: "Montserrat", sans-serif;
;
} }
.modal-window:target { .modal-window:target {
visibility: visible; visibility: visible;
opacity: 1; opacity: 1;
pointer-events: auto; pointer-events: auto;
} }
.modal-window>div { .modal-window > div {
width: 400px; width: 400px;
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
padding: 2em; padding: 2em;
background: white; background: white;
} }
.modal-window header { .modal-window header {
font-weight: bold; font-weight: bold;
} }
.modal-window h1 { .modal-window h1 {
font-size: 150%; font-size: 150%;
margin: 0 0 15px; margin: 0 0 15px;
} }
.modal-close { .modal-close {
color: #aaa; color: #aaa;
line-height: 50px; line-height: 50px;
font-size: 80%; font-size: 80%;
position: absolute; position: absolute;
right: 0; right: 0;
text-align: center; text-align: center;
top: 0; top: 0;
width: 70px; width: 70px;
text-decoration: none; text-decoration: none;
} }
.modal-close:hover { .modal-close:hover {
color: black; color: black;
} }
.modal-window > div {
.modal-window>div { border-radius: 1rem;
border-radius: 1rem;
} }
.modal-window div:not(:last-of-type) { .modal-window div:not(:last-of-type) {
margin-bottom: 15px; margin-bottom: 15px;
} }
.logo { .logo {
max-width: 150px; max-width: 150px;
display: block; display: block;
} }
small { small {
color: lightgray; color: lightgray;
} }
.btn { .btn {
background-color: white; background-color: white;
padding: 1em 1.5em; padding: 1em 1.5em;
border-radius: 0.5rem; border-radius: 0.5rem;
text-decoration: none; text-decoration: none;
} }
.btn i { .btn i {
padding-right: 0.3em; padding-right: 0.3em;
} }
@media only screen and (max-width: 1100px) { @media only screen and (max-width: 1100px) {
#digitalClock { #digitalClock {
display: none; display: none;
} }
} }
.clockColon { .clockColon {
opacity: 100%; opacity: 100%;
animation: blink .5s step-end infinite alternate;
transition: 0.2s;
animation: blink 0.5s step-end infinite alternate;
transition: 0.2s;
} }
@keyframes blink { @keyframes blink {
50% { 50% {
opacity: 0% opacity: 0%;
} }
} }

View file

@ -1,10 +1,12 @@
importScripts('./uv/uv.sw.js'); importScripts("./uv/uv.sw.js");
importScripts('./osana/osana.worker.js'); importScripts("./osana/osana.worker.js");
const UV = new UVServiceWorker(); const UV = new UVServiceWorker();
const Osana = new OsanaServiceWorker(); const Osana = new OsanaServiceWorker();
self.addEventListener('fetch', (event) => { self.addEventListener("fetch", (event) => {
if (event.request.url.startsWith(location.origin + '/service/go/')) event.respondWith(UV.fetch(event)); if (event.request.url.startsWith(location.origin + "/service/go/"))
if (event.request.url.startsWith(location.origin + '/service/~osana/')) event.respondWith(Osana.fetch(event)); event.respondWith(UV.fetch(event));
}); if (event.request.url.startsWith(location.origin + "/service/~osana/"))
event.respondWith(Osana.fetch(event));
});

View file

@ -1,87 +1,138 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap" rel="stylesheet"> <link
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@1,700&display=swap" rel="stylesheet"> href="https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap"
</head> rel="stylesheet"
<body style="background: #26233a;"> />
<div style="display: flex; <link
align-items: center; href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@1,700&display=swap"
justify-content: center; rel="stylesheet"
flex-wrap: nowrap; />
flex-direction: row;"> </head>
<button id='send-code' style=" <body style="background: #26233a">
background: #eb6f92; <div
border-radius: 3px; style="
border: transparent; display: flex;
width: 268px; align-items: center;
font-size: 18px; justify-content: center;
height: 69px; flex-wrap: nowrap;
cursor: pointer; flex-direction: row;
font-family: 'Roboto', sans-serif; "
" > Send Verification Code </button> >
<svg style=" <button
color: white; id="send-code"
font-size: 10px; style="
width: 53px; background: #eb6f92;
" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> border-radius: 3px;
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75" /> border: transparent;
</svg> width: 268px;
<input id='codeBox' type="text" placeholder='Enter the code sent to your email' style="width: 268px; font-size: 18px;
font-size: 18px; height: 69px;
height: 69px; cursor: pointer;
background: #1f1d2e; font-family: 'Roboto', sans-serif;
border-color: #eb6f92; "
border-width: 1px; >
color: white; Send Verification Code
font-style: italic; </button>
border-radius: 6px; <svg
text-align: center;"> style="color: white; font-size: 10px; width: 53px"
<svg style=" xmlns="http://www.w3.org/2000/svg"
color: white; fill="none"
font-size: 10px; viewBox="0 0 24 24"
width: 53px;" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> stroke-width="1.5"
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75" /> stroke="currentColor"
</svg> class="w-6 h-6"
<button id="checkCode" style=" >
background: #eb6f92; <path
border-radius: 3px; stroke-linecap="round"
border: transparent; stroke-linejoin="round"
width: 268px; d="M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75"
font-size: 18px; />
height: 69px; </svg>
cursor: pointer; <input
font-family: 'Roboto', sans-serif; id="codeBox"
"> Submit </button> type="text"
</div> placeholder="Enter the code sent to your email"
<br> style="
<div style=" width: 268px;
display: flex; font-size: 18px;
align-items: center; height: 69px;
justify-content: center; background: #1f1d2e;
align-content: center; border-color: #eb6f92;
flex-wrap: nowrap; border-width: 1px;
flex-direction: row; color: white;
color: white; font-style: italic;
font-family: 'Roboto', sans-serif; border-radius: 6px;
"> text-align: center;
<p id='checked'></p> "
</div> />
<hr> <svg
<div style=" style="color: white; font-size: 10px; width: 53px"
display: flex; xmlns="http://www.w3.org/2000/svg"
align-items: center; fill="none"
justify-content: center; viewBox="0 0 24 24"
align-content: center; stroke-width="1.5"
flex-wrap: nowrap; stroke="currentColor"
flex-direction: row; class="w-6 h-6"
color: white; >
font-family: 'Roboto', sans-serif; <path
"> stroke-linecap="round"
<p id='checked'>You are seeing this screen because the owner of this website has set this site to require email one time password upon entry.</p> stroke-linejoin="round"
</div> d="M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75"
<script src="resources/v.js"></script> />
</body> </svg>
</html> <button
id="checkCode"
style="
background: #eb6f92;
border-radius: 3px;
border: transparent;
width: 268px;
font-size: 18px;
height: 69px;
cursor: pointer;
font-family: 'Roboto', sans-serif;
"
>
Submit
</button>
</div>
<br />
<div
style="
display: flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: nowrap;
flex-direction: row;
color: white;
font-family: 'Roboto', sans-serif;
"
>
<p id="checked"></p>
</div>
<hr />
<div
style="
display: flex;
align-items: center;
justify-content: center;
align-content: center;
flex-wrap: nowrap;
flex-direction: row;
color: white;
font-family: 'Roboto', sans-serif;
"
>
<p id="checked">
You are seeing this screen because the owner of this website has set
this site to require email one time password upon entry.
</p>
</div>
<script src="resources/v.js"></script>
</body>
</html>

View file

@ -1 +1 @@
{"version":"7.10"} { "version": "7.11.6" }