mirror of
https://github.com/swissmakers/fail2ban-ui.git
synced 2026-04-11 13:47:05 +02:00
Add global threat map to the ban insights modal for better overview from where the most bans are (red pier)
This commit is contained in:
@@ -102,6 +102,9 @@
|
||||
"logs.modal.total_week_note": "Aktivität der letzten Woche",
|
||||
"logs.modal.insights_recurring": "Wiederkehrende IPs",
|
||||
"logs.modal.insights_recurring_empty": "Keine wiederkehrenden IPs erkannt.",
|
||||
"logs.modal.threat_map_title": "Globale Bedrohungskarte",
|
||||
"logs.modal.threat_map_hint": "Ziehen zum Drehen, Scrollen zum Zoomen.",
|
||||
"logs.modal.threat_map_empty": "Keine Geodaten verfügbar.",
|
||||
"filter_debug.title": "Filter-Debug",
|
||||
"filter_debug.select_filter": "Wählen Sie einen Filter",
|
||||
"filter_debug.filter_content": "Filter-Inhalt",
|
||||
|
||||
@@ -102,6 +102,9 @@
|
||||
"logs.modal.total_week_note": "Aktivität vor letschte Wuche",
|
||||
"logs.modal.insights_recurring": "Wiederkehrendi IPs",
|
||||
"logs.modal.insights_recurring_empty": "Ke wiederkehrendi IPs erkannt.",
|
||||
"logs.modal.threat_map_title": "Globali Bedrohigscharte",
|
||||
"logs.modal.threat_map_hint": "Zieh zum Dräie, Scroll zum Zoomä.",
|
||||
"logs.modal.threat_map_empty": "Ke Geodate verfüegbar.",
|
||||
"filter_debug.title": "Filter Debug",
|
||||
"filter_debug.select_filter": "Wähl ä Filter us",
|
||||
"filter_debug.filter_content": "Filter-Inhalt",
|
||||
|
||||
@@ -102,6 +102,9 @@
|
||||
"logs.modal.total_week_note": "Weekly activity",
|
||||
"logs.modal.insights_recurring": "Recurring IPs",
|
||||
"logs.modal.insights_recurring_empty": "No recurring IPs detected.",
|
||||
"logs.modal.threat_map_title": "Global Threat Map",
|
||||
"logs.modal.threat_map_hint": "Drag to rotate, scroll to zoom.",
|
||||
"logs.modal.threat_map_empty": "No geo data available.",
|
||||
"filter_debug.title": "Filter Debug",
|
||||
"filter_debug.select_filter": "Select a Filter",
|
||||
"filter_debug.filter_content": "Filter Content",
|
||||
|
||||
@@ -102,6 +102,9 @@
|
||||
"logs.modal.total_week_note": "Actividad semanal",
|
||||
"logs.modal.insights_recurring": "IPs recurrentes",
|
||||
"logs.modal.insights_recurring_empty": "No se detectaron IPs recurrentes.",
|
||||
"logs.modal.threat_map_title": "Mapa global de amenazas",
|
||||
"logs.modal.threat_map_hint": "Arrastrar para girar, desplazar para hacer zoom.",
|
||||
"logs.modal.threat_map_empty": "No hay datos geográficos disponibles.",
|
||||
"filter_debug.title": "Depuración de filtros",
|
||||
"filter_debug.select_filter": "Selecciona un filtro",
|
||||
"filter_debug.filter_content": "Contenido del filtro",
|
||||
|
||||
@@ -102,6 +102,9 @@
|
||||
"logs.modal.total_week_note": "Activité hebdomadaire",
|
||||
"logs.modal.insights_recurring": "IPs récurrentes",
|
||||
"logs.modal.insights_recurring_empty": "Aucune IP récurrente détectée.",
|
||||
"logs.modal.threat_map_title": "Carte mondiale des menaces",
|
||||
"logs.modal.threat_map_hint": "Glisser pour tourner, défiler pour zoomer.",
|
||||
"logs.modal.threat_map_empty": "Aucune donnée géographique disponible.",
|
||||
"filter_debug.title": "Débogage des filtres",
|
||||
"filter_debug.select_filter": "Sélectionnez un filtre",
|
||||
"filter_debug.filter_content": "Contenu du filtre",
|
||||
|
||||
@@ -102,6 +102,9 @@
|
||||
"logs.modal.total_week_note": "Attività settimanale",
|
||||
"logs.modal.insights_recurring": "IP ricorrenti",
|
||||
"logs.modal.insights_recurring_empty": "Nessun IP ricorrente rilevato.",
|
||||
"logs.modal.threat_map_title": "Mappa globale delle minacce",
|
||||
"logs.modal.threat_map_hint": "Trascinare per ruotare, scorrere per zoomare.",
|
||||
"logs.modal.threat_map_empty": "Nessun dato geografico disponibile.",
|
||||
"filter_debug.title": "Debug Filtro",
|
||||
"filter_debug.select_filter": "Seleziona un filtro",
|
||||
"filter_debug.filter_content": "Contenuto del filtro",
|
||||
|
||||
208
pkg/web/static/js/globe.js
Normal file
208
pkg/web/static/js/globe.js
Normal file
@@ -0,0 +1,208 @@
|
||||
// 3D threat globe for Ban Insights modal.
|
||||
"use strict";
|
||||
|
||||
// =========================================================================
|
||||
// Country Coordinates (ISO 3166-1 alpha-2 -> lat/lng)
|
||||
// =========================================================================
|
||||
|
||||
var COUNTRY_COORDS = {
|
||||
AF:{lat:33.94,lng:67.71},AL:{lat:41.15,lng:20.17},DZ:{lat:28.03,lng:1.66},
|
||||
AS:{lat:-14.27,lng:-170.13},AD:{lat:42.55,lng:1.6},AO:{lat:-11.2,lng:17.87},
|
||||
AG:{lat:17.06,lng:-61.8},AR:{lat:-38.42,lng:-63.62},AM:{lat:40.07,lng:45.04},
|
||||
AU:{lat:-25.27,lng:133.78},AT:{lat:47.52,lng:14.55},AZ:{lat:40.14,lng:47.58},
|
||||
BS:{lat:25.03,lng:-77.4},BH:{lat:26.07,lng:50.56},BD:{lat:23.68,lng:90.36},
|
||||
BB:{lat:13.19,lng:-59.54},BY:{lat:53.71,lng:27.95},BE:{lat:50.5,lng:4.47},
|
||||
BZ:{lat:17.19,lng:-88.5},BJ:{lat:9.31,lng:2.32},BT:{lat:27.51,lng:90.43},
|
||||
BO:{lat:-16.29,lng:-63.59},BA:{lat:43.92,lng:17.68},BW:{lat:-22.33,lng:24.68},
|
||||
BR:{lat:-14.24,lng:-51.93},BN:{lat:4.54,lng:114.73},BG:{lat:42.73,lng:25.49},
|
||||
BF:{lat:12.24,lng:-1.56},BI:{lat:-3.37,lng:29.92},KH:{lat:12.57,lng:104.99},
|
||||
CM:{lat:7.37,lng:12.35},CA:{lat:56.13,lng:-106.35},CV:{lat:16.0,lng:-24.01},
|
||||
CF:{lat:6.61,lng:20.94},TD:{lat:15.45,lng:18.73},CL:{lat:-35.68,lng:-71.54},
|
||||
CN:{lat:35.86,lng:104.2},CO:{lat:4.57,lng:-74.3},KM:{lat:-11.88,lng:43.87},
|
||||
CG:{lat:-0.23,lng:15.83},CD:{lat:-4.04,lng:21.76},CR:{lat:9.75,lng:-83.75},
|
||||
CI:{lat:7.54,lng:-5.55},HR:{lat:45.1,lng:15.2},CU:{lat:21.52,lng:-77.78},
|
||||
CY:{lat:35.13,lng:33.43},CZ:{lat:49.82,lng:15.47},DK:{lat:56.26,lng:9.5},
|
||||
DJ:{lat:11.83,lng:42.59},DM:{lat:15.41,lng:-61.37},DO:{lat:18.74,lng:-70.16},
|
||||
EC:{lat:-1.83,lng:-78.18},EG:{lat:26.82,lng:30.8},SV:{lat:13.79,lng:-88.9},
|
||||
GQ:{lat:1.65,lng:10.27},ER:{lat:15.18,lng:39.78},EE:{lat:58.6,lng:25.01},
|
||||
ET:{lat:9.15,lng:40.49},FJ:{lat:-17.71,lng:178.07},FI:{lat:61.92,lng:25.75},
|
||||
FR:{lat:46.23,lng:2.21},GA:{lat:-0.8,lng:11.61},GM:{lat:13.44,lng:-15.31},
|
||||
GE:{lat:42.32,lng:43.36},DE:{lat:51.17,lng:10.45},GH:{lat:7.95,lng:-1.02},
|
||||
GR:{lat:39.07,lng:21.82},GD:{lat:12.12,lng:-61.68},GT:{lat:15.78,lng:-90.23},
|
||||
GN:{lat:9.95,lng:-9.7},GW:{lat:11.8,lng:-15.18},GY:{lat:4.86,lng:-58.93},
|
||||
HT:{lat:18.97,lng:-72.29},HN:{lat:15.2,lng:-86.24},HU:{lat:47.16,lng:19.5},
|
||||
IS:{lat:64.96,lng:-19.02},IN:{lat:20.59,lng:78.96},ID:{lat:-0.79,lng:113.92},
|
||||
IR:{lat:32.43,lng:53.69},IQ:{lat:33.22,lng:43.68},IE:{lat:53.41,lng:-8.24},
|
||||
IL:{lat:31.05,lng:34.85},IT:{lat:41.87,lng:12.57},JM:{lat:18.11,lng:-77.3},
|
||||
JP:{lat:36.2,lng:138.25},JO:{lat:30.59,lng:36.24},KZ:{lat:48.02,lng:66.92},
|
||||
KE:{lat:-0.02,lng:37.91},KI:{lat:-3.37,lng:-168.73},KP:{lat:40.34,lng:127.51},
|
||||
KR:{lat:35.91,lng:127.77},KW:{lat:29.31,lng:47.48},KG:{lat:41.2,lng:74.77},
|
||||
LA:{lat:19.86,lng:102.5},LV:{lat:56.88,lng:24.6},LB:{lat:33.85,lng:35.86},
|
||||
LS:{lat:-29.61,lng:28.23},LR:{lat:6.43,lng:-9.43},LY:{lat:26.34,lng:17.23},
|
||||
LI:{lat:47.17,lng:9.56},LT:{lat:55.17,lng:23.88},LU:{lat:49.82,lng:6.13},
|
||||
MK:{lat:41.51,lng:21.75},MG:{lat:-18.77,lng:46.87},MW:{lat:-13.25,lng:34.3},
|
||||
MY:{lat:4.21,lng:101.98},MV:{lat:3.2,lng:73.22},ML:{lat:17.57,lng:-4.0},
|
||||
MT:{lat:35.94,lng:14.38},MH:{lat:7.13,lng:171.18},MR:{lat:21.01,lng:-10.94},
|
||||
MU:{lat:-20.35,lng:57.55},MX:{lat:23.63,lng:-102.55},FM:{lat:7.43,lng:150.55},
|
||||
MD:{lat:47.41,lng:28.37},MC:{lat:43.75,lng:7.41},MN:{lat:46.86,lng:103.85},
|
||||
ME:{lat:42.71,lng:19.37},MA:{lat:31.79,lng:-7.09},MZ:{lat:-18.67,lng:35.53},
|
||||
MM:{lat:21.91,lng:95.96},NA:{lat:-22.96,lng:18.49},NR:{lat:-0.52,lng:166.93},
|
||||
NP:{lat:28.39,lng:84.12},NL:{lat:52.13,lng:5.29},NZ:{lat:-40.9,lng:174.89},
|
||||
NI:{lat:12.87,lng:-85.21},NE:{lat:17.61,lng:8.08},NG:{lat:9.08,lng:8.68},
|
||||
NO:{lat:60.47,lng:8.47},OM:{lat:21.47,lng:55.98},PK:{lat:30.38,lng:69.35},
|
||||
PW:{lat:7.51,lng:134.58},PA:{lat:8.54,lng:-80.78},PG:{lat:-6.31,lng:143.96},
|
||||
PY:{lat:-23.44,lng:-58.44},PE:{lat:-9.19,lng:-75.02},PH:{lat:12.88,lng:121.77},
|
||||
PL:{lat:51.92,lng:19.15},PT:{lat:39.4,lng:-8.22},QA:{lat:25.35,lng:51.18},
|
||||
RO:{lat:45.94,lng:24.97},RU:{lat:61.52,lng:105.32},RW:{lat:-1.94,lng:29.87},
|
||||
KN:{lat:17.36,lng:-62.78},LC:{lat:13.91,lng:-60.98},VC:{lat:12.98,lng:-61.29},
|
||||
WS:{lat:-13.76,lng:-172.1},SM:{lat:43.94,lng:12.46},ST:{lat:0.19,lng:6.61},
|
||||
SA:{lat:23.89,lng:45.08},SN:{lat:14.5,lng:-14.45},RS:{lat:44.02,lng:21.01},
|
||||
SC:{lat:-4.68,lng:55.49},SL:{lat:8.46,lng:-11.78},SG:{lat:1.35,lng:103.82},
|
||||
SK:{lat:48.67,lng:19.7},SI:{lat:46.15,lng:14.99},SB:{lat:-9.65,lng:160.16},
|
||||
SO:{lat:5.15,lng:46.2},ZA:{lat:-30.56,lng:22.94},SS:{lat:6.88,lng:31.31},
|
||||
ES:{lat:40.46,lng:-3.75},LK:{lat:7.87,lng:80.77},SD:{lat:12.86,lng:30.22},
|
||||
SR:{lat:3.92,lng:-56.03},SZ:{lat:-26.52,lng:31.47},SE:{lat:60.13,lng:18.64},
|
||||
CH:{lat:46.82,lng:8.23},SY:{lat:34.8,lng:38.99},TW:{lat:23.7,lng:120.96},
|
||||
TJ:{lat:38.86,lng:71.28},TZ:{lat:-6.37,lng:34.89},TH:{lat:15.87,lng:100.99},
|
||||
TL:{lat:-8.87,lng:125.73},TG:{lat:8.62,lng:1.21},TO:{lat:-21.18,lng:-175.2},
|
||||
TT:{lat:10.69,lng:-61.22},TN:{lat:33.89,lng:9.54},TR:{lat:38.96,lng:35.24},
|
||||
TM:{lat:38.97,lng:59.56},TV:{lat:-7.11,lng:177.65},UG:{lat:1.37,lng:32.29},
|
||||
UA:{lat:48.38,lng:31.17},AE:{lat:23.42,lng:53.85},GB:{lat:55.38,lng:-3.44},
|
||||
US:{lat:37.09,lng:-95.71},UY:{lat:-32.52,lng:-55.77},UZ:{lat:41.38,lng:64.59},
|
||||
VU:{lat:-15.38,lng:166.96},VE:{lat:6.42,lng:-66.59},VN:{lat:14.06,lng:108.28},
|
||||
YE:{lat:15.55,lng:48.52},ZM:{lat:-13.13,lng:27.85},ZW:{lat:-19.02,lng:29.15},
|
||||
PS:{lat:31.95,lng:35.23},HK:{lat:22.4,lng:114.11},XK:{lat:42.6,lng:20.9},
|
||||
PR:{lat:18.22,lng:-66.59},RE:{lat:-21.12,lng:55.54},GP:{lat:16.27,lng:-61.55},
|
||||
MQ:{lat:14.64,lng:-61.02},GF:{lat:3.93,lng:-53.13},YT:{lat:-12.83,lng:45.17},
|
||||
NC:{lat:-20.9,lng:165.62},PF:{lat:-17.68,lng:-149.41},CW:{lat:12.17,lng:-68.98},
|
||||
SX:{lat:18.04,lng:-63.05},AW:{lat:12.51,lng:-69.97}
|
||||
};
|
||||
|
||||
// =========================================================================
|
||||
// Globe State
|
||||
// =========================================================================
|
||||
|
||||
var _globeInstance = null;
|
||||
var _globeResizeObserver = null;
|
||||
|
||||
// =========================================================================
|
||||
// Color Helper
|
||||
// =========================================================================
|
||||
|
||||
// Returns an rgba string interpolating from blue (low) to red (high).
|
||||
function _threatColor(ratio) {
|
||||
var r = Math.round(30 + 225 * ratio);
|
||||
var g = Math.round(100 * (1 - ratio));
|
||||
var b = Math.round(220 * (1 - ratio));
|
||||
return 'rgba(' + r + ',' + g + ',' + b + ',0.9)';
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Render
|
||||
// =========================================================================
|
||||
|
||||
function renderInsightsGlobe() {
|
||||
if (typeof Globe === 'undefined') return;
|
||||
|
||||
var container = document.getElementById('insightsGlobe');
|
||||
if (!container) return;
|
||||
|
||||
destroyInsightsGlobe();
|
||||
|
||||
var countries = (latestBanInsights && latestBanInsights.countries) || [];
|
||||
if (!countries.length) {
|
||||
var emptyMsg = (translations && translations['logs.modal.threat_map_empty']) || 'No geo data available.';
|
||||
container.innerHTML = '<p class="text-sm text-gray-400 text-center py-16">' + escapeHtml(emptyMsg) + '</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
var maxCount = 1;
|
||||
countries.forEach(function(s) {
|
||||
if (s.count > maxCount) maxCount = s.count;
|
||||
});
|
||||
|
||||
var points = [];
|
||||
countries.forEach(function(s) {
|
||||
var code = (s.country || '').toUpperCase();
|
||||
var coords = COUNTRY_COORDS[code];
|
||||
if (!coords) return;
|
||||
var ratio = Math.min(s.count / maxCount, 1);
|
||||
points.push({
|
||||
lat: coords.lat,
|
||||
lng: coords.lng,
|
||||
alt: 0.06 + 0.7 * ratio,
|
||||
radius: 0.4 + 0.6 * ratio,
|
||||
color: _threatColor(ratio),
|
||||
label: '<div style="padding:6px 10px;background:rgba(15,23,42,0.92);color:#f1f5f9;' +
|
||||
'border-radius:6px;font-size:13px;line-height:1.4;pointer-events:none;">' +
|
||||
'<b>' + escapeHtml(s.country || '??') + '</b><br>' +
|
||||
formatNumber(s.count) + ' ban' + (s.count !== 1 ? 's' : '') + '</div>',
|
||||
country: s.country,
|
||||
count: s.count
|
||||
});
|
||||
});
|
||||
|
||||
var width = container.clientWidth || 600;
|
||||
var height = container.clientHeight || 420;
|
||||
|
||||
var globe = Globe()
|
||||
.width(width)
|
||||
.height(height)
|
||||
.backgroundColor('rgba(0,0,0,0)')
|
||||
.showAtmosphere(true)
|
||||
.atmosphereColor('#3b82f6')
|
||||
.atmosphereAltitude(0.15)
|
||||
.globeImageUrl('//unpkg.com/three-globe/example/img/earth-night.jpg')
|
||||
.pointsData(points)
|
||||
.pointLat('lat')
|
||||
.pointLng('lng')
|
||||
.pointAltitude('alt')
|
||||
.pointRadius('radius')
|
||||
.pointColor('color')
|
||||
.pointLabel('label')
|
||||
.pointsMerge(false)
|
||||
(container);
|
||||
|
||||
globe.pointOfView({ lat: 30, lng: 10, altitude: 2.2 });
|
||||
|
||||
var controls = globe.controls();
|
||||
if (controls) {
|
||||
controls.autoRotate = true;
|
||||
controls.autoRotateSpeed = 0.4;
|
||||
controls.enableZoom = true;
|
||||
controls.minDistance = 120;
|
||||
controls.maxDistance = 500;
|
||||
}
|
||||
|
||||
_globeInstance = globe;
|
||||
|
||||
_globeResizeObserver = new ResizeObserver(function(entries) {
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
var rect = entries[i].contentRect;
|
||||
if (_globeInstance && rect.width > 0 && rect.height > 0) {
|
||||
_globeInstance.width(rect.width).height(rect.height);
|
||||
}
|
||||
}
|
||||
});
|
||||
_globeResizeObserver.observe(container);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Cleanup Globe
|
||||
// =========================================================================
|
||||
|
||||
function destroyInsightsGlobe() {
|
||||
if (_globeResizeObserver) {
|
||||
_globeResizeObserver.disconnect();
|
||||
_globeResizeObserver = null;
|
||||
}
|
||||
if (_globeInstance) {
|
||||
_globeInstance.pauseAnimation();
|
||||
_globeInstance._destructor && _globeInstance._destructor();
|
||||
_globeInstance = null;
|
||||
}
|
||||
var container = document.getElementById('insightsGlobe');
|
||||
if (container) {
|
||||
container.innerHTML = '';
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,9 @@ function closeModal(modalId) {
|
||||
if (!modal || modal.classList.contains('hidden')) {
|
||||
return;
|
||||
}
|
||||
if (modalId === 'banInsightsModal' && typeof destroyInsightsGlobe === 'function') {
|
||||
destroyInsightsGlobe();
|
||||
}
|
||||
modal.classList.add('hidden');
|
||||
openModalCount = Math.max(0, openModalCount - 1);
|
||||
updateBodyScrollLock();
|
||||
@@ -186,6 +189,9 @@ function openBanInsightsModal() {
|
||||
updateTranslations();
|
||||
}
|
||||
openModal('banInsightsModal');
|
||||
if (typeof renderInsightsGlobe === 'function') {
|
||||
setTimeout(renderInsightsGlobe, 150);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
||||
1
pkg/web/static/vendor/globe/countries-110m.json
vendored
Normal file
1
pkg/web/static/vendor/globe/countries-110m.json
vendored
Normal file
File diff suppressed because one or more lines are too long
20
pkg/web/static/vendor/globe/globe.gl.min.js
vendored
Normal file
20
pkg/web/static/vendor/globe/globe.gl.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1412,6 +1412,16 @@
|
||||
<div id="recurringIPsContainer" class="space-y-4 max-h-96 overflow-y-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-6 border border-gray-200 rounded-lg p-4 bg-gray-50">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div>
|
||||
<h4 class="text-base font-semibold text-gray-900" data-i18n="logs.modal.threat_map_title">Global Threat Map</h4>
|
||||
<p class="text-xs text-gray-500 mt-1" data-i18n="logs.modal.threat_map_hint">Drag to rotate, scroll to zoom.</p>
|
||||
</div>
|
||||
<span class="inline-flex items-center rounded-full bg-emerald-100 px-3 py-1 text-xs font-medium text-emerald-700">3D</span>
|
||||
</div>
|
||||
<div id="insightsGlobe" class="w-full flex justify-center overflow-hidden rounded-lg" style="height:420px; background:#0a1628;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1470,6 +1480,7 @@
|
||||
<!-- ******************************************************************* -->
|
||||
<script src="/static/vendor/jquery/jquery-3.6.0.min.js?v={{.version}}"></script>
|
||||
<script src="/static/vendor/select2/select2.min.js?v={{.version}}"></script>
|
||||
<script src="/static/vendor/globe/globe.gl.min.js?v={{.version}}"></script>
|
||||
<script src="/static/js/globals.js?v={{.version}}"></script>
|
||||
<script src="/static/js/core.js?v={{.version}}"></script>
|
||||
<script src="/static/js/api.js?v={{.version}}"></script>
|
||||
@@ -1479,6 +1490,7 @@
|
||||
<script src="/static/js/translations.js?v={{.version}}"></script>
|
||||
<script src="/static/js/ignoreips.js?v={{.version}}"></script>
|
||||
<script src="/static/js/dashboard.js?v={{.version}}"></script>
|
||||
<script src="/static/js/globe.js?v={{.version}}"></script>
|
||||
<script src="/static/js/servers.js?v={{.version}}"></script>
|
||||
<script src="/static/js/jails.js?v={{.version}}"></script>
|
||||
<script src="/static/js/console.js?v={{.version}}"></script>
|
||||
|
||||
Reference in New Issue
Block a user