UBS/routes/admin.js
2024-12-21 02:38:51 -07:00

182 lines
5.7 KiB
JavaScript

const express = require('express');
const router = express.Router();
const mariadb = require('mariadb');
const reasonFlags = JSON.parse(process.env.REASON_FLAGS)
const expressSession = require('express-session');
const bcrypt = require("bcrypt")
const crypto = require("crypto")
const flags = require('../flags');
const { execSync } = require('child_process');
const { env } = require('process');
const session = require('express-session');
const totp = require('totp-generator').TOTP;
// Create a MariaDB connection pool
const pool = mariadb.createPool({
host: process.env.DB_HOST, // Replace with your database host
port: process.env.DB_PORT || 3306,
user: process.env.DB_USER, // Replace with your database username
password: process.env.DB_PASS, // Replace with your database password
database: process.env.DB_DATABASE, // Replace with your database name
connectionLimit: 5 // Adjust connection limit as needed
});
router.use(express.json());
router.use(express.urlencoded({ extended: true }));
router.use(expressSession({
store: expressSession.MemoryStore(),
secret: process.env.SESSION_SECRET || 'default_secret',
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
maxAge: 24 * 60 * 60 * 1000 // 24 hours
}
}));
const authenticate = (req, res, next) => {
if (!req.session.admin) {
res.redirect('/admin/login');
return;
}
next();
}
// MAIN PAGES
router.get('/', authenticate, (req, res) => {
res.render('admin/dashboard', { env: process.env, session: req.session });
});
router.get('/edit/:id', authenticate, async (req, res) => {
const conn = await pool.getConnection();
const id = req.params.id;
const row = await conn.query('SELECT * FROM bans WHERE id = ?', [id]);
conn.end();
if (!row[0]) {
res.redirect('/admin');
return;
}
res.render('admin/edit', { env: process.env, session: req.session, ban: row[0], reasonFlags, setFlags: flags.getSetFlags(row[0].reasonsFlag, reasonFlags) });
});
// Ban Creation
router.get('/create', authenticate, (req, res) => {
res.render('admin/create', { env: process.env, session: req.session, reasonFlags });
});
router.post('/create', authenticate, async (req, res) => {
const conn = await pool.getConnection();
const data = req.body;
if (!data.robloxId && !data.discordId) {
res.json({ success: false, message: 'Please enter a Roblox ID or Discord ID.' });
return;
}
const reasonShort = data.reasonShort || 'No reason provided';
const reasonLong = data.reasonLong || 'No reason provided';
const reasonsFlag = data.reasonsFlag || 0;
const moderator = req.session.user.username || 'Unknown';
const expiresTimestamp = data.expiresTimestamp || null;
const robloxId = data.robloxId || null;
const discordId = data.discordId || null;
await conn.query('INSERT INTO bans (reasonShort, reasonLong, reasonsFlag, moderator, expiresTimestamp, robloxId, discordId) VALUES (?, ?, ?, ?, ?, ?, ?)',
[reasonShort, reasonLong, reasonsFlag, moderator, expiresTimestamp, robloxId, discordId]);
conn.end();
res.json({ success: true, message: 'User banned successfully', redirect: '/admin' });
});
// Ban Editing
router.post('/edit/:id', authenticate, async (req, res) => {
const conn = await pool.getConnection();
const id = req.params.id;
const data = req.body;
console.log(data)
if (!data.robloxId && !data.discordId) {
res.json({ success: false, message: 'Please enter a Roblox ID or Discord ID.' });
return;
}
const reasonShort = data.reasonShort || 'No reason provided';
const reasonLong = data.reasonLong || 'No reason provided';
const reasonsFlag = data.reasonsFlag || 0;
const moderator = req.session.user.username || 'Unknown';
const expiresTimestamp = data.expiresTimestamp || null;
const robloxId = data.robloxId || null;
const discordId = data.discordId || null;
// if data.neverExpires == "on" then set expiresTimestamp to null
if (data.neverExpires == "on") {
expiresTimestamp = null;
}
await conn.query('UPDATE bans SET reasonShort = ?, reasonLong = ?, reasonsFlag = ?, moderator = ?, expiresTimestamp = ?, robloxId = ?, discordId = ? WHERE id = ?',
[reasonShort, reasonLong, reasonsFlag, moderator, expiresTimestamp, robloxId, discordId, id]);
conn.end();
res.json({ success: true, message: 'User updated successfully', redirect: '/admin' });
});
// API STUFF //
router.get("/api/bans", authenticate, async (req, res) => {
const conn = await pool.getConnection();
const rows = await conn.query('SELECT * FROM bans');
conn.end();
res.json(rows);
});
// AUTH STUFF //
router.get('/login', (req, res) => {
if (req.session.admin) {
res.redirect('/admin');
return;
}
res.render('admin/login', { env: process.env });
});
router.post('/login', async (req, res) => {
const conn = await pool.getConnection();
const username = req.body.username;
const password = req.body.password;
const row = await conn.query('SELECT * FROM users WHERE username = ?', [username]);
conn.end();
if (row[0]) {
const user = row[0];
const match = await bcrypt.compare(password, user.passwordHash);
if (match) {
if (user.totp_token) {
if (!req.body.totp) {
return res.json({ success: false, totpRequired: true, message: 'Please enter your 2FA code!' });
}
const generatedToken = totp.generate(user.totp_token).otp;
if (req.body.totp !== generatedToken) {
return res.json({ success: false, totpRequired: true, message: 'Invalid TOTP token' });
}
}
req.session.admin = true;
req.session.user = user;
delete req.session.user.passwordHash; // Security measure
return res.json({ success: true, message: 'Login successful', redirect: '/admin' });
}
}
res.json({ success: false, message: 'Invalid username or password' });
});
router.all('/logout', (req, res) => {
req.session.destroy();
res.redirect('/admin/login');
});
module.exports = router;