mirror of
https://github.com/NebulaServices/Nebula.git
synced 2025-05-17 13:30:00 -04:00
Refactor & implement verification
This commit is contained in:
parent
ec2807105a
commit
326d59bff2
20 changed files with 1348 additions and 69 deletions
208
app.js
208
app.js
|
@ -5,42 +5,195 @@ import createBareServer from "@tomphttp/bare-server-node";
|
|||
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
|
||||
import path from "node:path";
|
||||
import config from "./deployment.config.json" assert { type: "json" };
|
||||
import sgMail from "@sendgrid/mail";
|
||||
import nodemailer from "nodemailer";
|
||||
import * as uuid from "uuid";
|
||||
import fs from "node:fs";
|
||||
import bcrypt from "bcrypt";
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
const __dirname = process.cwd();
|
||||
const ACTIVE_CODES = new Set();
|
||||
let TOKENS = fs
|
||||
.readFileSync("./memory.txt", "utf-8")
|
||||
.trim()
|
||||
.split("\n")
|
||||
.map((token) => {
|
||||
const parts = token.split(":");
|
||||
return {
|
||||
id: parts[0],
|
||||
token: parts[1],
|
||||
expiration: parts[2]
|
||||
};
|
||||
});
|
||||
|
||||
const server = http.createServer();
|
||||
const app = express(server);
|
||||
const bareServer = createBareServer("/bare/");
|
||||
|
||||
// Static files
|
||||
// Middleware
|
||||
app.use(cookieParser());
|
||||
app.use(express.json());
|
||||
app.use(
|
||||
express.urlencoded({
|
||||
extended: true
|
||||
})
|
||||
);
|
||||
|
||||
app.patch("/generate-otp", (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
app.post("/validate-otp", (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
app.all("/", (req, res, next) => {
|
||||
console.log(req.url);
|
||||
// validate verification
|
||||
// Verification
|
||||
app.patch("/generate-otp", async (req, res) => {
|
||||
if (
|
||||
config.sendgrid_verification == true ||
|
||||
config.discord_verification == true ||
|
||||
config.smtp_verificaton == true
|
||||
) {
|
||||
if (!req.cookies["verification"]) {
|
||||
res.redirect("/unv.html");
|
||||
} else {
|
||||
next();
|
||||
const OTP = generateCode();
|
||||
ACTIVE_CODES.add(OTP);
|
||||
|
||||
setTimeout(() => {
|
||||
ACTIVE_CODES.delete(OTP);
|
||||
}, 1000 * 60 * 5);
|
||||
|
||||
let email = {
|
||||
to: "",
|
||||
from: "",
|
||||
subject: `NebulaWEB personal access code ${OTP}`,
|
||||
text: `
|
||||
####### ACCESS CODE (OTP) ${OTP} #######
|
||||
####### DO NOT SHARE THIS CODE! #######
|
||||
(this message is automated)`
|
||||
};
|
||||
|
||||
if (config.sendgrid_verification == true) {
|
||||
sgMail.setApiKey(config.sendgrid_options.api_key);
|
||||
|
||||
email.to = config.sendgrid_options.to_email;
|
||||
email.from = config.sendgrid_options.sendFromEmail;
|
||||
try {
|
||||
await sgMail.send(msg);
|
||||
} catch {
|
||||
return res.status(504).end();
|
||||
}
|
||||
}
|
||||
|
||||
if (config.smtp_verification == true) {
|
||||
const smtpMailerAgent = nodemailer.createTransport(config.smtp_options);
|
||||
|
||||
email.to = config.smtp_options.to_email;
|
||||
email.from = config.smtp_options.sendFromEmail;
|
||||
try {
|
||||
smtpMailerAgent.sendMail(email);
|
||||
} catch {
|
||||
return res.status(504).end();
|
||||
}
|
||||
}
|
||||
|
||||
if (config.discord_verification == true) {
|
||||
try {
|
||||
await fetch(config.webhook_url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
content: `Your NebulaWEB access code is \`${OTP}\``
|
||||
})
|
||||
});
|
||||
} catch {
|
||||
return res.status(500).end();
|
||||
}
|
||||
}
|
||||
|
||||
res.status(200).end();
|
||||
} else {
|
||||
res.status(404).end();
|
||||
}
|
||||
});
|
||||
|
||||
function generateCode() {
|
||||
const code = Math.floor(Math.random() * 1000000);
|
||||
return code.toString().padStart(6, "0");
|
||||
}
|
||||
|
||||
app.post("/validate-otp", (req, res) => {
|
||||
if (
|
||||
config.sendgrid_verification == true ||
|
||||
config.discord_verification == true ||
|
||||
config.smtp_verificaton == true
|
||||
) {
|
||||
const OTP = req.body.otp;
|
||||
|
||||
if (ACTIVE_CODES.has(OTP)) {
|
||||
ACTIVE_CODES.delete(OTP);
|
||||
|
||||
const token = uuid.v4();
|
||||
|
||||
TOKENS.push({
|
||||
id: OTP,
|
||||
token: hash(token),
|
||||
expiration: Date.now() + 1000 * 60 * 60 * 24 * 30
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
"./memory.txt",
|
||||
TOKENS.map((token) => {
|
||||
return `${token.id}:${token.token}:${token.expiration}`;
|
||||
}).join("\n"),
|
||||
"utf-8"
|
||||
);
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
validation: `${OTP}:${token}`
|
||||
});
|
||||
} else {
|
||||
res.status(401).json({
|
||||
success: false
|
||||
});
|
||||
}
|
||||
} else {
|
||||
res.status(404).end();
|
||||
}
|
||||
});
|
||||
|
||||
// Static files
|
||||
app.use("/uv/", express.static(uvPath));
|
||||
app.use(express.static(path.join(__dirname, "static")));
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
|
||||
// Login route
|
||||
app.get("/login", (req, res) => {
|
||||
if (
|
||||
config.sendgrid_verification == true ||
|
||||
config.discord_verification == true ||
|
||||
config.smtp_verificaton == true
|
||||
) {
|
||||
res.sendFile(path.join(__dirname, "src", "unv.html"));
|
||||
} else {
|
||||
res.redirect("/");
|
||||
}
|
||||
});
|
||||
|
||||
// General Routes
|
||||
app.use((req, res, next) => {
|
||||
const verification = req.cookies["validation"];
|
||||
if (!verification || !validateToken(verification)) {
|
||||
res.redirect("/login");
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
app.get("/", (req, res) => {
|
||||
res.sendFile(path.join(__dirname, "src", "index.html"));
|
||||
});
|
||||
|
||||
app.get("/options", (req, res) => {
|
||||
res.sendFile(path.join(__dirname, "src", "options.html"));
|
||||
});
|
||||
|
||||
app.get("/privacy", (req, res) => {
|
||||
res.sendFile(path.join(__dirname, "src", "privacy.html"));
|
||||
});
|
||||
|
||||
// Bare Server
|
||||
server.on("request", (req, res) => {
|
||||
|
@ -66,3 +219,24 @@ server.on("listening", () => {
|
|||
server.listen({
|
||||
port: PORT
|
||||
});
|
||||
|
||||
function hash(token) {
|
||||
const salt = bcrypt.genSaltSync(10);
|
||||
return bcrypt.hashSync(token, salt);
|
||||
}
|
||||
|
||||
function validateToken(verification) {
|
||||
console.log(verification);
|
||||
const [id, token] = verification.split(":");
|
||||
const tokenData = TOKENS.find((token) => token.id == id);
|
||||
|
||||
if (!tokenData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tokenData.expiration < Date.now()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bcrypt.compareSync(token, tokenData.token);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
},
|
||||
|
||||
"discord_verification": true,
|
||||
"webhook_url": "YOUR DISCORD WEBHOOK URL",
|
||||
"webhook_url": "https://discord.com/api/webhooks/1072301556461998172/rsMxTsD5AvGFqLoVRt_mmMcVFWJ9xQDLuiy_FsbWapHoYTamL9tsURZO-4j7P1OT4n0Z",
|
||||
|
||||
"smtp_verification": false,
|
||||
"smtp_options": {
|
||||
|
|
1152
package-lock.json
generated
1152
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -13,14 +13,17 @@
|
|||
"author": "Nebula Services",
|
||||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"@sendgrid/mail": "^7.7.0",
|
||||
"@titaniumnetwork-dev/ultraviolet": "^1.0.8-beta",
|
||||
"@tomphttp/bare-server-node": "^1.2.2",
|
||||
"bcrypt": "^5.1.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"express": "^4.18.2",
|
||||
"node-fetch": "^3.3.0",
|
||||
"nodemailer": "^6.8.0",
|
||||
"nodemailer-sendgrid-transport": "^0.2.0",
|
||||
"serve-static": "^1.15.0"
|
||||
"serve-static": "^1.15.0",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
@ -310,42 +310,6 @@ if (storedSetTheme == null) {
|
|||
}
|
||||
|
||||
window.onload = function () {
|
||||
function setCookie(cname, cvalue, exdays) {
|
||||
const d = new Date();
|
||||
d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
|
||||
let expires = "expires=" + d.toUTCString();
|
||||
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
|
||||
}
|
||||
|
||||
function getCookie(cname) {
|
||||
let name = cname + "=";
|
||||
let decodedCookie = decodeURIComponent(document.cookie);
|
||||
let ca = decodedCookie.split(";");
|
||||
for (let i = 0; i < ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) == " ") {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
function httpGet(theUrl) {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open("GET", theUrl, false); // false for synchronous request
|
||||
xmlHttp.send(null);
|
||||
return xmlHttp.responseText;
|
||||
}
|
||||
if (httpGet("/verification") == "true") {
|
||||
if (getCookie("verifiedAccess") == "") {
|
||||
console.log("COOKIE NOT FOUND - ENTRY NOT PERMITTED");
|
||||
window.location = "/unv.html";
|
||||
} else {
|
||||
console.log("COOKIE RECOGNIZED - ENTRY PERMITTED ");
|
||||
}
|
||||
}
|
||||
let background = localStorage.getItem("--background-primary");
|
||||
let navbar = localStorage.getItem("--navbar-color");
|
||||
let navbarHeight = localStorage.getItem("--navbar-height");
|
|
@ -19,7 +19,8 @@ validateOTP.onclick = () => {
|
|||
return response.json();
|
||||
}).then((data) => {
|
||||
if (data.success) {
|
||||
|
||||
setCookie("validation", data.validation, 30);
|
||||
location.href = "/";
|
||||
} else {
|
||||
alert("Invalid OTP.");
|
||||
}
|
||||
|
@ -27,3 +28,14 @@ validateOTP.onclick = () => {
|
|||
alert("An error occurred while validating your OTP.")
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
function setCookie(name, value, days) {
|
||||
var expires = "";
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
|
||||
expires = "; expires=" + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue