WE LOVE TESTING ON PROD

This commit is contained in:
Christopher Cookman 2025-10-01 19:04:07 -06:00
parent cc62815961
commit a52a10378c
3 changed files with 135 additions and 0 deletions

View file

@ -234,6 +234,78 @@ app.post('/admin/login', (req, res) => {
});
})
app.get("/admin/register/:inviteCode", async (req, res) => {
const inviteCode = req.params.inviteCode;
if (!inviteCode) {
res.status(400).send('Bad Request');
return;
}
const inviteData = await pool.query("SELECT * FROM admin_invites WHERE code = ?", [inviteCode]);
if (!inviteData || inviteData.length === 0) {
res.status(400).send('Bad or Expired Invite Code');
return;
}
const invite = inviteData[0];
if (invite.expiresAt && new Date(invite.expiresAt) < new Date()) {
res.status(400).send('Invite Code Expired');
return;
}
if (invite.uses >= invite.maxUses) {
res.status(400).send('Invite Code Max Uses Reached');
return;
}
res.render('admin/register', { inviteCode });
});
app.post("/admin/register/:inviteCode", async (req, res) => {
const inviteCode = req.params.inviteCode;
if (!inviteCode) {
res.render('admin/register', { error: 'Bad Request' });
return;
}
const inviteData = await pool.query("SELECT * FROM admin_invites WHERE code = ?", [inviteCode]);
if (!inviteData || inviteData.length === 0) {
res.render('admin/register', { error: 'Bad or Expired Invite Code' });
return;
}
const invite = inviteData[0];
if (invite.expiresAt && new Date(invite.expiresAt) < new Date()) {
res.render('admin/register', { error: 'Invite Code Expired' });
return;
}
if (invite.uses >= invite.maxUses) {
res.render('admin/register', { error: 'Invite Code Max Uses Reached' });
return;
}
const username = req.body.username;
const password = req.body.password;
if (!username || !password) {
res.render('admin/register', { error: 'Username and Password are required', inviteCode });
return;
}
const existingUser = await pool.query("SELECT * FROM users WHERE username = ?", [String(username)]);
if (existingUser && existingUser.length > 0) {
res.render('admin/register', { error: 'Username already exists', inviteCode });
return;
}
bcrypt.hash(password, saltRounds).then((hash) => {
const newUser = pool.query("INSERT INTO users (username, passwordHash) VALUES (?, ?)",
[String(username), hash]);
const updateInvite = pool.query("UPDATE admin_invites SET uses = uses + 1 WHERE code = ?", [inviteCode]);
Promise.all([newUser, updateInvite]).then(() => {
res.redirect('/admin/login');
}).catch(err => {
console.error('Error creating user:', err);
res.render('admin/register', { error: 'Internal server error', inviteCode });
});
}).catch(err => {
console.error('Error hashing password:', err);
res.render('admin/register', { error: 'Internal server error', inviteCode });
});
});
app.get('/api/v1/admin/routes', (req, res) => { // Get all routes
if (!req.session.adminAuthenticated) {
res.status(401).json({ error: 'Unauthorized' });

View file

@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS admin_invites (
code VARCHAR(36) PRIMARY KEY NOT NULL DEFAULT (UUID()),
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
maxUses INTEGER NOT NULL DEFAULT 1,
uses INTEGER NOT NULL DEFAULT 0,
expiresAt TIMESTAMP,
createdBy INTEGER,
FOREIGN KEY (createdBy) REFERENCES users(id) ON DELETE SET NULL
);

54
views/admin/register.ejs Normal file
View file

@ -0,0 +1,54 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
<title>AstroCom Admin Registration</title>
</head>
<body class="bg-dark">
<div class="container">
<div class="row justify-content-center mt-5">
<div class="col-md-6 col-lg-4">
<div class="card bg-dark text-light shadow">
<div class="card-body p-4">
<h2 class="text-center mb-4">Admin Registration</h2>
<% if (typeof notice !== 'undefined') { %>
<div class="alert alert-info text-center mb-3"><%= notice %></div>
<% } %>
<% if (typeof info !== 'undefined') { %>
<div class="alert alert-primary text-center mb-3"><%= info %></div>
<% } %>
<% if (typeof warn !== 'undefined') { %>
<div class="alert alert-warning text-center mb-3"><%= warn %></div>
<% } %>
<% if (typeof error !== 'undefined') { %>
<div class="alert alert-danger text-center mb-3"><%= error %></div>
<% } %>
<form action="." method="POST">
<div class="mb-3">
<label for="username" class="form-label">Username:</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password:</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary w-100">Register</button>
</form>
</div>
</div>
</div>
<div id="footer" class="text-light mt-5"></div>
</div>
<script src="/assets/js/bootstrap.bundle.min.js"></script>
<script src="/assets/js/jquery.min.js"></script>
<script>
$(function() {
$("#footer").load("/footer");
});
</script>
</body>
</html>