This commit is contained in:
2026-04-20 18:05:36 +00:00
parent d73422555d
commit 33b1f276c6
26 changed files with 598 additions and 183 deletions

View File

@@ -2,6 +2,7 @@ const express = require('express');
const rateLimit = require('express-rate-limit');
const { ChannelType } = require('discord.js');
const { CONFIG } = require('../config');
const { safeEqual } = require('../utils');
const { applyConfigUpdates, readAllConfig } = require('../services/configPersistence');
const { logSystem } = require('../services/debugLog');
const { REGISTRY: NOTIFICATION_REGISTRY } = require('../services/notificationRegistry');
@@ -15,6 +16,7 @@ const {
const router = express.Router();
// Intentionally no trust-proxy: loopback-only; global rate-limit bucket.
const internalLimiter = rateLimit({
windowMs: 60 * 1000,
max: 10,
@@ -28,7 +30,7 @@ router.use(internalLimiter);
// Middleware: verify internal secret
router.use((req, res, next) => {
const secret = req.headers['x-internal-secret'];
if (!CONFIG.INTERNAL_API_SECRET || secret !== CONFIG.INTERNAL_API_SECRET) {
if (!CONFIG.INTERNAL_API_SECRET || !safeEqual(secret, CONFIG.INTERNAL_API_SECRET)) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
@@ -136,10 +138,13 @@ router.post('/restart', express.json(), (req, res) => {
const delay = new Date(scheduledFor).getTime() - Date.now();
if (delay <= 0) return res.status(400).json({ error: 'Scheduled time is in the past' });
if (scheduledRestart) clearTimeout(scheduledRestart);
scheduledRestart = setTimeout(() => {
// Lazy require: broccolini-discord.js requires this file at module scope before its exports are populated.
const { trackTimeout } = require('../broccolini-discord');
scheduledRestart = trackTimeout(setTimeout(() => {
console.log('[restart] Scheduled restart firing...');
process.exit(0);
}, delay);
}, delay));
if (scheduledRestart && typeof scheduledRestart.unref === 'function') scheduledRestart.unref();
res.json({ ok: true, mode, scheduledFor, delayMs: delay });
return;
}