From 2dce1380376fb86c2843244e670187d6154b3827 Mon Sep 17 00:00:00 2001 From: Aidan Date: Sat, 14 Dec 2024 12:35:18 -0500 Subject: [PATCH] major update (improved registration system and admin panel) --- .env.example | 7 +++ .gitignore | 4 +- Dockerfile | 2 +- README.md | 16 +++++- app.js | 113 ++++++++++++++++++++++++++++++++++--- docker-compose.yml.example | 17 +++++- package.json | 6 +- src/admin-dash.ejs | 50 ++++++++++++++++ src/admin-login.ejs | 21 +++++++ src/error/404.ejs | 7 +++ src/error/500.ejs | 7 +++ src/error/email.ejs | 14 +++++ src/reg-success.ejs | 8 +++ src/register.ejs | 28 ++++++--- src/req-status.ejs | 21 +++++++ src/shards/nav.ejs | 6 ++ 16 files changed, 303 insertions(+), 24 deletions(-) create mode 100644 .env.example create mode 100644 src/admin-dash.ejs create mode 100644 src/admin-login.ejs create mode 100644 src/error/404.ejs create mode 100644 src/error/500.ejs create mode 100644 src/error/email.ejs create mode 100644 src/reg-success.ejs create mode 100644 src/req-status.ejs diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..6923c59 --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +DB_NAME=pontusmail +DB_USER=root +DB_PASSWORD=passwdhere +DB_HOST=127.0.0.1 +SESSION_SECRET=secretkeyhere +ADMIN_USERNAME=admin +ADMIN_PASSWORD=admin \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8670b45..88e094b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ package-lock.json docker-compose.yml register,log donations.json -.idea/ \ No newline at end of file +.idea/ +db/ +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 1697dbe..f3fcfd0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18 +FROM node:20 WORKDIR /usr/src/app COPY package*.json ./ RUN npm install --only=production diff --git a/README.md b/README.md index 4233b5c..cf3ec38 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,17 @@ Landing page for p0ntus mail ```bash mv donations.json.example donations.json ``` -4. Install dependencies +4. Copy the example `.env` + ```bash + mv .env.example .env + ``` + + Make sure you edit this with your MySQL server information and other values. +5. Install dependencies ```bash npm install ``` -5. Start the server +6. Start the server ```bash node app.js ``` @@ -38,6 +44,12 @@ You can also use Docker to self-host pontus-mail's frontend. Make sure you have ```bash mv docker-compose.yml.example docker-compose.yml ``` +3. Copy the example `.env` + ```bash + mv .env.example .env + ``` + + Make sure you edit this file with values matching in `docker-compose.xml`, and other desired values like admin username/password. 3. Copy the example `donations.json` ```bash mv donations.json.example donations.json diff --git a/app.js b/app.js index 8666587..9a772e2 100644 --- a/app.js +++ b/app.js @@ -1,17 +1,48 @@ const express = require('express'); const bodyParser = require('body-parser'); const path = require('path'); -const fs = require('fs'); +const session = require('express-session'); +const { Sequelize, DataTypes } = require('sequelize'); +const { error } = require('console'); +require('dotenv').config(); const app = express(); app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, 'src')); app.use(bodyParser.urlencoded({ extended: false })); - app.use(express.static(path.join(__dirname, 'public'))); +app.use(session({ + secret: process.env.SESSION_SECRET, + resave: false, + saveUninitialized: true +})); +const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, { + host: process.env.DB_HOST || '127.0.0.1', + dialect: 'mysql' +}); + +sequelize.authenticate() + .then(() => console.log('Database connected')) + .catch(err => console.log('Error: ' + err)); + +const Request = sequelize.define('Request', { + fullName: DataTypes.STRING, + email: DataTypes.STRING, + reason: DataTypes.TEXT, + telegram: DataTypes.STRING, + status: { + type: DataTypes.STRING, + defaultValue: 'Pending' + } +}); + +// Sync models +sequelize.sync(); + +// Routes app.get('/', (req, res) => { res.render('index', { currentPage: 'home' }); }); @@ -20,10 +51,6 @@ app.get('/services', (req, res) => { res.render('services', { currentPage: 'services' }); }); -app.get('/register', (req, res) => { - res.render('register', { currentPage: 'register' }); -}); - app.get('/donate', (req, res) => { const donations = JSON.parse(fs.readFileSync('donations.json', 'utf8')); res.render('donate', { @@ -64,7 +91,75 @@ app.get('/guides/vaultwarden/firefox', (req, res) => { res.render('guides/vaultwarden/firefox', { currentPage: 'guides' }); }); -const PORT = process.env.PORT || 3000; -app.listen(PORT, () => { - console.log(`Server is running on port ${PORT}`); +app.get('/register', (req, res) => { + res.render('register', { currentPage: 'register' }); +}); + +app.post('/register', async (req, res) => { + const { fullName, email, reason, telegram } = req.body; + await Request.create({ fullName, email, reason, telegram }); + res.render('reg-success', { currentPage: 'register' }); +}); + +app.get('/request', async (req, res) => { + console.log("Got /request"); + const { email } = req.query; + + if (!email) { + return res.status(400).render('error/email'); + } + + try { + const request = await Request.findOne({ where: { email } }); + if (!request) { + return res.status(404).render('error/404'); + } + res.render('req-status', { request }); + } catch (error) { + console.error(error); + res.status(500).render('error/500'); + } +}); + +function checkAdminAuth(req, res, next) { + if (req.session.admin) { + next(); + } else { + res.redirect('/admin', { error: null }); + } +} + +app.get('/admin', (req, res) => { + res.render('admin-login', { currentPage: 'admin', error: null }); +}); + +app.post('/admin', (req, res) => { + const { username, password } = req.body; + if (username === process.env.ADMIN_USERNAME && password === process.env.ADMIN_PASSWORD) { + req.session.admin = true; + res.redirect('/admin/dashboard'); + } else { + res.render('admin-login', { error: 'An error occurred.' }); + } +}); + +app.get('/admin/dashboard', checkAdminAuth, async (req, res) => { + const requests = await Request.findAll(); + res.render('admin-dash', { requests, currentPage: 'admin' }); +}); + +app.post('/admin/update-status', checkAdminAuth, async (req, res) => { + const { id, status } = req.body; + await Request.update({ status }, { where: { id } }); + res.redireHot('/admin/dashboard'); +}); + +app.post('/admin/delete-request', checkAdminAuth, async (req, res) => { + const { id } = req.body; + await Request.destroy({ where: { id } }); + res.redirect('/admin/dashboard'); +}); + +app.listen(3000, () => { + console.log('Server started on port 3000'); }); \ No newline at end of file diff --git a/docker-compose.yml.example b/docker-compose.yml.example index ce09d68..6f6097d 100644 --- a/docker-compose.yml.example +++ b/docker-compose.yml.example @@ -4,10 +4,23 @@ services: container_name: pontus-mail restart: always ports: - - "80:3000" + - "2424:3000" volumes: - ./register.log:/usr/src/app/register.log - ./exclusions.json:/usr/src/app/exclusions.json - ./donations.json:/usr/src/app/donations.json environment: - - NODE_ENV=production \ No newline at end of file + - NODE_ENV=production + - DB_HOST=pontus-mail-db + - DB_USER=root + - DB_PASSWORD=mysqlrootpasswdhere + - DB_NAME=pontusmail + pontus-mail-db: + image: mysql:latest + environment: + - MYSQL_ROOT_PASSWORD=mysqlrootpasswdhere + - MYSQL_DATABASE=pontusmail + ports: + - "3306:3306" + volumes: + - ./db:/var/lib/mysql \ No newline at end of file diff --git a/package.json b/package.json index 4a3b1db..74cdbff 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,15 @@ "license": "CC0-1.0", "dependencies": { "body-parser": "^1.20.3", + "dotenv": "^16.4.7", "ejs": "^3.1.10", "express": "^4.21.1", + "express-session": "^1.18.1", + "mariadb": "^3.4.0", + "mysql2": "^3.11.5", + "sequelize": "^6.37.5", "winston": "^3.17.0" }, - "devDependencies": {}, "repository": { "type": "git", "url": "git+https://github.com/ihatenodejs/pontus-mail.git" diff --git a/src/admin-dash.ejs b/src/admin-dash.ejs new file mode 100644 index 0000000..d81f858 --- /dev/null +++ b/src/admin-dash.ejs @@ -0,0 +1,50 @@ +<%- include('shards/header', { title: 'Admin Dashboard - p0ntus mail' }) %> +
+ <%- include('shards/nav', { currentPage: 'admin' }) %> + Dashboard +
+ + + + + + + + + + + + + + + <% requests.forEach(request => { %> + + + + + + + + + + + <% }); %> + +
IDFull NameEmailReasonTelegramStatusUpdate StatusDelete
<%= request.id %><%= request.fullName %><%= request.email %><%= request.reason %><%= request.telegram %><%= request.status %> +
+ + + +
+
+
+ + +
+
+
+<%- include('shards/footer') %> \ No newline at end of file diff --git a/src/admin-login.ejs b/src/admin-login.ejs new file mode 100644 index 0000000..16aa472 --- /dev/null +++ b/src/admin-login.ejs @@ -0,0 +1,21 @@ +<%- include('shards/header', { title: 'Admin - p0ntus mail' }) %> +
+ <%- include('shards/nav', { currentPage: 'admin' }) %> + Login to administration panel +
+ <% if (error) { %> +
<%= error %>
+ <% } %> +
+
+ + +
+
+ + +
+ +
+
+<%- include('shards/footer') %> \ No newline at end of file diff --git a/src/error/404.ejs b/src/error/404.ejs new file mode 100644 index 0000000..42efbf6 --- /dev/null +++ b/src/error/404.ejs @@ -0,0 +1,7 @@ +<%- include('../shards/header', { title: '404 Not Found - p0ntus mail' }) %> +
+ 404 Not Found +
+

