{% extends 'paxalia/base.html' %}
{% load static i18n %}
{% block title %}{% trans "Security Center" %} – Paxalia Analytics{% endblock %}
{% block page_title %}{% trans "Security Center" %}{% endblock %}
{% block page_subtitle %}{% trans "Application posture, server runtime, authentication, and audit evidence" %}{% endblock %}
{% block extra_css %}
{% endblock %}
{% block dashboard_content %}
{% if not dependency_health.django_supported %}
{% blocktrans with version=dependency_health.django_version %}Running Django {{ version }}, which isn't in this package's known-supported list. Check djangoproject.com for your version's support status.{% endblocktrans %}
{% endif %}
{% trans "Successful logins (30d)" %}{{ total_success_30d }}
{% trans "Failed logins (30d)" %}{{ total_failed_30d }}
{% trans "New-location logins (30d)" %}{{ new_location_logins_30d }}
{% trans "Active sessions" %}{{ active_sessions|length }}
{% if mfa_status is not None %}
{% endif %}
{% trans "Runtime posture" %}
{% trans "Dashboard version" %}{{ runtime_security.dashboard_version }}
{% trans "Django" %}{{ runtime_security.django }}
{% trans "Python" %}{{ runtime_security.python }}
{% trans "Database" %}{{ runtime_security.db_vendor }}
{% trans "Environment" %}{{ runtime_security.environment }}
{% trans "DEBUG" %}{% if runtime_security.debug %}{% trans "Enabled" %}{% else %}{% trans "Disabled" %}{% endif %}
{% trans "HTTPS redirect" %}{% if runtime_security.secure_ssl_redirect %}{% trans "Enabled" %}{% else %}{% trans "Proxy/application dependent" %}{% endif %}
{% trans "IP block enforcement" %}{% if runtime_security.security_block_middleware %}{% trans "Active" %}{% else %}{% trans "Not active" %}{% endif %}
{% trans "Slow query capture" %}{% if runtime_security.slow_query_middleware %}{% trans "Active" %}{% else %}{% trans "Not active" %}{% endif %}
{% trans "Memory used" %}{% if runtime_security.memory_percent != None %}{{ runtime_security.memory_percent }}%{% else %}—{% endif %}
{% trans "Root disk used" %}{% if runtime_security.disk_percent != None %}{{ runtime_security.disk_percent }}%{% else %}—{% endif %}
{% trans "Host" %}{{ runtime_security.hostname }}
{% trans "This view reports the runtime visible to the Django process. It is intentionally not a network vulnerability scanner and does not execute arbitrary remote probes." %}
{% trans "Operating-system login sessions" %}
{% if runtime_security.os_users %}
{% trans "User" %}
{% trans "Terminal" %}
{% trans "Host" %}
{% trans "Since" %}
{% for u in runtime_security.os_users %}
{{ u.name }}
{{ u.terminal }}
{{ u.host }}
{{ u.started|date:"Y-m-d H:i" }}
{% endfor %}
{% else %}
{% trans "No operating-system users are currently visible." %}{% trans "psutil may return no interactive sessions for a headless server or container." %}
{% if e.city or e.country_name %}{{ e.city }}{% if e.city and e.country_name %}, {% endif %}{{ e.country_name }}{% else %}—{% endif %}
{{ e.browser }} / {{ e.os }}
{% if e.is_new_location %}{% trans "Yes" %}{% else %}—{% endif %}
{% if e.is_active_session %}
{% elif e.result == 'success' %}
{% trans "ended" %}
{% else %}—{% endif %}
{% endfor %}
{% else %}
{% trans "No login activity recorded yet." %}
{% endif %}
{% trans "Active Sessions" %}
{% trans "Session revocation requires the default database session backend. If this project uses a different SESSION_ENGINE, revoking here ends tracking but may not immediately invalidate the session." %}
{% if active_sessions %}
{% trans "User" %}
{% trans "Signed in" %}
{% trans "IP" %}
{% trans "Device" %}
{% trans "Actions" %}
{% for e in active_sessions %}
{{ e.user.get_username|default:"—" }}
{{ e.created_at|date:"Y-m-d H:i" }}
{{ e.ip_address|default:"—" }}
{{ e.browser }} / {{ e.os }}
{% endfor %}
{% else %}
{% trans "No active sessions tracked." %}
{% endif %}
{% trans "Top attacking IPs (30d)" %}
{% if failed_by_ip %}
{% trans "IP" %}
{% trans "Failed attempts" %}
{% trans "Actions" %}
{% for row in failed_by_ip %}
{{ row.ip_address }}
{{ row.count }}
{% endfor %}
{% else %}
{% trans "No failed logins in the last 30 days." %}
{% endif %}
{% trans "Top targeted usernames (30d)" %}
{% if failed_by_username %}
{% trans "Username attempted" %}
{% trans "Failed attempts" %}
{% for row in failed_by_username %}
{{ row.username_attempted }}
{{ row.count }}
{% endfor %}
{% else %}
{% trans "No failed logins in the last 30 days." %}
{% endif %}
{% trans "IP Blocklist" %}
{% trans "Blocking here only takes effect if SecurityBlockMiddleware is added to MIDDLEWARE." %}
{% if blocked_ips %}
{% trans "IP" %}
{% trans "Reason" %}
{% trans "Status" %}
{% trans "Added" %}
{% trans "Actions" %}
{% for b in blocked_ips %}
{{ b.ip_address }}
{{ b.reason|default:"—" }}
{% if b.active %}{% trans "Blocked" %}{% else %}{% trans "Inactive" %}{% endif %}
{{ b.created_at|date:"Y-m-d H:i" }}
{% if b.active %}
{% else %}—{% endif %}
{% endfor %}
{% else %}
{% trans "No IPs blocked." %}
{% endif %}
{% trans "Admin Audit Log" %}
{% if audit_entries %}
{% trans "When" %}
{% trans "User" %}
{% trans "Action" %}
{% trans "Detail" %}
{% trans "IP" %}
{% for a in audit_entries %}
{{ a.created_at|date:"Y-m-d H:i" }}
{{ a.user.get_username|default:"system" }}
{{ a.action }}
{{ a.detail|default:"—" }}
{{ a.ip_address|default:"—" }}
{% endfor %}
{% else %}
{% trans "No admin actions recorded yet." %}
{% endif %}
{% trans "CSP Violations" %}
{% trans "This package doesn't set your Content-Security-Policy header — point your own CSP's report-uri/report-to at this dashboard's /csp-report/ endpoint to start seeing reports here." %}
{% if csp_violations %}
{% trans "When" %}
{% trans "Directive" %}
{% trans "Blocked URI" %}
{% trans "Page" %}
{% for v in csp_violations %}
{{ v.created_at|date:"Y-m-d H:i" }}
{{ v.violated_directive|default:"—" }}
{{ v.blocked_uri|default:"—" }}
{{ v.document_uri|default:"—" }}
{% endfor %}
{% else %}
{% trans "No CSP violations reported." %}
{% endif %}
{% trans "Security Scorecard" %}
{% trans "A pass/fail/warn checklist read from your Django settings at page-load time — not a live filesystem scan." %}
{% trans "Passing" %}{{ scorecard.summary.pass }}
{% trans "Warnings" %}{{ scorecard.summary.warn }}