Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge #9

Merged
merged 17 commits into from
Jul 13, 2024
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 v182
Copyright (c) 2024 redo

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
16 changes: 6 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
<p align="center"><a href="https://github.com/v182/nero"><img src="https://media.discordapp.net/attachments/984837636457918465/1000014634012647464/giphy.gif" alt="Gray shape shifter" height="120"/></a></p>
<h1 align="center">Nero</h1>
<p align="center">Modern & up to date Pterodactyl Client Dashboard</p>





<p align="center"><a href="https://github.com/v182/nero"></a><a href="#nastyox"><img src="http://randojs.com/images/dropShadow.png" width="75%"/></a></p><br/>

<br/><br/><br/>

## :star: Features
Expand All @@ -34,9 +27,12 @@
## :zap: Documentation
[Click here](https://nero-docs.pages.dev/)

## Demo
[Click here](https://nero-demo.pages.dev)

## Preview
<img width="2031" alt="Preview1" src="https://github.com/v182/Nero/assets/142740981/2155152d-6d39-4c46-8154-a786fb80a6e8">
<img width="2031" alt="Preview2" src="https://github.com/v182/Nero/assets/142740981/cba3cd89-63e6-4915-b65b-16ee117ebb0d">

## Support
Open a Issue or join our [Discord](https://discord.gg/Ku7chqmbCS)

## Note
Be aware that Nero is a reworked & updated version of the Client known as [NorthClient](https://github.com/northdevelopment/northclient)
Binary file modified db.sqlite
Binary file not shown.
230 changes: 136 additions & 94 deletions routes/auth/email.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,104 +2,146 @@ const settings = require('../../handlers/readSettings').settings();
const mailer = require("../../handlers/mailer").mailer();
const makeid = require("../../handlers/makeid");
const fetch = require("node-fetch");
const Swal = require('sweetalert2');

function sendAlert(res, message) {
res.send(`
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
</head>
<body>
<script>
Swal.fire({
icon: 'error',
title: 'Oops...',
text: '${message}',
}).then(() => {
window.history.back();
});
</script>
</body>
</html>
`);
}


module.exports.load = async function(app, ejs, db) {
app.get("/auth/login", async (req, res) => {
if (!req.query.email || !req.query.password) return res.send("<br>Missing information.<br>")
const user = await db.get(`user-${req.query.email}`);
if (!user) return res.send({error: "Invalid Email or Password."});
if (user.password !== req.query.password) return res.send({error: "Invalid Email or Password."});
app.get("/auth/login", async (req, res) => {
if (!req.query.email || !req.query.password) {
return res.json({ error: "Missing information." });
}
const user = await db.get(`user-${req.query.email}`);
if (!user) {
return res.json({ error: "Invalid Email or Password." });
}
if (user.password !== req.query.password) {
return res.json({ error: "Invalid Email or Password." });
}

let cacheaccount = await fetch(
`${settings.pterodactyl.domain}/api/application/users/${await db.get(`users-${req.query.email}`)}?include=servers`,
{
method: "get",
headers: { 'Content-Type': 'application/json', "Authorization": `Bearer ${settings.pterodactyl.key}` }
}
);
if (await cacheaccount.statusText == "Not Found") return res.send("An error has occured while attempting to get your user information.");
cacheaccount = JSON.parse(await cacheaccount.text());
let cacheaccount = await fetch(
`${settings.pterodactyl.domain}/api/application/users/${await db.get(`users-${req.query.email}`)}?include=servers`,
{
method: "get",
headers: { 'Content-Type': 'application/json', "Authorization": `Bearer ${settings.pterodactyl.key}` }
}
);
if (await cacheaccount.statusText == "Not Found") {
return res.json({ error: "An error has occurred while attempting to get your user information." });
}
cacheaccount = JSON.parse(await cacheaccount.text());

req.session.pterodactyl = cacheaccount.attributes;
req.session.userinfo = user;
return res.redirect("/dashboard")
});
req.session.pterodactyl = cacheaccount.attributes;
req.session.userinfo = user;
return res.json({ success: true });
});

app.get("/auth/register", async (req, res) => {
if (!req.query.email || !req.query.username || !req.query.password) return res.send("<br> Missing information </br>")
if (await db.get(`user-${req.query.email}`)) return res.send("Already registered.");
const userinfo = {
username: req.query.username,
id: req.query.email,
password: req.query.password,
discriminator: null
}
const accountjson = await fetch(
`${settings.pterodactyl.domain}/api/application/users`, {
method: "post",
headers: {
'Content-Type': 'application/json',
"Authorization": `Bearer ${settings.pterodactyl.key}`
},
body: JSON.stringify({
username: req.query.username,
email: req.query.email,
first_name: req.query.username,
last_name: "(credentials)",
password: req.query.password
})
}
);
if (accountjson.status == 201) {
const accountinfo = JSON.parse(await accountjson.text());
await db.set(`users-${req.query.email}`, accountinfo.attributes.id);
} else {
let accountlistjson = await fetch(
`${settings.pterodactyl.domain}/api/application/users?include=servers&filter[email]=${encodeURIComponent(req.query.email)}`, {
method: "get",
headers: {
'Content-Type': 'application/json',
"Authorization": `Bearer ${settings.pterodactyl.key}`
}
}
);
const accountlist = await accountlistjson.json();
const user = accountlist.data.filter(acc => acc.attributes.email == req.query.email);
if (user.length == 1) {
let userid = user[0].attributes.id;
await db.set(`users-${userinfo.id}`, userid);
} else {
return res.send("An error has occured when attempting to create your account.");
};
}
let cacheaccount = await fetch(
`${settings.pterodactyl.domain}/api/application/users/${await db.get(`users-${req.query.email}`)}?include=servers`,
{
method: "get",
headers: { 'Content-Type': 'application/json', "Authorization": `Bearer ${settings.pterodactyl.key}` }
}
);
if (await cacheaccount.statusText == "Not Found") return res.send("An error has occured while attempting to get your user information.");
let cacheaccountinfo = JSON.parse(await cacheaccount.text());
await db.set(`user-${req.query.email}`, userinfo);
await db.set(`username-${userinfo.id}`, req.query.username);
app.get("/auth/register", async (req, res) => {
if (!req.query.email || !req.query.username || !req.query.password) {
return res.json({ error: "Missing information." });
}
if (await db.get(`user-${req.query.email}`)) {
return res.json({ error: "Already registered." });
}

const userinfo = {
username: req.query.username,
id: req.query.email,
password: req.query.password,
discriminator: null
};

let userdb = await db.get("userlist");
userdb = userdb ? userdb : [];
if (!userdb.includes(`${userinfo.id}`)) {
userdb.push(`${userinfo.id}`);
await db.set("userlist", userdb);
const accountjson = await fetch(
`${settings.pterodactyl.domain}/api/application/users`, {
method: "post",
headers: {
'Content-Type': 'application/json',
"Authorization": `Bearer ${settings.pterodactyl.key}`
},
body: JSON.stringify({
username: req.query.username,
email: req.query.email,
first_name: req.query.username,
last_name: "(credentials)",
password: req.query.password
})
}
);

if (accountjson.status == 201) {
const accountinfo = JSON.parse(await accountjson.text());
await db.set(`users-${req.query.email}`, accountinfo.attributes.id);
} else {
let accountlistjson = await fetch(
`${settings.pterodactyl.domain}/api/application/users?include=servers&filter[email]=${encodeURIComponent(req.query.email)}`, {
method: "get",
headers: {
'Content-Type': 'application/json',
"Authorization": `Bearer ${settings.pterodactyl.key}`
}
}
if (settings.smtp.enabled == true) {
mailer.sendMail({
from: settings.smtp.mailfrom,
to: userinfo.id,
subject: `Signup`,
html: `Here are your login details for ${settings.name} Panel:\n Username: ${req.query.username}\n Email: ${userinfo.id}\n Password: ${userinfo.password}`
});
}
req.session.pterodactyl = cacheaccountinfo.attributes;
req.session.userinfo = userinfo;
return res.redirect("/dashboard");
});
}
);
const accountlist = await accountlistjson.json();
const user = accountlist.data.filter(acc => acc.attributes.email == req.query.email);
if (user.length == 1) {
let userid = user[0].attributes.id;
await db.set(`users-${userinfo.id}`, userid);
} else {
return res.json({ error: "An error has occurred when attempting to create your account." });
}
}

let cacheaccount = await fetch(
`${settings.pterodactyl.domain}/api/application/users/${await db.get(`users-${req.query.email}`)}?include=servers`,
{
method: "get",
headers: { 'Content-Type': 'application/json', "Authorization": `Bearer ${settings.pterodactyl.key}` }
}
);
if (await cacheaccount.statusText == "Not Found") {
return res.json({ error: "An error has occurred while attempting to get your user information." });
}

let cacheaccountinfo = JSON.parse(await cacheaccount.text());
await db.set(`user-${req.query.email}`, userinfo);
await db.set(`username-${userinfo.id}`, req.query.username);

let userdb = await db.get("userlist");
userdb = userdb ? userdb : [];
if (!userdb.includes(`${userinfo.id}`)) {
userdb.push(`${userinfo.id}`);
await db.set("userlist", userdb);
}
if (settings.smtp.enabled == true) {
mailer.sendMail({
from: settings.smtp.mailfrom,
to: userinfo.id,
subject: `Signup`,
html: `Here are your login details for ${settings.name} Panel:\n Username: ${req.query.username}\n Email: ${userinfo.id}\n Password: ${userinfo.password}`
});
}
req.session.pterodactyl = cacheaccountinfo.attributes;
req.session.userinfo = userinfo;
return res.redirect("/dashboard");
});
}
Binary file modified sessions.db
Binary file not shown.
2 changes: 1 addition & 1 deletion settings.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Nero
defaulttheme: default
version: 1.0
version: 1.5.1
website:
port: 3000
secret: makethishard
Expand Down
2 changes: 1 addition & 1 deletion themes/default/admin.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@
<div class="card-header">
<div class="card-title">Nero Client Dashboard
<center> <a
href="https://github.com/v182/Nero"
href="https://github.com/redo-quest/Nero"
target="_blank"><i class="fab fa-github"
href="https://github.com/v182/Nero"></i>GITHUB</a>
</div>
Expand Down
5 changes: 3 additions & 2 deletions themes/default/buy.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
<% } %>
<meta content='width=device-width, initial-scale=1.0, shrink-to-fit=no' name='viewport' />
<link rel="icon"
href="<%= settings.website.logo %>" />
href="https://images-ext-1.discordapp.net/external/sMKkyuJo8Wn_AK_Foyl0aGrWwhe9fbqtPgkThvHxdxs/%3Fsize%3D1024/https/cdn.discordapp.com/icons/933803406513012807/bb763a3db98f9f0ae8d6029e8355dd06.png"
type="image/png">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700">
<link rel="stylesheet" href="/assets/thmeneed/vendor/nucleo/css/nucleo.css" type="text/css">
<link rel="stylesheet" href="/assets/thmeneed/vendor/@fortawesome/fontawesome-free/css/all.min.css"
Expand Down Expand Up @@ -262,7 +263,7 @@
<center>
<div class="row mx-auto">
<select style="border-radius: 15px; padding: 8px;" class="form-control mx-auto" style="width:45% !important;" name="month"><option value="1">1st</option><option value="2">2nd</option><option value="3">3rd</option><option value="4">4th</option><option value="5">5th</option><option value="6">6th</option><option value="7">7th</option><option value="8">8th</option><option value="9">9th</option><option value="10">10th</option><option value="11">11th</option><option value="12">12th</option></select><br><br>
<br/><select style="border-radius: 15px; padding: 8px;" class="form-control mx-auto" style="width:45% !important;" name="year"><option value="2022">2022</option><option value="2023">2023</option><option value="2024">2024</option><option value="2025">2025</option><option value="2026">2026</option><option value="2027">2027</option><option value="2028">2028</option><option value="2029">2029</option><option value="2030">2030</option><option value="2031">2031</option><option value="2032">2032</option><option value="2033">2033</option></select>
<br/><select style="border-radius: 15px; padding: 8px;" class="form-control mx-auto" style="width:45% !important;" name="year"><option value="2024">2024</option><option value="2025">2025</option><option value="2026">2026</option><option value="2027">2027</option><option value="2028">2028</option><option value="2029">2029</option><option value="2030">2030</option><option value="2031">2031</option><option value="2032">2032</option><option value="2033">2033</option></select>
</div>
</center>
<br>
Expand Down
22 changes: 17 additions & 5 deletions themes/default/dashboard.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@
<!-- Icons. Uncomment required icon fonts -->
<link rel="stylesheet" href="../assets/vendor/fonts/boxicons.css" />


<!-- Add Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">

<!-- Add jQuery -->
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

<!-- Add Bootstrap JS -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

<!-- Core CSS -->
<link rel="stylesheet" href="../assets/vendor/css/core.css" class="template-customizer-core-css" />
<link rel="stylesheet" href="../assets/vendor/css/theme-default.css" class="template-customizer-theme-css" />
Expand Down Expand Up @@ -550,11 +560,11 @@
<br />
<li class="d-flex">
<div class="avatar flex-shrink-0 me-3">
<span class="avatar-initial rounded bg-label-primary"><i class="bx bxl-discord"></i></span>
<span class="avatar-initial rounded bg-label-primary"><i class="bx bx-home-circle"></i></span>
</div>
<div class="d-flex w-100 flex-wrap align-items-center justify-content-between gap-2">
<div class="me-2">
<small class="text-muted d-block mb-1">Dashboard URL:</small>
<small class="text-muted d-block mb-1">Dashboard:</small>
<a href="<%= settings.pterodactyl.domain %>" class="btn btn-primary">Go to Dashboard</a>
</div>
</div>
Expand All @@ -571,7 +581,7 @@
</div>
<div>
<a style="cursor:pointer;" data-toggle="modal" data-target="#modal-notification">
<span class="btn btn-primary">Regenrate Password</span>
<span class="btn btn-primary">Reset</span>
</a>
</div>
</div>
Expand Down Expand Up @@ -626,7 +636,7 @@
</div>
</div>
</div>
</li>
</li>
</li>
</div>
</div>
Expand Down Expand Up @@ -710,7 +720,9 @@
<script>
document.write(new Date().getFullYear());
</script>

Powered by
<a href="https://github.com/redo-quest/nero" target="_blank"
class="footer-link fw-bolder">NeroClient</a>
</div>
<div>
<a href="/404" class="footer-link me-4" target="_blank">License</a>
Expand Down
Loading