The requested resource could not be found.

+
+<%- include('../shards/footer') %> \ No newline at end of file diff --git a/src/error/500.ejs b/src/error/500.ejs new file mode 100644 index 0000000..f7ee2bd --- /dev/null +++ b/src/error/500.ejs @@ -0,0 +1,7 @@ +<%- include('../shards/header', { title: '500 Internal Server Error - p0ntus mail' }) %> +
+ 500 Internal Server Error +
+

An unexpected error occurred. Please try again later.

+
+<%- include('../shards/footer') %> \ No newline at end of file diff --git a/src/error/email.ejs b/src/error/email.ejs new file mode 100644 index 0000000..d27b1f5 --- /dev/null +++ b/src/error/email.ejs @@ -0,0 +1,14 @@ +<%- include('../shards/header', { title: 'Request Status - p0ntus mail' }) %> +
+ We need your email +
+

We need an email to check your request. Please enter your p0ntus mail email address below:

+
+
+ + +
+ +
+
+<%- include('../shards/footer') %> \ No newline at end of file diff --git a/src/reg-success.ejs b/src/reg-success.ejs new file mode 100644 index 0000000..6c94f7d --- /dev/null +++ b/src/reg-success.ejs @@ -0,0 +1,8 @@ +<%- include('shards/header', { title: 'Registration Successful - p0ntus mail' }) %> +
+ <%- include('shards/nav', { currentPage: 'register' }) %> + Registration Submitted +
+

