feat: security panel - recent blocks table + top attacked paths
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Added to GeoIP tab: - Last 20 blocked requests with IP, country, path, timestamp - Top 10 most targeted URL paths with hit counts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5030b71beb
commit
7073a56dc3
@ -140,6 +140,33 @@ def admin_security():
|
|||||||
'code': code, 'flag': flag, 'name': name, 'count': count
|
'code': code, 'flag': flag, 'name': name, 'count': count
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Recent geo blocks (last 20) with details
|
||||||
|
recent_geo_blocks = []
|
||||||
|
top_paths = []
|
||||||
|
if geoip_enabled:
|
||||||
|
recent_blocks = db.query(SecurityAlert).filter(
|
||||||
|
SecurityAlert.alert_type == 'geo_blocked'
|
||||||
|
).order_by(desc(SecurityAlert.created_at)).limit(20).all()
|
||||||
|
|
||||||
|
for b in recent_blocks:
|
||||||
|
country_code = b.details.get('country', '??') if b.details else '??'
|
||||||
|
flag, name = country_flags.get(country_code, ('🏴', country_code))
|
||||||
|
recent_geo_blocks.append({
|
||||||
|
'ip': b.ip_address,
|
||||||
|
'country_flag': flag,
|
||||||
|
'country_name': name,
|
||||||
|
'path': b.details.get('path', '/') if b.details else '/',
|
||||||
|
'created_at': b.created_at
|
||||||
|
})
|
||||||
|
|
||||||
|
# Top attacked paths
|
||||||
|
path_counts = {}
|
||||||
|
for alert in geo_alerts:
|
||||||
|
if alert.details and 'path' in alert.details:
|
||||||
|
path = alert.details['path']
|
||||||
|
path_counts[path] = path_counts.get(path, 0) + 1
|
||||||
|
top_paths = sorted(path_counts.items(), key=lambda x: x[1], reverse=True)[:10]
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'admin/security_dashboard.html',
|
'admin/security_dashboard.html',
|
||||||
audit_logs=audit_logs,
|
audit_logs=audit_logs,
|
||||||
@ -148,6 +175,8 @@ def admin_security():
|
|||||||
stats=stats,
|
stats=stats,
|
||||||
geoip_enabled=geoip_enabled,
|
geoip_enabled=geoip_enabled,
|
||||||
geoip_stats=geoip_stats,
|
geoip_stats=geoip_stats,
|
||||||
|
recent_geo_blocks=recent_geo_blocks,
|
||||||
|
top_paths=top_paths,
|
||||||
generated_at=datetime.now()
|
generated_at=datetime.now()
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@ -542,6 +542,47 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Top attacked paths -->
|
||||||
|
{% if top_paths %}
|
||||||
|
<h3 style="margin-top: var(--spacing-xl); margin-bottom: var(--spacing-md);">🎯 Najczęściej atakowane ścieżki</h3>
|
||||||
|
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--spacing-sm);">
|
||||||
|
{% for path, count in top_paths %}
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; background: var(--background); border-radius: var(--radius); border: 1px solid var(--border);">
|
||||||
|
<code style="font-size: var(--font-size-sm); color: var(--text-primary); word-break: break-all;">{{ path }}</code>
|
||||||
|
<span style="flex-shrink: 0; margin-left: 10px; background: var(--primary); color: white; font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 10px;">{{ count }}</span>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Recent geo blocks table -->
|
||||||
|
{% if recent_geo_blocks %}
|
||||||
|
<h3 style="margin-top: var(--spacing-xl); margin-bottom: var(--spacing-md);">📋 Ostatnie zablokowane próby</h3>
|
||||||
|
<div style="overflow-x: auto;">
|
||||||
|
<table style="width: 100%; border-collapse: collapse; font-size: var(--font-size-sm);">
|
||||||
|
<thead>
|
||||||
|
<tr style="border-bottom: 2px solid var(--border); text-align: left;">
|
||||||
|
<th style="padding: 10px 12px; color: var(--text-secondary); font-weight: 600;">Data i godzina</th>
|
||||||
|
<th style="padding: 10px 12px; color: var(--text-secondary); font-weight: 600;">IP</th>
|
||||||
|
<th style="padding: 10px 12px; color: var(--text-secondary); font-weight: 600;">Kraj</th>
|
||||||
|
<th style="padding: 10px 12px; color: var(--text-secondary); font-weight: 600;">Ścieżka</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for block in recent_geo_blocks %}
|
||||||
|
<tr style="border-bottom: 1px solid var(--border);">
|
||||||
|
<td style="padding: 8px 12px; white-space: nowrap;">{{ block.created_at.strftime('%d.%m.%Y %H:%M:%S') }}</td>
|
||||||
|
<td style="padding: 8px 12px; font-family: monospace; font-size: 12px;">{{ block.ip }}</td>
|
||||||
|
<td style="padding: 8px 12px;">{{ block.country_flag }} {{ block.country_name }}</td>
|
||||||
|
<td style="padding: 8px 12px;"><code style="background: var(--background); padding: 2px 6px; border-radius: 3px; font-size: 12px;">{{ block.path }}</code></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="empty-state" style="background: #fef3c7; border-radius: var(--radius-lg); padding: var(--spacing-xl);">
|
<div class="empty-state" style="background: #fef3c7; border-radius: var(--radius-lg); padding: var(--spacing-xl);">
|
||||||
<p style="color: #92400e;">⚠️ GeoIP Blocking jest wyłączone</p>
|
<p style="color: #92400e;">⚠️ GeoIP Blocking jest wyłączone</p>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user