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,35 @@
const rateLimit = require('express-rate-limit')
const log = require('../utils/logger')('ratelimit')
function makeLimiter({ windowMs, max, label, message }) {
return rateLimit({
windowMs,
max,
standardHeaders: true,
legacyHeaders: false,
message: { message },
handler: (req, res, next, options) => {
log.warn(`${label} rate limit exceeded`, { ip: req.ip, path: req.originalUrl })
res.status(options.statusCode).json(options.message)
},
})
}
// Brute-force protection on login.
const loginLimiter = makeLimiter({
windowMs: 15 * 60 * 1000,
max: 10,
label: 'login',
message: 'Too many login attempts. Please try again later.',
})
// Throttle the public contact form.
const contactLimiter = makeLimiter({
windowMs: 60 * 60 * 1000,
max: 5,
label: 'contact',
message: 'Too many messages sent. Please try again later.',
})
module.exports = { loginLimiter, contactLimiter }