fix: public footer reads DB settings for all visitors

- settings.js: new public GET /settings/public returns only
  copyright + icp (no auth, no sensitive settings leaked)
- app.js loadFooter(): dropped Auth.isAdmin() gate, uses public
  endpoint; showPublic() (home/root) now loads footer too
- security.js: apiKeyGuard whitelist /api/settings/public and
  /api/settings/skin-site
This commit is contained in:
2026-08-22 02:51:20 +08:00
parent 6c05a13ae4
commit d7fb971f9f
3 changed files with 17 additions and 5 deletions

View File

@@ -154,7 +154,7 @@ const captchaLimiter = rateLimit({
function apiKeyGuard(req, res, next) {
const p = req.originalUrl;
if (p === '/api/health' || p.startsWith('/api/install') || p.startsWith('/api/polls/server-list')) return next();
if (p === '/api/health' || p.startsWith('/api/install') || p.startsWith('/api/polls/server-list') || p.startsWith('/api/settings/public') || p.startsWith('/api/settings/skin-site')) return next();
const key = getApiKey();
if (!key) return next();
if (!req.headers['x-api-key'] || req.headers['x-api-key'].length !== key.length) return res.status(401).json({ error: '无效的 API 密钥' });

View File

@@ -70,6 +70,16 @@ function formatUuid(id) {
return `${s.slice(0,8)}-${s.slice(8,12)}-${s.slice(12,16)}-${s.slice(16,20)}-${s.slice(20)}`;
}
// 公开: 页尾信息(版权/ICP, 访客可见, 不暴露其他设置)
router.get('/public', async (req, res) => {
try {
const rows = await query("SELECT k, v FROM settings WHERE k IN ('copyright','icp')");
const map = {};
for (const r of rows) map[r.k] = r.v;
res.json({ copyright: map.copyright || '', icp: map.icp || '' });
} catch { res.json({ copyright: '', icp: '' }); }
});
// 公开: 读取站点配置的皮肤站地址(玩家绑定身份时自动带出)
router.get('/skin-site', async (req, res) => {
try {