Initial commit: UOMysticmoon backend (Express + MariaDB + JWT)

- Layered API (router -> controller -> model -> db), serverlinkr pattern
- Public / auth / admin route groups; posts, wiki, settings, users, activity models
- JWT httpOnly-cookie auth (Secure auto-detected: LAN HTTP + Pangolin HTTPS)
- Site LIVE/MAINTENANCE mode with admin preview bypass
- Dual file+console logging (info/warn/error/debug) + HTTP access logs
- Docker Compose (app + MariaDB), schema.sql + seed, .env.example
- Verified end-to-end against MariaDB (27/27 smoke checks)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 20:58:32 -05:00
commit eef79e2403
41 changed files with 4195 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
const users = require('../../../model/users/users.model')
const activity = require('../../../model/activity/activity.model')
const { signToken, setAuthCookie, clearAuthCookie } = require('../../../utils/auth')
const log = require('../../../utils/logger')('auth')
async function login(req, res) {
const { username, password } = req.body
try {
const user = await users.getRawByUsername(username)
const ok = user && (await users.validatePassword(user, password))
if (!ok) {
log.warn('login failed', { username, ip: req.ip })
return res.status(401).json({ message: 'Incorrect username or password.' })
}
await users.recordLogin(user.id)
const token = signToken(user)
setAuthCookie(req, res, token)
await activity.log({ req, userId: user.id, action: 'auth.login' })
log.info('login success', { username: user.username, id: user.id, ip: req.ip })
return res.json({
user: { id: user.id, username: user.username, role: user.role },
})
} catch (err) {
log.error('login error', err)
return res.status(500).json({ message: 'Internal Server Error' })
}
}
async function logout(req, res) {
clearAuthCookie(req, res)
return res.json({ message: 'Logged out.' })
}
async function me(req, res) {
try {
const user = await users.getById(req.user.id)
if (!user) return res.status(401).json({ message: 'Unauthorized' })
return res.json({ user })
} catch (err) {
return res.status(500).json({ message: 'Internal Server Error' })
}
}
module.exports = { login, logout, me }

View File

@@ -0,0 +1,22 @@
const express = require('express')
const { body } = require('express-validator')
const { login, logout, me } = require('./auth.controller')
const { isLoggedIn } = require('../../../utils/auth')
const { loginLimiter } = require('../../../middleware/rateLimit')
const validate = require('../../../middleware/validate')
const authRouter = express.Router()
authRouter.post(
'/login',
loginLimiter,
body('username').isString().trim().notEmpty(),
body('password').isString().notEmpty(),
validate,
login,
)
authRouter.post('/logout', logout)
authRouter.get('/me', isLoggedIn, me)
module.exports = authRouter