Several major changes: Added verification system, better loading screen, added documentation, optimizations, cleanups, etc, and finally fixed Markdown.

This commit is contained in:
Green! 2022-11-14 04:16:59 +00:00
parent bf0c2fb307
commit 38dde4ed38
16 changed files with 4311 additions and 4567 deletions

3
.breakpoints Normal file
View file

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

View file

@ -2,50 +2,31 @@
<div align=center>
<img src='https://nebulaproxy.nebula.bio/images/logo.png' width="100px" height="100px">
<h1> Nebula </h1>
Nebula Web is an official flagship of Nebula Services. Nebula Web is a stunning and sleak webproxy with support for hundreds of popular sites, and partial support for WebRTC, used in GfN. With Nebula Web, the sky is the limit. Enjoy.
NebulaWeb is an official flagship of Nebula Services and Nebula Developer Labs. NebulaWeb is a stunning, sleak, and functional web-proxy with support for thousands of popular sites. With NebulaWeb, the sky is the limit.
</div>
## Features
- Stunning UI with multiple themes
- Stunning highly functional UI with multiple themes
- XOR/b64 Encrypts all traffic sent from Nebula
- Hides your IP from sites
- [List of officially supported sites](https://github.com/NebulaServices/Nebula/blob/main/docs/officially-supported-sites.md)
- *limited* mobile support
- StealthMode (buffed `about:blank` cloaking)
- Advanced cloaking options
- **NEW** Deployment option - Email OTP Verification (tutorial can be found below)
### Self Hosting
```bash
$ git clone https://github.com/NebulaServices/Nebula.git
$ cd Nebula
$ npm ci
$ npm start
```
## Tech Stack
- HTML, JS, CSS
- Partical.JS
- UV Backend Proxy
- Osana Backend Proxy
- **Server:** Bare server on Node
## Support
For support, email chloe@nebula.bio or join our discord: discord.nebula.bio
## Demo
[Click here to see a demo of Nebula](https://tutorialread.beauty/)
# Deployment
## Quick Deployment Options
Table of contents
- Quick & easy deployment
- how to use email OTP Verification mode
- Advanced Deployment
## 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)
<br>
[![Run on Replit](https://raw.githubusercontent.com/BinBashBanana/deploy-buttons/master/buttons/remade/replit.svg)](https://replit.com/github/NebulaServices/Nebula)
@ -63,6 +44,13 @@ For support, email chloe@nebula.bio or join our discord: discord.nebula.bio
[![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)
---
## how to use email OTP Verification mode
* change `"verification":false,` to `"verification":true,`
* Make an account with Sendgrid (https://app.sendgrid.com/)
* verify email
* get API key
* fill out information in `deployment.config.json`
## Advanced Deployment
### Initial configuration
@ -112,6 +100,25 @@ sudo nohup PORT=80 node . &
*Note: Server will need to run` cd Nebula && sudo nohup PORT=80 node . &` on reboot*
(Nebula's license is now GNU AGPL V3 as of v7.10)
## Tech Stack
- HTML, JS, CSS
- Partical.JS
- UV Backend Proxy
- Osana Backend Proxy
- **Server:** Bare server on Node
## Support
For support, email chloe@nebula.bio or join our discord: discord.nebula.bio
## Demo
[Click here to see a demo of Nebula](https://tutorialread.beauty/)
## Acknowledgements
- [UV (one of the back-end proxy we use)](https://github.com/titaniumnetwork-dev/Ultraviolet)

148
app.js
View file

@ -1,54 +1,142 @@
import createBareServer from '@tomphttp/bare-server-node';
import http from 'http';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import serveStatic from 'serve-static';
import createBareServer from "@tomphttp/bare-server-node"
import http from "http"
import { fileURLToPath } from "url"
import { dirname, join } from "path"
import serveStatic from "serve-static"
import { createRequire } from "module"
const require = createRequire(import.meta.url)
const config = require("./deployment.config.json")
import fs from "fs"
var base64data
import sgTransport from "nodemailer-sendgrid-transport"
import nodemailer from "nodemailer"
const options = {
auth: {
api_key: config.api_key,
},
}
const mailerAgent = nodemailer.createTransport(sgTransport(options))
function sendVerificationEmail(UUID, mailTo, OTP) {
const email = {
to: mailTo,
from: `${config.sendFromEmail}`,
subject: `NebulaWEB personal access code ${OTP}`,
text: `
####### ACCESS CODE (OTP) ${OTP} #######
####### DO NOT SHARE THIS CODE! #######
(this message is automated)`,
html: `
####### ACCESS CODE (OTP) ${OTP} #######
####### DO NOT SHARE THIS CODE! #######
(this message is automated)
`,
}
if (config.verification == true) {
mailerAgent.sendMail(email, (err, res) => {
if (err) {
console.log(err)
}
console.log(res)
})
}
}
const PORT = process.env.PORT || 3000;
const bareServer = createBareServer('/bare/', {
function getNewCode() {
var seq = (Math.floor(Math.random() * 10000) + 10000).toString().substring(1)
if (seq == "0") {
getNewCode()
}
return seq
}
const PORT = process.env.PORT || 3000
const bareServer = createBareServer("/bare/", {
logErrors: false,
localAddress: undefined
});
localAddress: undefined,
})
const serve = serveStatic(join(
dirname(fileURLToPath(import.meta.url)),
'static/'
), {
const serve = serveStatic(
join(dirname(fileURLToPath(import.meta.url)), "static/"),
{
fallthrough: false,
maxAge: 5 * 60 * 1000
});
maxAge: 5 * 60 * 1000,
}
)
const server = http.createServer();
const server = http.createServer()
server.on('request', (request, response) => {
server.on("request", (request, response) => {
try {
if (bareServer.shouldRoute(request)) {
bareServer.routeRequest(request, response);
bareServer.routeRequest(request, response)
} else {
serve(request, response, err => {
let base64data
const url = request.url
if (url.startsWith("/sendNewCode")) {
const OTP = getNewCode()
fs.writeFile("./memory.txt", OTP, function (err) {
if (err) return console.log(err)
console.log(`Wrote OTP code to temp file`)
})
fs.readFile("./memory.txt", "utf8", (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data)
sendVerificationEmail("10", config.email, data)
let buff = new Buffer(data)
base64data = buff.toString("base64")
console.log("302")
response.writeHead(302, {
location: "/unv.html?c=" + base64data,
})
response.end()
})
} else if (url.startsWith("/verification")) {
var body
if (config.verification == true) {
const body = "true"
response.writeHead(200, {
"Content-Length": Buffer.byteLength(body),
"Content-Type": "text/plain",
})
response.end(body)
} else {
const body = "false"
response.writeHead(200, {
"Content-Length": Buffer.byteLength(body),
"Content-Type": "text/plain",
})
response.end(body)
}
} else {
serve(request, response, (err) => {
response.writeHead(err?.statusCode || 500, null, {
"Content-Type": "text/plain"
"Content-Type": "text/plain",
})
response.end(err?.stack)
});
})
}
}
} catch (e) {
response.writeHead(500, "Internal Server Error", {
"Content-Type": "text/plain"
"Content-Type": "text/plain",
})
response.end(e.stack)
}
});
server.on('upgrade', (req, socket, head) => {
})
server.on("upgrade", (req, socket, head) => {
if (bareServer.shouldRoute(req)) {
bareServer.routeUpgrade(req, socket, head);
bareServer.routeUpgrade(req, socket, head)
} else {
socket.end();
socket.end()
}
});
})
server.listen(PORT);
server.listen(PORT)
if (process.env.UNSAFE_CONTINUE)
process.on("uncaughtException", (err, origin) => {
@ -58,4 +146,4 @@ if (process.env.UNSAFE_CONTINUE)
console.error()
})
console.log(`Server running at http://localhost:${PORT}/.`);
console.log(`Server running at http://localhost:${PORT}/.`)

7
deployment.config.json Normal file
View file

@ -0,0 +1,7 @@
{
"verification": false,
"api_key":"YOUR_SENDGRID_API_KEY",
"sendFromEmail":"THE EMAIL THE CODES WILL BE SENT FROM (MUST BE VERIFIED IN SENDGRID)",
"type": "code",
"email": "YOUR_EMAIL_HERE"
}

1
memory.txt Normal file
View file

@ -0,0 +1 @@
5003

2472
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,8 @@
"crypto-js": "4.1.1",
"css-tree": "^2.1.0",
"node-fetch": "^3.2.6",
"nodemailer": "^6.8.0",
"nodemailer-sendgrid-transport": "^0.2.0",
"serve-static": "^1.15.0",
"ws": "^8.8.1"
},

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

12
static/resources/v.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,6 @@
@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');
:root {
--background-primary: #191724;
--navbar-color: #26233a;
@ -15,12 +16,12 @@
--navbar-logo-filter: none;
}
::-webkit-input-placeholder {
::-webkit-input-placeholder {
text-align: center;
font-family: 'Roboto';
}
:-moz-placeholder {
:-moz-placeholder {
text-align: center;
}
@ -35,9 +36,11 @@
right: 0;
background-color: var(--navbar-color);
}
.sidenav-btn {
display: none;
}
.sidenav {
height: 100%;
width: 0;
@ -72,9 +75,10 @@
left: 140px;
}
@media only screen and (max-width: 690px) { /* funny number */
@media only screen and (max-width: 690px) {
/* funny number */
#navbar > ul > li {
#navbar>ul>li {
display: none;
}
@ -87,7 +91,8 @@
width: var(--navbar-height);
height: var(--navbar-height);
}
.sidenav-btn > svg {
.sidenav-btn>svg {
width: 50px;
height: 50px;
}
@ -95,7 +100,8 @@
#digitalCLOContainerLI {
display: none;
}
#navbar > ul > li > a > svg {
#navbar>ul>li>a>svg {
min-width: 24px;
}
}
@ -150,7 +156,7 @@ a:hover {
padding: 1rem;
}
::placeholder,
::placeholder,
input[type='text'] {
color: var(--input-placeholder-color);
font-size: 20px;
@ -250,6 +256,7 @@ ul li ul:hover {
width: 0px;
transition-duration: 0.5s;
}
100% {
width: 300px;
transition-duration: 0.5s;
@ -281,6 +288,7 @@ svg rect {
0% {
height: -20px;
}
100% {
height: 0px;
}
@ -318,6 +326,7 @@ body {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
@ -352,6 +361,7 @@ input:focus::placeholder {
cursor: default;
}
.stamp:hover {
text-align: right;
position: fixed;
@ -388,6 +398,7 @@ input:focus::placeholder {
bottom: 0;
padding-right: 15px;
}
.modal-window {
position: fixed;
background-color: rgba(255, 255, 255, 0.25);
@ -400,14 +411,17 @@ input:focus::placeholder {
opacity: 0;
pointer-events: none;
transition: all 0.3s;
font-family: 'Montserrat', sans-serif;;
font-family: 'Montserrat', sans-serif;
;
}
.modal-window:target {
visibility: visible;
opacity: 1;
pointer-events: auto;
}
.modal-window > div {
.modal-window>div {
width: 400px;
position: absolute;
top: 50%;
@ -416,9 +430,11 @@ font-family: 'Montserrat', sans-serif;;
padding: 2em;
background: white;
}
.modal-window header {
font-weight: bold;
}
.modal-window h1 {
font-size: 150%;
margin: 0 0 15px;
@ -435,13 +451,13 @@ font-family: 'Montserrat', sans-serif;;
width: 70px;
text-decoration: none;
}
.modal-close:hover {
color: black;
}
.modal-window > div {
.modal-window>div {
border-radius: 1rem;
}
@ -464,6 +480,7 @@ small {
border-radius: 0.5rem;
text-decoration: none;
}
.btn i {
padding-right: 0.3em;
}
@ -481,6 +498,7 @@ small {
transition: 0.2s;
}
@keyframes blink {
50% {
opacity: 0%

View file

@ -1,4 +1,5 @@
@import url("https://fonts.googleapis.com/css2?family=Work+Sans:wght@300&display=swap");
:root {
--background-primary: #191724;
--sidebar-color: #191724;
@ -127,6 +128,7 @@ li {
}
@import url('https://fonts.googleapis.com/css2?family=Mulish:wght@300&display=swap');
.toogle-button {
font-weight: bold;
font-size: 10PX;
@ -186,6 +188,7 @@ ul li {
0% {
opacity: 0.01;
}
100% {
opacity: 1;
}
@ -195,12 +198,14 @@ ul li {
0% {
opacity: 0.01;
}
100% {
opacity: 1;
}
}
@import url('https://fonts.googleapis.com/css?family=Roboto:400,500&display=swap');
.notification-container {
position: fixed;
top: 4px;
@ -227,6 +232,7 @@ ul li {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
@ -300,6 +306,7 @@ ul li {
}
@import url('https://fonts.googleapis.com/css2?family=Ubuntu:wght@300&display=swap');
.settings-cont {
background: #45454521;
box-sizing: border-box;
@ -336,6 +343,7 @@ ul li {
}
@import url('https://fonts.googleapis.com/css2?family=Oxygen:wght@700&display=swap');
.new-tag {
font-size: 16px;
color: rgb(226, 68, 68);
@ -434,6 +442,7 @@ ul li {
}
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap');
.expiramental {
font-family: 'Roboto', sans-serif;
font-size: 10px;
@ -453,7 +462,7 @@ label {
/* text-indent: -10049px; */
width: 85px;
height: 37px;
background:#504e58;
background: #504e58;
display: block;
border-radius: 100px;
position: relative;

87
static/unv.html Normal file
View file

@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="preconnect" href="https://fonts.googleapis.com">
<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 href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@1,700&display=swap" rel="stylesheet">
</head>
<body style="background: #26233a;">
<div style="display: flex;
align-items: center;
justify-content: center;
flex-wrap: nowrap;
flex-direction: row;">
<button id='send-code' style="
background: #eb6f92;
border-radius: 3px;
border: transparent;
width: 268px;
font-size: 18px;
height: 69px;
cursor: pointer;
font-family: 'Roboto', sans-serif;
" > Send Verification Code </button>
<svg style="
color: white;
font-size: 10px;
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">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75" />
</svg>
<input id='codeBox' type="text" placeholder='Enter the code sent to your email' style="width: 268px;
font-size: 18px;
height: 69px;
background: #1f1d2e;
border-color: #eb6f92;
border-width: 1px;
color: white;
font-style: italic;
border-radius: 6px;
text-align: center;">
<svg style="
color: white;
font-size: 10px;
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">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12h15m0 0l-6.75-6.75M19.5 12l-6.75 6.75" />
</svg>
<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>