init
This commit is contained in:
commit
0e3323b7ab
13 changed files with 1625 additions and 0 deletions
170
templates/base.html
Normal file
170
templates/base.html
Normal file
|
@ -0,0 +1,170 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>VPN Log Viewer</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
h1, h2, h3 {
|
||||
color: #0066cc;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 20px 0;
|
||||
}
|
||||
th, td {
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
a {
|
||||
color: #0066cc;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.filter-section {
|
||||
margin: 20px 0;
|
||||
padding: 10px;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.filter-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.filter-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
align-items: flex-end;
|
||||
}
|
||||
.filter-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 200px;
|
||||
}
|
||||
.filter-item label {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.filter-item select, .filter-item input {
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
input[type="datetime-local"] {
|
||||
min-width: 220px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
font-weight: normal;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.checkbox-label input[type="checkbox"] {
|
||||
margin-right: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.filter-button, .reset-button {
|
||||
padding: 8px 16px;
|
||||
background-color: #0066cc;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
.reset-button {
|
||||
background-color: #666;
|
||||
}
|
||||
.filter-button:hover, .reset-button:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.table-responsive {
|
||||
overflow-x: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
.log-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.log-table th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: #f2f2f2;
|
||||
z-index: 10;
|
||||
}
|
||||
.api-info {
|
||||
margin: 15px 0;
|
||||
padding: 15px;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.api-info h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.api-info p {
|
||||
margin: 5px 0;
|
||||
}
|
||||
.navigation-links {
|
||||
margin: 15px 0;
|
||||
}
|
||||
.nav-link {
|
||||
display: inline-block;
|
||||
padding: 8px 16px;
|
||||
background-color: #0066cc;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.nav-link:hover {
|
||||
background-color: #0055aa;
|
||||
text-decoration: none;
|
||||
}
|
||||
pre {
|
||||
background-color: #f8f8f8;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
overflow-x: auto;
|
||||
white-space: pre-wrap;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1><a href="/">VPN Log Viewer</a></h1>
|
||||
</header>
|
||||
<main>
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
<footer>
|
||||
<p><small>VPN Log Viewer - Logs updated every 5 minutes</small></p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
133
templates/combined.html
Normal file
133
templates/combined.html
Normal file
|
@ -0,0 +1,133 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const defaultTimeCheckbox = document.getElementById('use-default-time');
|
||||
const startDateInput = document.getElementById('start-date');
|
||||
const endDateInput = document.getElementById('end-date');
|
||||
|
||||
// Function to toggle date fields enabled/disabled based on checkbox
|
||||
function toggleDateFields() {
|
||||
if (defaultTimeCheckbox.checked) {
|
||||
startDateInput.disabled = true;
|
||||
endDateInput.disabled = true;
|
||||
} else {
|
||||
startDateInput.disabled = false;
|
||||
endDateInput.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Initial setup
|
||||
toggleDateFields();
|
||||
|
||||
// Set up event listener
|
||||
defaultTimeCheckbox.addEventListener('change', toggleDateFields);
|
||||
});
|
||||
</script>
|
||||
<h2>Combined VPN Sessions View</h2>
|
||||
|
||||
<div class="navigation-links">
|
||||
<a href="/" class="nav-link">Back to Log Files</a>
|
||||
</div>
|
||||
|
||||
<div class="api-info">
|
||||
<h3>API Endpoints</h3>
|
||||
<p>Get combined data via API: <a href="/api/all-entries" target="_blank">/api/all-entries</a></p>
|
||||
<p>Filter by gateway: <a href="/api/all-entries?gateway={{ selected_gateway }}" target="_blank">/api/all-entries?gateway={{ selected_gateway }}</a></p>
|
||||
<p>Filter by date range: <a href="/api/all-entries?start_date={{ start_date }}&end_date={{ end_date }}" target="_blank">/api/all-entries?start_date={{ start_date }}&end_date={{ end_date }}</a></p>
|
||||
<p>Use default time (last 30 min): <a href="/api/all-entries?use_default_time" target="_blank">/api/all-entries?use_default_time</a></p>
|
||||
<p>Search: <a href="/api/all-entries?search={{ search_term }}" target="_blank">/api/all-entries?search={{ search_term }}</a></p>
|
||||
<p>Combined filters: <a href="/api/all-entries?gateway={{ selected_gateway }}&start_date={{ start_date | replace("T", "T") }}&end_date={{ end_date | replace("T", "T") }}&search={{ search_term }}" target="_blank">/api/all-entries?gateway={{ selected_gateway }}&start_date={{ start_date }}&end_date={{ end_date }}&search={{ search_term }}</a></p>
|
||||
<p><small>Note: For API calls, date/time must be in ISO format (YYYY-MM-DDThh:mm:ss)</small></p>
|
||||
</div>
|
||||
|
||||
<div class="filter-section">
|
||||
<form method="get" class="filter-form">
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<label for="gateway-select">Gateway:</label>
|
||||
<select id="gateway-select" name="gateway">
|
||||
<option value="">All Gateways</option>
|
||||
{% for gateway in gateways %}
|
||||
<option value="{{ gateway }}" {% if gateway == selected_gateway %}selected{% endif %}>{{ gateway }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-item">
|
||||
<label for="start-date">From Date/Time:</label>
|
||||
<input type="datetime-local" id="start-date" name="start_date" value="{{ start_date }}" step="60">
|
||||
</div>
|
||||
|
||||
<div class="filter-item">
|
||||
<label for="end-date">To Date/Time:</label>
|
||||
<input type="datetime-local" id="end-date" name="end_date" value="{{ end_date }}" step="60">
|
||||
</div>
|
||||
|
||||
<div class="filter-item">
|
||||
<label for="search-input">Search:</label>
|
||||
<input type="text" id="search-input" name="search" value="{{ search_term or '' }}" placeholder="Search in all fields...">
|
||||
</div>
|
||||
|
||||
<div class="filter-item">
|
||||
<label for="use-default-time" class="checkbox-label">
|
||||
<input type="checkbox" id="use-default-time" name="use_default_time" {% if not start_date and not end_date %}checked{% endif %}>
|
||||
Use default time range (last 30 min)
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="filter-item">
|
||||
<button type="submit" class="filter-button">Apply Filters</button>
|
||||
<a href="/combined" class="reset-button">Reset</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="log-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{% for col in columns %}
|
||||
<th>
|
||||
{% if col.startswith('_') %}
|
||||
{{ col[1:] | capitalize }}
|
||||
{% else %}
|
||||
{{ col }}
|
||||
{% endif %}
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in rows %}
|
||||
<tr>
|
||||
{% for col in columns %}
|
||||
<td>
|
||||
{% if col == '_source_file' %}
|
||||
<a href="/view/{{ row[col] }}">{{ row[col] }}</a>
|
||||
{% elif col == '_timestamp' and row[col] %}
|
||||
{{ row[col].strftime('%Y-%m-%d %H:%M:%S UTC') }}
|
||||
{% else %}
|
||||
{% if row[col] is string %}
|
||||
{{ row[col].strip() }}
|
||||
{% elif row[col] is none %}
|
||||
<!-- Empty for None values -->
|
||||
{% else %}
|
||||
{{ row[col] }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="{{ columns|length }}">No matching logs found</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
53
templates/index.html
Normal file
53
templates/index.html
Normal file
|
@ -0,0 +1,53 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>VPN Session Logs</h2>
|
||||
|
||||
<div class="navigation-links">
|
||||
<a href="/combined" class="nav-link">View Combined Logs</a>
|
||||
</div>
|
||||
|
||||
<div class="api-info">
|
||||
<h3>API Endpoints</h3>
|
||||
<p>Get all logs: <a href="/api/logs" target="_blank">/api/logs</a></p>
|
||||
<p>Filter logs by gateway: <a href="/api/logs?gateway={{ selected_gateway }}" target="_blank">/api/logs?gateway={{ selected_gateway }}</a></p>
|
||||
<p>Get all gateways: <a href="/api/gateways" target="_blank">/api/gateways</a></p>
|
||||
<p>Get log content: <a href="/api/log-content/{{ logs[0].filename if logs else 'filename.logs' }}" target="_blank">/api/log-content/{filename}</a></p>
|
||||
</div>
|
||||
|
||||
<div class="filter-section">
|
||||
<form method="get">
|
||||
<label for="gateway-select">Filter by Gateway:</label>
|
||||
<select id="gateway-select" onchange="this.form.submit()" name="gateway">
|
||||
<option value="">All Gateways</option>
|
||||
{% for gateway in gateways %}
|
||||
<option value="{{ gateway }}" {% if gateway == selected_gateway %}selected{% endif %}>{{ gateway }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Gateway</th>
|
||||
<th>Timestamp</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for log in logs %}
|
||||
<tr>
|
||||
<td>{{ log.gateway }}</td>
|
||||
<td>{{ log.timestamp.strftime('%Y-%m-%d %H:%M:%S UTC') }}</td>
|
||||
<td><a href="/view/{{ log.filename }}">View</a></td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="3">No logs found</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
99
templates/view.html
Normal file
99
templates/view.html
Normal file
|
@ -0,0 +1,99 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>VPN Session Details</h2>
|
||||
|
||||
<p><a href="/">← Back to all logs</a></p>
|
||||
|
||||
<div class="api-info">
|
||||
<h3>API Endpoints</h3>
|
||||
<p>Get log content via API: <a href="/api/log-content/{{ filename }}" target="_blank">/api/log-content/{{ filename }}</a></p>
|
||||
</div>
|
||||
|
||||
<div class="log-info">
|
||||
<p><strong>Gateway:</strong> {{ gateway }}</p>
|
||||
<p><strong>Timestamp:</strong> {{ timestamp.strftime('%Y-%m-%d %H:%M:%S UTC') if timestamp else 'Unknown' }}</p>
|
||||
<p><strong>Filename:</strong> {{ filename }}</p>
|
||||
</div>
|
||||
|
||||
<h3>Log Content</h3>
|
||||
|
||||
{% if parsed_rows %}
|
||||
<div class="table-container">
|
||||
<table class="log-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{% for col in columns %}
|
||||
<th>{{ col }}</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in parsed_rows %}
|
||||
<tr>
|
||||
{% if 'Index' in columns %}
|
||||
<td>{{ row.index }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if 'User' in columns %}
|
||||
<td>{{ row.user.strip() if row.user else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if 'Group' in columns %}
|
||||
<td>{{ row.group.strip() if row.group else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{# VPN Login Users fields #}
|
||||
{% if 'Auth Type' in columns %}
|
||||
<td>{{ row.auth_type.strip() if row.auth_type else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if 'Timeout' in columns %}
|
||||
<td>{{ row.timeout.strip() if row.timeout else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if 'Auth-Timeout' in columns %}
|
||||
<td>{{ row.auth_timeout.strip() if row.auth_timeout else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if 'From' in columns %}
|
||||
<td>{{ row.from_ip.strip() if row.from_ip else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if 'HTTP in/out' in columns %}
|
||||
<td>{{ row.http.strip() if row.http else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if 'HTTPS in/out' in columns %}
|
||||
<td>{{ row.https.strip() if row.https else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if 'Two-factor Auth' in columns %}
|
||||
<td>{{ row.two_factor.strip() if row.two_factor else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{# VPN Sessions fields #}
|
||||
{% if 'Source IP' in columns %}
|
||||
<td>{{ row.source_ip.strip() if row.source_ip else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if 'Duration' in columns %}
|
||||
<td>{{ row.duration.strip() if row.duration else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if 'I/O Bytes' in columns %}
|
||||
<td>{{ row.io_bytes.strip() if row.io_bytes else "" }}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if 'Tunnel/Dest IP' in columns %}
|
||||
<td>{{ (row.tunnel_dest_ip.strip() if row.tunnel_dest_ip else "") }}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<pre>{{ raw_content }}</pre>
|
||||
{% endif %}
|
||||
{% endblock %}
|
Loading…
Add table
Add a link
Reference in a new issue