Your request has been submitted successfully. You can check the status of your request here.

+
+<%- include('shards/footer') %> \ No newline at end of file diff --git a/src/register.ejs b/src/register.ejs index 3f1c805..e1ab4bd 100644 --- a/src/register.ejs +++ b/src/register.ejs @@ -1,14 +1,26 @@ <%- include('shards/header', { title: 'Register - p0ntus mail' }) %>
<%- include('shards/nav', { currentPage: 'register' }) %> - Register +

Register


- Please contact signupp0ntus.com with the following info: - +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
<%- include('shards/footer') %> \ No newline at end of file diff --git a/src/req-status.ejs b/src/req-status.ejs new file mode 100644 index 0000000..727a1c6 --- /dev/null +++ b/src/req-status.ejs @@ -0,0 +1,21 @@ +<%- include('shards/header', { title: 'Request Status - p0ntus mail' }) %> +
+ <%- include('shards/nav', { currentPage: 'request' }) %> + Request Status +
+ <% if (request) { %> +

Request Status: <%= request.status %>

+ <% if (request.status === 'Approved') { %> +
+

Your request has been approved. You can access your p0ntus mail account here with your email as the username and abcabc for the password. FOR SECURITY, CHANGE YOUR PASSWORD ASAP.

+

I also suggest you check out our guides at mail.p0ntus.com/guides.

+

You can also access Vaultwarden at vaultwarden.p0ntus.com.

+

If you need any help or support, contact admin@p0ntus.com.

+

Your webmail can be accessed here.

+
+ <% } %> + <% } else { %> +

No request found for the provided email.

+ <% } %> +
+<%- include('shards/footer') %> \ No newline at end of file diff --git a/src/shards/nav.ejs b/src/shards/nav.ejs index 3ea1c0f..46c0584 100644 --- a/src/shards/nav.ejs +++ b/src/shards/nav.ejs @@ -32,4 +32,10 @@ <% } else { %> Guides <% } %> + <% if (currentPage === 'request') { %> + Request + <% } %> + <% if (currentPage === 'admin') { %> + Admin + <% } %> \ No newline at end of file