优化安全策略

This commit is contained in:
CN-JS-HuiBai
2026-04-10 21:58:42 +08:00
parent 90634dfacf
commit 66b5702d03
2 changed files with 71 additions and 15 deletions

View File

@@ -427,6 +427,7 @@
<div class="modal-tabs">
<button class="modal-tab active" data-tab="prom">数据源管理</button>
<button class="modal-tab" data-tab="site">大屏设置</button>
<button class="modal-tab" data-tab="security">安全设置</button>
<button class="modal-tab" data-tab="latency">延迟线路管理</button>
<button class="modal-tab" data-tab="auth">账号安全</button>
</div>
@@ -507,15 +508,6 @@
<option value="0">隐藏 (Hide)</option>
</select>
</div>
<div class="form-group" style="margin-top: 15px;">
<label for="requireLoginForServerDetailsInput">服务器详情是否仅登录后可查看</label>
<select id="requireLoginForServerDetailsInput"
style="padding: 10px 14px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary); width: 100%;">
<option value="1">仅登录后可查看</option>
<option value="0">允许公开查看</option>
</select>
<p style="font-size: 0.72rem; color: var(--text-muted); margin-top: 6px;">开启后,未登录访客仍可看到大屏总览,但点击单台服务器时需要先登录。</p>
</div>
<div class="form-group" style="margin-top: 15px;">
<label for="logoUrlInput">Logo URL (白天/默认,支持图片链接)</label>
<input type="url" id="logoUrlInput" placeholder="https://example.com/logo_light.png">
@@ -574,6 +566,26 @@
</div>
<small style="display: block; margin-top: 6px; color: var(--text-muted);">选择参与 24 小时网络流量统计的 Prometheus 数据源。如果不勾选任何项,则统计所有数据源。</small>
</div>
<div class="form-actions" style="margin-top: 25px; display: flex; justify-content: flex-end;">
<button class="btn btn-add" id="btnSaveSiteSettings">保存基础设置</button>
</div>
<div class="form-message" id="siteSettingsMessage"></div>
</div>
</div>
<!-- Security Settings Tab -->
<div class="tab-content" id="tab-security">
<div class="security-settings-form">
<h3>安全与隐私设置</h3>
<div class="form-group" style="margin-top: 15px;">
<label for="requireLoginForServerDetailsInput">服务器详情是否仅登录后可查看</label>
<select id="requireLoginForServerDetailsInput"
style="padding: 10px 14px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary); width: 100%;">
<option value="1">仅登录后可查看</option>
<option value="0">允许公开查看</option>
</select>
<p style="font-size: 0.72rem; color: var(--text-muted); margin-top: 6px;">开启后,未登录访客仍可看到大屏总览,但点击单台服务器时需要先登录。</p>
</div>
<div class="form-group" style="margin-top: 15px;">
<label for="showServerIpInput">服务器详情内是否显示 IPv4 和 IPv6 地址</label>
<select id="showServerIpInput"
@@ -584,7 +596,7 @@
<p style="font-size: 0.72rem; color: var(--text-muted); margin-top: 6px;">开启后,点击服务器详情时会显示该服务器的公网 IP 地址(需 node_exporter 提供支持)。</p>
</div>
<div class="form-actions" style="margin-top: 25px; display: flex; justify-content: flex-end;">
<button class="btn btn-add" id="btnSaveSiteSettings">保存基础设置</button>
<button class="btn btn-add" id="btnSaveSecuritySettings">保存安全设置</button>
</div>
<div class="form-message" id="siteSettingsMessage"></div>
</div>

View File

@@ -52,6 +52,7 @@
siteTitleInput: document.getElementById('siteTitleInput'),
logoUrlInput: document.getElementById('logoUrlInput'),
btnSaveSiteSettings: document.getElementById('btnSaveSiteSettings'),
btnSaveSecuritySettings: document.getElementById('btnSaveSecuritySettings'),
siteSettingsMessage: document.getElementById('siteSettingsMessage'),
logoText: document.getElementById('logoText'),
logoIconContainer: document.getElementById('logoIconContainer'),
@@ -541,11 +542,23 @@
if (dom.logoUrlDarkInput) dom.logoUrlDarkInput.value = window.SITE_SETTINGS.logo_url_dark || '';
if (dom.faviconUrlInput) dom.faviconUrlInput.value = window.SITE_SETTINGS.favicon_url || '';
if (dom.showServerIpInput) dom.showServerIpInput.value = window.SITE_SETTINGS.show_server_ip ? "1" : "0";
// Latency routes loaded separately in openSettings or on startup
// Apply security dependency
updateSecurityDependency();
}
loadSiteSettings();
// Bind save button for security tab
if (dom.btnSaveSecuritySettings) {
dom.btnSaveSecuritySettings.addEventListener('click', saveSiteSettings);
}
// Security dependency listener
if (dom.requireLoginForServerDetailsInput) {
dom.requireLoginForServerDetailsInput.addEventListener('change', updateSecurityDependency);
}
// Track intervals for resource management
initWebSocket();
backgroundIntervals.push(setInterval(fetchNetworkHistory, NETWORK_HISTORY_INTERVAL));
@@ -1978,6 +1991,12 @@
}
};
siteThemeQuery.addEventListener('change', siteThemeHandler);
// Update IP visibility input
if (dom.showServerIpInput) dom.showServerIpInput.value = settings.show_server_ip ? "1" : "0";
// Sync security tab dependency
updateSecurityDependency();
} catch (err) {
console.error('Error loading site settings:', err);
}
@@ -2096,8 +2115,13 @@
show_server_ip: dom.showServerIpInput ? (dom.showServerIpInput.value === "1") : false
};
dom.btnSaveSiteSettings.disabled = true;
dom.btnSaveSiteSettings.textContent = '保存中...';
// UI Feedback for both potential save buttons
const saveButtons = [dom.btnSaveSiteSettings, dom.btnSaveSecuritySettings].filter(b => b);
saveButtons.forEach(btn => {
btn.disabled = true;
btn.originalText = btn.textContent;
btn.textContent = '保存中...';
});
try {
const response = await fetch('/api/settings', {
@@ -2134,8 +2158,28 @@
showSiteMessage(`保存失败: ${err.message}`, 'error');
console.error('Save settings error:', err);
} finally {
dom.btnSaveSiteSettings.disabled = false;
dom.btnSaveSiteSettings.textContent = '保存设置';
saveButtons.forEach(btn => {
btn.disabled = false;
btn.textContent = btn.originalText || '保存设置';
});
}
}
function updateSecurityDependency() {
if (!dom.requireLoginForServerDetailsInput || !dom.showServerIpInput) return;
const requireLogin = dom.requireLoginForServerDetailsInput.value === "1";
if (!requireLogin) {
// If public access is allowed, force hide IP and disable the toggle
dom.showServerIpInput.value = "0";
dom.showServerIpInput.disabled = true;
dom.showServerIpInput.style.opacity = "0.6";
dom.showServerIpInput.parentElement.style.opacity = "0.7";
} else {
// Re-enable when login is required
dom.showServerIpInput.disabled = false;
dom.showServerIpInput.style.opacity = "1";
dom.showServerIpInput.parentElement.style.opacity = "1";
}
}