fix: deploy crash + multiple bug fixes + cleanup
- server.js: fix getSiteName() returning string when not installed causing 'getSiteName(...).then is not a function' crash on homepage (deploy blocker) - server.js: auto-load business routes after install completes (no restart needed), HTML cache keyed by api_key - install: validate db name/email/password, trigger route loading after complete - app.js: fix forgot/reset/verify pages rendering HomePage (missing page mapping) - verify.js: support URL token auto-verification for external registration links - auth: new email_code template for 6-digit code, reset_password template (forgot-password was using verify_email template) - upload.js: fix MP4 magic-bytes check using undefined buf variable - tickets.js: status enum validation, anonymous submission rate limit - security.js: XSS whitelist preserves email template HTML, strips scripts, blocks javascript:/data: hrefs; CORS reject returns 403 - bans.js: allow clearing reason/duration, status enum validation - users.js: fix req.user.role ReferenceError in create user modal - home.js: tracking results now have detail view button - .gitignore: ignore data/ (db credentials), logs, session files, temp scripts
This commit is contained in:
@@ -17,6 +17,7 @@ const HTML_PATH = path.join(PUBLIC_DIR, 'index.html');
|
||||
|
||||
let cachedHtml = null;
|
||||
let htmlTimestamp = 0;
|
||||
let htmlKey = null;
|
||||
|
||||
function getSiteName() {
|
||||
if (!isInstalled()) return 'MC举报系统';
|
||||
@@ -27,17 +28,18 @@ function getSiteName() {
|
||||
}
|
||||
|
||||
function getHtmlWithKey() {
|
||||
return getSiteName().then(siteName => {
|
||||
return Promise.resolve(getSiteName()).then(siteName => {
|
||||
const stat = fs.statSync(HTML_PATH);
|
||||
const mtime = stat.mtimeMs;
|
||||
if (!cachedHtml || htmlTimestamp < mtime || cachedHtml.indexOf(siteName) === -1) {
|
||||
const cfg = getConfig();
|
||||
const key = cfg?.api_key || '';
|
||||
if (!cachedHtml || htmlTimestamp < mtime || htmlKey !== key || cachedHtml.indexOf(siteName) === -1) {
|
||||
let html = fs.readFileSync(HTML_PATH, 'utf-8');
|
||||
const cfg = getConfig();
|
||||
const key = cfg?.api_key || '';
|
||||
const redirect = isInstalled() ? '' : '<script>location.hash="#/install"</script>';
|
||||
html = html.replace('</head>', `<script>window.__API_KEY__=${JSON.stringify(key)};window.__SITE_NAME__=${JSON.stringify(siteName)}</script>${redirect}</head>`);
|
||||
cachedHtml = html;
|
||||
htmlTimestamp = mtime;
|
||||
htmlKey = key;
|
||||
}
|
||||
return cachedHtml;
|
||||
});
|
||||
@@ -65,11 +67,9 @@ app.use(cors({
|
||||
const allowed = process.env.CORS_ORIGIN;
|
||||
if (!allowed || allowed === '*') return cb(null, true);
|
||||
if (allowed === origin) return cb(null, true);
|
||||
if (!allowed) {
|
||||
const host = origin || '';
|
||||
if (host.startsWith('http://localhost:') || host.startsWith('https://localhost:')) return cb(null, true);
|
||||
}
|
||||
cb(new Error('Not allowed by CORS'));
|
||||
const host = origin || '';
|
||||
if (host.startsWith('http://localhost:') || host.startsWith('https://localhost:')) return cb(null, true);
|
||||
cb(null, false);
|
||||
},
|
||||
credentials: true,
|
||||
methods: ['GET','POST','PUT','DELETE'],
|
||||
@@ -100,7 +100,11 @@ app.use('/js', express.static(path.join(PUBLIC_DIR, 'js'), staticOpts));
|
||||
const installRoutes = require('./routes/install');
|
||||
app.use('/api/install', installRoutes);
|
||||
|
||||
if (isInstalled()) {
|
||||
let businessLoaded = false;
|
||||
function loadBusinessRoutes() {
|
||||
if (businessLoaded) return;
|
||||
businessLoaded = true;
|
||||
|
||||
const authRoutes = require('./routes/auth');
|
||||
app.use('/api/auth/login', methodGuard(['POST']), loginLimiter);
|
||||
app.use('/api/auth/register', methodGuard(['POST']), registerLimiter);
|
||||
@@ -124,6 +128,9 @@ if (isInstalled()) {
|
||||
app.get('/api/verify', (req, res) => res.redirect(`/#/verify?token=${req.query.token}`));
|
||||
}
|
||||
|
||||
if (isInstalled()) loadBusinessRoutes();
|
||||
global.__loadBusinessRoutes = loadBusinessRoutes;
|
||||
|
||||
app.get('/api/health', (req, res) => res.json({ status: 'ok', installed: isInstalled() }));
|
||||
|
||||
app.get('/', async (req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user