Initial commit — SETEC LABS Manager (Setec_CDM)
Flask-based VPS management panel with SSH remote command execution. Includes E2E encrypted SSH tunnel (AES-256-GCM + Go agent), setup wizard, security hardening tools, DNS management, firewall configs, monitoring, backup, and .sec patch update system. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
168
setec-web/templates/fail2ban.html
Normal file
168
setec-web/templates/fail2ban.html
Normal file
@@ -0,0 +1,168 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Fail2Ban{% endblock %}
|
||||
{% block content %}
|
||||
<h1>[!] Fail2Ban</h1>
|
||||
|
||||
<div class="toolbar">
|
||||
<button class="btn" onclick="loadStatus()">Refresh</button>
|
||||
<button class="btn" onclick="loadAllJails()">All Jails Detail</button>
|
||||
<button class="btn" onclick="loadLog()">View Log</button>
|
||||
<button class="btn" onclick="loadConfig()">Edit Config</button>
|
||||
<button class="btn btn-warn" onclick="reloadF2B()">Reload</button>
|
||||
<button class="btn btn-danger" onclick="unbanAll()">Unban All</button>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-2">
|
||||
<div class="card">
|
||||
<div class="card-title">Status</div>
|
||||
<div class="output" id="status-output"><span class="info">Loading...</span></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-title">Jail Details</div>
|
||||
<div class="toolbar">
|
||||
<select id="jail-select" onchange="loadJail()">
|
||||
<option value="">-- select jail --</option>
|
||||
<option value="sshd">sshd</option>
|
||||
<option value="nginx-http-auth">nginx-http-auth</option>
|
||||
<option value="nginx-botsearch">nginx-botsearch</option>
|
||||
<option value="nginx-badbots">nginx-badbots</option>
|
||||
<option value="postfix">postfix</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="output" id="jail-output"><span class="info">Select a jail</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-2">
|
||||
<div class="card">
|
||||
<div class="card-title">Ban IP</div>
|
||||
<label>Jail</label>
|
||||
<select id="ban-jail">
|
||||
<option value="sshd">sshd</option>
|
||||
<option value="nginx-http-auth">nginx-http-auth</option>
|
||||
<option value="nginx-botsearch">nginx-botsearch</option>
|
||||
<option value="nginx-badbots">nginx-badbots</option>
|
||||
<option value="postfix">postfix</option>
|
||||
</select>
|
||||
<label>IP Address</label>
|
||||
<input type="text" id="ban-ip" placeholder="1.2.3.4" style="width:200px">
|
||||
<br><br>
|
||||
<button class="btn btn-danger" onclick="banIP()">Ban</button>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-title">Unban IP</div>
|
||||
<label>Jail</label>
|
||||
<select id="unban-jail">
|
||||
<option value="sshd">sshd</option>
|
||||
<option value="nginx-http-auth">nginx-http-auth</option>
|
||||
<option value="nginx-botsearch">nginx-botsearch</option>
|
||||
<option value="nginx-badbots">nginx-badbots</option>
|
||||
<option value="postfix">postfix</option>
|
||||
</select>
|
||||
<label>IP Address</label>
|
||||
<input type="text" id="unban-ip" placeholder="1.2.3.4" style="width:200px">
|
||||
<br><br>
|
||||
<button class="btn" onclick="unbanIP()">Unban</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" id="config-card" style="display:none">
|
||||
<div class="card-title">jail.local</div>
|
||||
<textarea id="config-editor" rows="20" style="width:100%;tab-size:4" spellcheck="false"></textarea>
|
||||
<br>
|
||||
<button class="btn" onclick="saveConfig()">Save & Reload</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-title">Output / Log</div>
|
||||
<div class="output" id="output" style="max-height:500px"><span class="info">Ready.</span></div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
async function loadStatus() {
|
||||
const res = await apiGet('/api/fail2ban/status');
|
||||
showResult(res, 'status-output');
|
||||
}
|
||||
|
||||
async function loadJail() {
|
||||
const name = document.getElementById('jail-select').value;
|
||||
if (!name) return;
|
||||
const res = await apiGet('/api/fail2ban/jail/' + name);
|
||||
showResult(res, 'jail-output');
|
||||
}
|
||||
|
||||
async function loadAllJails() {
|
||||
const res = await apiGet('/api/fail2ban/jails');
|
||||
showResult(res);
|
||||
}
|
||||
|
||||
async function banIP() {
|
||||
const jail = document.getElementById('ban-jail').value;
|
||||
const ip = document.getElementById('ban-ip').value.trim();
|
||||
if (!ip) { alert('Enter an IP'); return; }
|
||||
const res = await apiPost('/api/fail2ban/ban', {jail, ip});
|
||||
showResult(res);
|
||||
loadJail();
|
||||
}
|
||||
|
||||
async function unbanIP() {
|
||||
const jail = document.getElementById('unban-jail').value;
|
||||
const ip = document.getElementById('unban-ip').value.trim();
|
||||
if (!ip) { alert('Enter an IP'); return; }
|
||||
const res = await apiPost('/api/fail2ban/unban', {jail, ip});
|
||||
showResult(res);
|
||||
loadJail();
|
||||
}
|
||||
|
||||
async function unbanAll() {
|
||||
if (!confirm('Unban ALL IPs from ALL jails?')) return;
|
||||
const res = await apiPost('/api/fail2ban/unban-all');
|
||||
showResult(res);
|
||||
loadStatus();
|
||||
}
|
||||
|
||||
async function reloadF2B() {
|
||||
const res = await apiPost('/api/fail2ban/reload');
|
||||
showResult(res);
|
||||
loadStatus();
|
||||
}
|
||||
|
||||
async function loadLog() {
|
||||
const res = await apiGet('/api/fail2ban/log?lines=50');
|
||||
showResult(res);
|
||||
}
|
||||
|
||||
async function loadConfig() {
|
||||
document.getElementById('config-card').style.display = '';
|
||||
const res = await apiGet('/api/fail2ban/config');
|
||||
if (res.ok) {
|
||||
document.getElementById('config-editor').value = res.data.stdout || '';
|
||||
}
|
||||
}
|
||||
|
||||
async function saveConfig() {
|
||||
const content = document.getElementById('config-editor').value;
|
||||
if (!confirm('Save config and reload fail2ban?')) return;
|
||||
const res = await apiPost('/api/fail2ban/config/save', {content});
|
||||
showResult(res);
|
||||
loadStatus();
|
||||
}
|
||||
|
||||
document.getElementById('config-editor').addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Tab') {
|
||||
e.preventDefault();
|
||||
const s = this.selectionStart;
|
||||
this.value = this.value.substring(0, s) + ' ' + this.value.substring(this.selectionEnd);
|
||||
this.selectionStart = this.selectionEnd = s + 4;
|
||||
}
|
||||
if (e.key === 's' && (e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
saveConfig();
|
||||
}
|
||||
});
|
||||
|
||||
loadStatus();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user