Tochile commited on
Commit
61ad322
·
1 Parent(s): 72796ad

Deploy Ake-Project Flask app

Browse files
Dockerfile ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9
2
+
3
+ # Create non-root user (HF best practice)
4
+ RUN useradd -m -u 1000 user
5
+ USER user
6
+ ENV PATH="/home/user/.local/bin:$PATH"
7
+
8
+ # Set working directory
9
+ WORKDIR /app
10
+
11
+ # Install dependencies
12
+ COPY --chown=user ./requirements.txt requirements.txt
13
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
14
+
15
+ # Copy all project files
16
+ COPY --chown=user . /app
17
+
18
+ # Expose Hugging Face default port
19
+ EXPOSE 7860
20
+
21
+ # Start Flask app with Gunicorn
22
+ CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:7860"]
__pycache__/app.cpython-311.pyc ADDED
Binary file (9.72 kB). View file
 
app.py ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py (Flask Backend)
2
+
3
+ import os
4
+ import random
5
+ import time
6
+ from flask import Flask, render_template, request, jsonify
7
+ import numpy as np
8
+ import pandas as pd
9
+ from sklearn.preprocessing import StandardScaler
10
+ import torch
11
+ import torch.nn as nn
12
+ import json # For debugging/logging if needed
13
+
14
+ # --- Configuration ---
15
+ app = Flask(__name__)
16
+ MODEL_PATH = 'zero_day_encoder_model.pth'
17
+ # Assuming the scaler was fit on data with the same number of features as input_dim
18
+ # For a real system, you'd save/load the scaler as well.
19
+ # For this demo, we'll re-initialize a dummy scaler and use the exact number of features
20
+ # determined by the loaded model's input layer.
21
+ GLOBAL_SCALER = None # Will be initialized after model loads
22
+ MODEL_INPUT_DIM = None # Will be set by the loaded model
23
+ MODEL_LATENT_DIM = 32 # Must match the latent_dim used during training
24
+ ANOMALY_THRESHOLD = 5.0 # Adjustable threshold for flagging attacks (Euclidean distance)
25
+
26
+ # --- PyTorch Model Architecture (Must match training script) ---
27
+ class Encoder(nn.Module):
28
+ def __init__(self, input_dim, latent_dim):
29
+ super(Encoder, self).__init__()
30
+ self.fc1 = nn.Linear(input_dim, 128)
31
+ self.relu = nn.ReLU()
32
+ self.fc2 = nn.Linear(128, 64)
33
+ self.fc3 = nn.Linear(64, latent_dim) # Latent dimension for embeddings
34
+
35
+ def forward(self, x):
36
+ x = self.relu(self.fc1(x))
37
+ x = self.relu(self.fc2(x))
38
+ return self.fc3(x)
39
+
40
+ # --- Load the Trained Model and Initialize Scaler/Centroid ---
41
+ # This will be run once when the Flask app starts
42
+ def load_model_and_params():
43
+ global GLOBAL_SCALER, MODEL_INPUT_DIM, GLOBAL_CENTROID
44
+
45
+ if not os.path.exists(MODEL_PATH):
46
+ print(f"Error: Model file not found at {MODEL_PATH}. Please train the Jupyter Notebook first.")
47
+ # Fallback to dummy model if not found
48
+ # This will allow the app to run but not perform real anomaly detection
49
+ MODEL_INPUT_DIM = 7 + 39 # Dummy, assuming original 7 financial + 39 CICIDS features
50
+ GLOBAL_SCALER = StandardScaler()
51
+ # Initialize a dummy encoder for app startup without a model file
52
+ dummy_encoder = Encoder(MODEL_INPUT_DIM, MODEL_LATENT_DIM)
53
+ GLOBAL_CENTROID = np.random.rand(MODEL_LATENT_DIM) * 0.1 # Small random centroid
54
+ return dummy_encoder
55
+
56
+ try:
57
+ # Create a dummy instance to load the state_dict into
58
+ # We need to infer the input_dim from the saved state_dict or hardcode it
59
+ # A more robust way is to save model architecture as well, or pass input_dim during saving.
60
+ # For now, let's assume input_dim = 7 (financial) + 39 (CICIDS selected) = 46.
61
+ # This input_dim must precisely match what the trained model expects.
62
+ temp_input_dim = 7 + 39 # Base assumption: 7 financial + 39 CICIDS features
63
+ temp_encoder = Encoder(temp_input_dim, MODEL_LATENT_DIM)
64
+
65
+ # Load the state dictionary
66
+ state_dict = torch.load(MODEL_PATH, map_location=torch.device('cpu')) # Map to CPU as Flask runs on CPU
67
+
68
+ # Update input_dim based on the loaded state_dict if possible
69
+ # Check the first linear layer's weight shape
70
+ if 'fc1.weight' in state_dict:
71
+ MODEL_INPUT_DIM = state_dict['fc1.weight'].shape[1]
72
+ temp_encoder = Encoder(MODEL_INPUT_DIM, MODEL_LATENT_DIM) # Recreate with correct input_dim
73
+ else:
74
+ print(f"Warning: Could not infer input_dim from model state_dict. Using assumed: {temp_input_dim}")
75
+ MODEL_INPUT_DIM = temp_input_dim
76
+
77
+ temp_encoder.load_state_dict(state_dict)
78
+ temp_encoder.eval() # Set to evaluation mode
79
+
80
+ # Load the scaler and centroid. In a real system, you'd save these from your training notebook.
81
+ # For this demo, we'll create a dummy scaler and centroid that correspond to the model's input_dim.
82
+ GLOBAL_SCALER = StandardScaler()
83
+ # In a production setup, the scaler's parameters (mean, std) and the centroid
84
+ # would be saved during training and loaded here. For simplicity, we'll
85
+ # just initialize a generic scaler and a placeholder centroid.
86
+ # The centroid should ideally be learned from the *benign* training data.
87
+ # For demonstration, we'll generate a random one and rely on the model's embeddings.
88
+ GLOBAL_CENTROID = np.random.rand(MODEL_LATENT_DIM) # Placeholder centroid.
89
+
90
+ print(f"Model loaded successfully. Input Dimension: {MODEL_INPUT_DIM}")
91
+ return temp_encoder
92
+
93
+ except Exception as e:
94
+ print(f"Error loading model: {e}")
95
+ print("Using dummy model for application startup.")
96
+ MODEL_INPUT_DIM = 7 + 39 # Fallback
97
+ GLOBAL_SCALER = StandardScaler()
98
+ dummy_encoder = Encoder(MODEL_INPUT_DIM, MODEL_LATENT_DIM)
99
+ GLOBAL_CENTROID = np.random.rand(MODEL_LATENT_DIM) * 0.1
100
+ return dummy_encoder
101
+
102
+ ENCODER_MODEL = load_model_and_params()
103
+
104
+ # --- Helper Function for Anomaly Detection ---
105
+ def detect_anomaly(raw_data_point):
106
+ """
107
+ Processes a single raw data point and returns its anomaly score and classification.
108
+ """
109
+ global GLOBAL_SCALER, ENCODER_MODEL, GLOBAL_CENTROID, MODEL_INPUT_DIM
110
+
111
+ # Ensure the input data has the correct number of features
112
+ if len(raw_data_point) != MODEL_INPUT_DIM:
113
+ print(f"Input data dimension mismatch: Expected {MODEL_INPUT_DIM}, got {len(raw_data_point)}")
114
+ # Pad or truncate if dimensions don't match (for robust demo)
115
+ if len(raw_data_point) < MODEL_INPUT_DIM:
116
+ raw_data_point = np.pad(raw_data_point, (0, MODEL_INPUT_DIM - len(raw_data_point)), 'constant')
117
+ else:
118
+ raw_data_point = raw_data_point[:MODEL_INPUT_DIM]
119
+
120
+
121
+ # Reshape for scaler (needs 2D array: n_samples, n_features)
122
+ data_point_2d = np.array(raw_data_point).reshape(1, -1)
123
+
124
+ # Use a dummy fit_transform if scaler hasn't seen data, otherwise transform
125
+ # In a real app, the scaler would be loaded, or fit on a small sample of representative data at startup.
126
+ # For robust demo: if scaler has no 'mean_' attr (not fitted), fit it on some dummy data first.
127
+ if not hasattr(GLOBAL_SCALER, 'mean_') or GLOBAL_SCALER.mean_ is None or GLOBAL_SCALER.mean_.shape[0] != MODEL_INPUT_DIM:
128
+ print("Scaler not fitted or dimension mismatch, fitting dummy scaler...")
129
+ # Create dummy data for scaler to fit, matching input_dim
130
+ dummy_fit_data = np.random.rand(100, MODEL_INPUT_DIM)
131
+ GLOBAL_SCALER.fit(dummy_fit_data)
132
+
133
+ scaled_data_point = GLOBAL_SCALER.transform(data_point_2d)
134
+
135
+ # Convert to PyTorch tensor
136
+ data_tensor = torch.tensor(scaled_data_point, dtype=torch.float32)
137
+
138
+ with torch.no_grad():
139
+ embedding = ENCODER_MODEL(data_tensor).cpu().numpy().flatten()
140
+
141
+ # Calculate anomaly score (Euclidean distance to centroid)
142
+ anomaly_score = np.linalg.norm(embedding - GLOBAL_CENTROID)
143
+
144
+ # Classify based on threshold
145
+ is_anomaly = anomaly_score > ANOMALY_THRESHOLD
146
+ attack_status = "Attack Detected!" if is_anomaly else "Normal Behavior"
147
+ reaction_message = ""
148
+ if is_anomaly:
149
+ reaction_message = "Immediate transaction review triggered. Connection flagged."
150
+ # Simulate prevention by, e.g., setting a flag, initiating a block, etc.
151
+ # In a real system, this would trigger actual security measures.
152
+ print(f"ALERT: Zero-Day Attack Detected! Score: {anomaly_score:.2f}")
153
+
154
+ return {
155
+ 'score': float(anomaly_score),
156
+ # Explicitly convert numpy.bool_ to Python bool for jsonify compatibility
157
+ 'is_anomaly': bool(is_anomaly),
158
+ 'status': attack_status,
159
+ 'reaction': reaction_message,
160
+ 'attack_type': random.choice(['Phishing', 'Malware', 'DDoS', 'Insider Threat', 'Zero-Day Exploitation']) if is_anomaly else 'Benign'
161
+ }
162
+
163
+ # --- Flask Routes ---
164
+ @app.route('/')
165
+ def index():
166
+ """Renders the main dashboard HTML page."""
167
+ # Pass MODEL_INPUT_DIM to the frontend for simulation logic
168
+ return render_template('index.html', MODEL_INPUT_DIM=MODEL_INPUT_DIM)
169
+
170
+ @app.route('/api/analyze_log', methods=['POST'])
171
+ def analyze_log():
172
+ """
173
+ API endpoint to receive simulated log data, run anomaly detection,
174
+ and return results.
175
+ """
176
+ try:
177
+ data = request.get_json()
178
+ raw_log_data = data.get('log_features')
179
+ if not raw_log_data:
180
+ return jsonify({'error': 'No log_features provided'}), 400
181
+
182
+ # Convert list to numpy array
183
+ raw_log_data = np.array(raw_log_data, dtype=np.float32)
184
+
185
+ result = detect_anomaly(raw_log_data)
186
+ return jsonify(result)
187
+
188
+ except Exception as e:
189
+ print(f"Error in /api/analyze_log: {e}")
190
+ return jsonify({'error': str(e)}), 500
191
+
192
+ @app.route('/api/metrics')
193
+ def get_metrics():
194
+ """
195
+ Simulates real-time metrics for the dashboard.
196
+ In a real system, this would fetch from a database or monitoring system.
197
+ """
198
+ total_transactions = random.randint(100000, 1000000)
199
+ threats_detected = random.randint(50, 500)
200
+ blocked_attempts = random.randint(30, threats_detected)
201
+ active_users = random.randint(1000, 50000)
202
+ return jsonify({
203
+ 'totalTransactions': total_transactions,
204
+ 'threatsDetected': threats_detected,
205
+ 'blockedAttempts': blocked_attempts,
206
+ 'activeUsers': active_users,
207
+ 'timestamp': time.strftime("%Y-%m-%d %H:%M:%S")
208
+ })
209
+
210
+ if __name__ == '__main__':
211
+ app.run(host="0.0.0.0", port=7860, debug=True)
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ flask
2
+ numpy
3
+ pandas
4
+ scikit-learn
5
+ torch
6
+ gunicorn
templates/index.html ADDED
@@ -0,0 +1,596 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- templates/index.html (HTML Frontend with Bootstrap & JavaScript) -->
2
+
3
+ <!DOCTYPE html>
4
+ <html lang="en">
5
+ <head>
6
+ <meta charset="UTF-8">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
+ <title>Zero-Day Attack Monitoring Dashboard</title>
9
+ <!-- Bootstrap CSS CDN -->
10
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
11
+ <!-- Chart.js CDN for plotting -->
12
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
13
+
14
+ <style>
15
+ body {
16
+ font-family: 'Inter', sans-serif;
17
+ background-color: #f0f2f5;
18
+ color: #333;
19
+ }
20
+ .navbar-brand {
21
+ font-weight: bold;
22
+ }
23
+ .card {
24
+ border-radius: 1rem;
25
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
26
+ background-color: #fff;
27
+ }
28
+ .card-header {
29
+ background-color: #007bff;
30
+ color: white;
31
+ border-top-left-radius: 1rem;
32
+ border-top-right-radius: 1rem;
33
+ }
34
+ .dashboard-metric-value {
35
+ font-size: 2.5rem;
36
+ font-weight: bold;
37
+ color: #007bff;
38
+ }
39
+ .anomaly-indicator {
40
+ height: 50px;
41
+ border-radius: 0.5rem;
42
+ transition: background-color 0.5s ease;
43
+ }
44
+ .anomaly-low { background-color: #28a745; /* Green */ }
45
+ .anomaly-medium { background-color: #ffc107; /* Yellow */ }
46
+ .anomaly-high { background-color: #dc3545; /* Red */ }
47
+
48
+ .attack-reaction-box {
49
+ border: 2px solid #ccc;
50
+ padding: 1rem;
51
+ border-radius: 0.5rem;
52
+ min-height: 100px;
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ font-weight: bold;
57
+ text-align: center;
58
+ transition: all 0.5s ease;
59
+ }
60
+ .attack-detected {
61
+ border-color: #dc3545;
62
+ background-color: #dc354522; /* Light red background */
63
+ color: #dc3545;
64
+ }
65
+ .chart-container {
66
+ position: relative;
67
+ height: 300px;
68
+ width: 100%;
69
+ }
70
+ /* Styling for the new simulation control buttons */
71
+ .simulation-control-card .btn {
72
+ border-radius: 0.5rem;
73
+ margin-right: 0.5rem; /* Space between buttons */
74
+ }
75
+ .badge-info {
76
+ background-color: #17a2b8; /* Bootstrap info blue */
77
+ color: white;
78
+ padding: 0.5em 0.75em;
79
+ border-radius: 0.5rem;
80
+ }
81
+ .recent-events-table {
82
+ max-height: 300px; /* Limit height for scrollability */
83
+ overflow-y: auto; /* Enable vertical scrolling */
84
+ }
85
+ </style>
86
+ </head>
87
+ <body>
88
+ <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
89
+ <div class="container-fluid">
90
+ <a class="navbar-brand" href="#">
91
+ <img src="https://placehold.co/30x30/FFFFFF/000000?text=)\🛡️" alt="Logo" class="d-inline-block align-text-top me-2">
92
+ Financial Zero-Day Defense
93
+ </a>
94
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
95
+ <span class="navbar-toggler-icon"></span>
96
+ </button>
97
+ <div class="collapse navbar-collapse" id="navbarNav">
98
+ <ul class="navbar-nav ms-auto">
99
+ <li class="nav-item">
100
+ <a class="nav-link active" aria-current="page" href="#">Dashboard</a>
101
+ </li>
102
+ <li class="nav-item">
103
+ <a class="nav-link" href="#">Reports</a>
104
+ </li>
105
+ <li class="nav-item">
106
+ <a class="nav-link" href="#">Settings</a>
107
+ </li>
108
+ </ul>
109
+ </div>
110
+ </div>
111
+ </nav>
112
+
113
+ <div class="container-fluid mt-4">
114
+ <h1 class="mb-4">Real-Time Zero-Day Attack Monitoring</h1>
115
+
116
+ <!-- Overall Metrics Dashboard -->
117
+ <div class="row mb-4">
118
+ <div class="col-md-3">
119
+ <div class="card text-center p-3">
120
+ <div class="card-body">
121
+ <h5 class="card-title text-muted">Total Transactions</h5>
122
+ <p class="dashboard-metric-value" id="totalTransactions">Loading...</p>
123
+ </div>
124
+ </div>
125
+ </div>
126
+ <div class="col-md-3">
127
+ <div class="card text-center p-3">
128
+ <div class="card-body">
129
+ <h5 class="card-title text-muted">Threats Detected (24h)</h5>
130
+ <p class="dashboard-metric-value text-danger" id="threatsDetected">Loading...</p>
131
+ </div>
132
+ </div>
133
+ </div>
134
+ <div class="col-md-3">
135
+ <div class="card text-center p-3">
136
+ <div class="card-body">
137
+ <h5 class="card-title text-muted">Blocked Attempts (24h)</h5>
138
+ <p class="dashboard-metric-value text-success" id="blockedAttempts">Loading...</p>
139
+ </div>
140
+ </div>
141
+ </div>
142
+ <div class="col-md-3">
143
+ <div class="card text-center p-3">
144
+ <div class="card-body">
145
+ <h5 class="card-title text-muted">Active Users</h5>
146
+ <p class="dashboard-metric-value text-info" id="activeUsers">Loading...</p>
147
+ </div>
148
+ </div>
149
+ </div>
150
+ </div>
151
+
152
+ <div class="row">
153
+ <!-- Anomaly Detection Section -->
154
+ <div class="col-md-6 mb-4">
155
+ <div class="card">
156
+ <div class="card-header">
157
+ Real-Time Anomaly Analysis
158
+ </div>
159
+ <div class="card-body">
160
+ <div class="mb-3">
161
+ <label for="anomalyThreshold" class="form-label">Anomaly Threshold: <span id="thresholdValue" class="badge bg-primary">5.0</span></label>
162
+ <input type="range" class="form-range" id="anomalyThreshold" min="0.1" max="10.0" step="0.1" value="5.0">
163
+ </div>
164
+ <h4 class="mb-3">Current Anomaly Score: <span id="currentAnomalyScore" class="badge bg-secondary">0.00</span></h4>
165
+ <div class="anomaly-indicator" id="anomalyIndicator"></div>
166
+ <p class="mt-3 fs-5" id="anomalyStatus">Waiting for data...</p>
167
+ </div>
168
+ </div>
169
+ </div>
170
+
171
+ <!-- System Reaction & Prevention -->
172
+ <div class="col-md-6 mb-4">
173
+ <div class="card">
174
+ <div class="card-header">
175
+ System Reaction & Prevention
176
+ </div>
177
+ <div class="card-body">
178
+ <div class="attack-reaction-box" id="attackReactionBox">
179
+ System is operating normally.
180
+ </div>
181
+ <p class="mt-3 text-muted">
182
+ *This section simulates immediate responses to detected zero-day attacks.
183
+ </p>
184
+ </div>
185
+ </div>
186
+ </div>
187
+ </div>
188
+
189
+ <div class="row mb-4">
190
+ <!-- Simulation Control Section -->
191
+ <div class="col-md-6 mb-4">
192
+ <div class="card simulation-control-card">
193
+ <div class="card-header">
194
+ Simulation Control
195
+ </div>
196
+ <div class="card-body text-center">
197
+ <p class="text-muted">Start or stop the real-time log simulation of financial transactions.</p>
198
+ <button class="btn btn-success" id="beginSimulationBtn">Begin Simulation</button>
199
+ <button class="btn btn-warning" id="stopSimulationBtn" disabled>Stop Simulation</button>
200
+ <div id="simulationStatus" class="mt-3 badge bg-info">Simulation Stopped</div>
201
+ </div>
202
+ </div>
203
+ </div>
204
+
205
+ <!-- Anomaly Score History Chart -->
206
+ <div class="col-md-6 mb-4">
207
+ <div class="card">
208
+ <div class="card-header">
209
+ Anomaly Score History
210
+ </div>
211
+ <div class="card-body">
212
+ <div class="chart-container">
213
+ <canvas id="anomalyScoreChart"></canvas>
214
+ </div>
215
+ </div>
216
+ </div>
217
+ </div>
218
+ </div>
219
+
220
+ <div class="row mb-4">
221
+ <!-- Recent Attack Events Table -->
222
+ <div class="col-md-6 mb-4">
223
+ <div class="card">
224
+ <div class="card-header">
225
+ Recent Attack Events
226
+ </div>
227
+ <div class="card-body recent-events-table">
228
+ <table class="table table-sm table-striped">
229
+ <thead>
230
+ <tr>
231
+ <th>Time</th>
232
+ <th>Anomaly Score</th>
233
+ <th>Status</th>
234
+ <th>Type</th>
235
+ </tr>
236
+ </thead>
237
+ <tbody id="recentEventsTableBody">
238
+ <!-- Events will be dynamically added here -->
239
+ <tr><td colspan="4" class="text-center text-muted">No recent attack events.</td></tr>
240
+ </tbody>
241
+ </table>
242
+ </div>
243
+ </div>
244
+ </div>
245
+
246
+ <!-- Daily Attack Breakdown Pie Chart -->
247
+ <div class="col-md-6 mb-4">
248
+ <div class="card">
249
+ <div class="card-header">
250
+ Daily Attack Breakdown
251
+ </div>
252
+ <div class="card-body">
253
+ <div class="chart-container">
254
+ <canvas id="attackBreakdownChart"></canvas>
255
+ </div>
256
+ </div>
257
+ </div>
258
+ </div>
259
+ </div>
260
+ </div>
261
+
262
+ <!-- Bootstrap JS Bundle with Popper -->
263
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
264
+ <script>
265
+ const anomalyThresholdSlider = document.getElementById('anomalyThreshold');
266
+ const thresholdValueSpan = document.getElementById('thresholdValue');
267
+ const currentAnomalyScoreSpan = document.getElementById('currentAnomalyScore');
268
+ const anomalyIndicatorDiv = document.getElementById('anomalyIndicator');
269
+ const anomalyStatusP = document.getElementById('anomalyStatus');
270
+ const attackReactionBox = document.getElementById('attackReactionBox');
271
+
272
+ // References to the new simulation control buttons and status
273
+ const beginSimulationBtn = document.getElementById('beginSimulationBtn');
274
+ const stopSimulationBtn = document.getElementById('stopSimulationBtn');
275
+ const simulationStatusSpan = document.getElementById('simulationStatus');
276
+ const recentEventsTableBody = document.getElementById('recentEventsTableBody');
277
+
278
+ let simulationIntervalId;
279
+ let isSimulationRunning = false;
280
+
281
+ let anomalyScoreHistory = [];
282
+ let anomalyLabelsHistory = [];
283
+ let chart; // Anomaly Score History Chart.js instance
284
+ let attackBreakdownChart; // Daily Attack Breakdown Chart.js instance
285
+
286
+ // Object to store counts of different attack types for the pie chart
287
+ let attackTypeCounts = {
288
+ 'Phishing': 0, 'Malware': 0, 'DDoS': 0, 'Insider Threat': 0, 'Zero-Day Exploitation': 0, 'Benign': 0
289
+ };
290
+
291
+ // Flask will inject this from the backend.
292
+ const MODEL_INPUT_DIM = {{ MODEL_INPUT_DIM }};
293
+
294
+ // Initialize Chart.js for Anomaly Score History
295
+ function initializeAnomalyScoreChart() {
296
+ const ctx = document.getElementById('anomalyScoreChart').getContext('2d');
297
+ chart = new Chart(ctx, {
298
+ type: 'line',
299
+ data: {
300
+ labels: [], // Time labels
301
+ datasets: [{
302
+ label: 'Anomaly Score',
303
+ data: [],
304
+ borderColor: 'rgb(75, 192, 192)',
305
+ tension: 0.1,
306
+ fill: false,
307
+ pointRadius: 3,
308
+ pointBackgroundColor: function(context) {
309
+ const index = context.dataIndex;
310
+ const score = context.dataset.data[index];
311
+ return score > parseFloat(anomalyThresholdSlider.value) ? 'red' : 'green';
312
+ }
313
+ }, {
314
+ // Dataset for the anomaly threshold line
315
+ label: 'Anomaly Threshold',
316
+ data: Array(50).fill(parseFloat(anomalyThresholdSlider.value)),
317
+ borderColor: 'rgba(255, 99, 132, 0.7)',
318
+ borderDash: [5, 5],
319
+ tension: 0.1,
320
+ fill: false,
321
+ pointRadius: 0 // No points for the threshold line
322
+ }]
323
+ },
324
+ options: {
325
+ responsive: true,
326
+ maintainAspectRatio: false,
327
+ scales: {
328
+ x: {
329
+ title: {
330
+ display: true,
331
+ text: 'Time'
332
+ }
333
+ },
334
+ y: {
335
+ title: {
336
+ display: true,
337
+ text: 'Anomaly Score'
338
+ },
339
+ beginAtZero: true
340
+ }
341
+ },
342
+ plugins: {
343
+ tooltip: {
344
+ callbacks: {
345
+ label: function(context) {
346
+ let label = context.dataset.label || '';
347
+ if (label) {
348
+ label += ': ';
349
+ }
350
+ if (context.parsed.y !== null) {
351
+ label += context.parsed.y.toFixed(2);
352
+ }
353
+ // Only add (Anomaly) if it's the 'Anomaly Score' dataset and actually an anomaly
354
+ if (context.dataset.label === 'Anomaly Score') {
355
+ const index = context.dataIndex;
356
+ const isAnomaly = anomalyLabelsHistory[index];
357
+ if (isAnomaly) {
358
+ label += ' (Anomaly)';
359
+ }
360
+ }
361
+ return label;
362
+ }
363
+ }
364
+ }
365
+ }
366
+ }
367
+ });
368
+
369
+ // Update threshold line dynamically
370
+ anomalyThresholdSlider.addEventListener('input', (event) => {
371
+ const newThreshold = parseFloat(event.target.value);
372
+ thresholdValueSpan.textContent = newThreshold.toFixed(1);
373
+ chart.data.datasets[1].data.fill(newThreshold); // Update threshold line data
374
+ chart.update(); // Redraw chart
375
+ updateAnomalyIndicator(parseFloat(currentAnomalyScoreSpan.textContent)); // Re-evaluate indicator
376
+ });
377
+ }
378
+
379
+ // Initialize Chart.js for Daily Attack Breakdown
380
+ function initializeAttackBreakdownChart() {
381
+ const ctx = document.getElementById('attackBreakdownChart').getContext('2d');
382
+ attackBreakdownChart = new Chart(ctx, {
383
+ type: 'pie',
384
+ data: {
385
+ labels: Object.keys(attackTypeCounts),
386
+ datasets: [{
387
+ data: Object.values(attackTypeCounts),
388
+ backgroundColor: [
389
+ 'rgba(255, 99, 132, 0.8)', // Phishing (Red)
390
+ 'rgba(54, 162, 235, 0.8)', // Malware (Blue)
391
+ 'rgba(255, 206, 86, 0.8)', // DDoS (Yellow)
392
+ 'rgba(75, 192, 192, 0.8)', // Insider Threat (Teal)
393
+ 'rgba(153, 102, 255, 0.8)', // Zero-Day Exploitation (Purple)
394
+ 'rgba(40, 167, 69, 0.8)' // Benign (Green)
395
+ ],
396
+ borderColor: '#fff',
397
+ borderWidth: 2
398
+ }]
399
+ },
400
+ options: {
401
+ responsive: true,
402
+ maintainAspectRatio: false,
403
+ plugins: {
404
+ legend: {
405
+ position: 'top',
406
+ },
407
+ tooltip: {
408
+ callbacks: {
409
+ label: function(context) {
410
+ const label = context.label || '';
411
+ const value = context.parsed;
412
+ const total = context.dataset.data.reduce((acc, current) => acc + current, 0);
413
+ const percentage = total > 0 ? ((value / total) * 100).toFixed(1) + '%' : '0.0%';
414
+ return `${label}: ${value} (${percentage})`;
415
+ }
416
+ }
417
+ }
418
+ }
419
+ }
420
+ });
421
+ }
422
+
423
+ // Update Anomaly Indicator Color
424
+ function updateAnomalyIndicator(score) {
425
+ anomalyIndicatorDiv.classList.remove('anomaly-low', 'anomaly-medium', 'anomaly-high');
426
+ const threshold = parseFloat(anomalyThresholdSlider.value);
427
+ if (score > threshold * 1.2) { // Significantly above threshold
428
+ anomalyIndicatorDiv.classList.add('anomaly-high');
429
+ anomalyStatusP.textContent = 'HIGH ANOMALY DETECTED!';
430
+ anomalyStatusP.style.color = '#dc3545';
431
+ attackReactionBox.classList.add('attack-detected');
432
+ } else if (score > threshold) { // Above threshold
433
+ anomalyIndicatorDiv.classList.add('anomaly-medium');
434
+ anomalyStatusP.textContent = 'Anomaly Detected!';
435
+ anomalyStatusP.style.color = '#ffc107';
436
+ attackReactionBox.classList.add('attack-detected');
437
+ } else {
438
+ anomalyIndicatorDiv.classList.add('anomaly-low');
439
+ anomalyStatusP.textContent = 'Normal Behavior';
440
+ anomalyStatusP.style.color = '#28a745';
441
+ attackReactionBox.classList.remove('attack-detected');
442
+ }
443
+ }
444
+
445
+ // Simulate random log data for demonstration
446
+ function generateRandomLogFeatures(type) {
447
+ let features = [];
448
+ // Use MODEL_INPUT_DIM passed from Flask backend
449
+ for (let i = 0; i < MODEL_INPUT_DIM; i++) {
450
+ if (type === 'benign') {
451
+ // Simulate benign data (e.g., values around 5, small std dev)
452
+ features.push(Math.random() * 2 + 4); // Range 4 to 6
453
+ } else {
454
+ // Simulate anomaly data (e.g., values outside normal range)
455
+ features.push(Math.random() * 5 - 10); // Range -10 to -5
456
+ }
457
+ }
458
+ return features;
459
+ }
460
+
461
+ // Send log data to Flask backend for analysis
462
+ async function sendLogForAnalysis() {
463
+ // Determine if it's a benign or anomaly log based on a probability
464
+ const randomType = Math.random() < 0.15 ? 'anomaly' : 'benign'; // 15% chance of anomaly
465
+ const logFeatures = generateRandomLogFeatures(randomType);
466
+
467
+ try {
468
+ const response = await fetch('/api/analyze_log', {
469
+ method: 'POST',
470
+ headers: {
471
+ 'Content-Type': 'application/json',
472
+ },
473
+ body: JSON.stringify({ log_features: logFeatures }),
474
+ });
475
+ const result = await response.json();
476
+
477
+ if (result.error) {
478
+ console.error("API Error:", result.error);
479
+ anomalyStatusP.textContent = `Error: ${result.error}`;
480
+ anomalyStatusP.style.color = '#dc3545';
481
+ return;
482
+ }
483
+
484
+ currentAnomalyScoreSpan.textContent = result.score.toFixed(2);
485
+ updateAnomalyIndicator(result.score);
486
+ attackReactionBox.textContent = result.reaction || "System is operating normally.";
487
+
488
+ // Update Anomaly Score History chart
489
+ const now = new Date();
490
+ chart.data.labels.push(now.toLocaleTimeString());
491
+ chart.data.datasets[0].data.push(result.score);
492
+ anomalyLabelsHistory.push(result.is_anomaly);
493
+
494
+ // Limit chart history to, e.g., last 50 points
495
+ const maxHistory = 50;
496
+ if (chart.data.labels.length > maxHistory) {
497
+ chart.data.labels.shift();
498
+ chart.data.datasets[0].data.shift();
499
+ anomalyLabelsHistory.shift();
500
+ }
501
+ chart.update();
502
+
503
+ // Update Recent Attack Events table
504
+ if (result.is_anomaly) {
505
+ // Remove initial "No recent events" row if it exists
506
+ if (recentEventsTableBody.children.length === 1 && recentEventsTableBody.children[0].textContent.includes('No recent attack events')) {
507
+ recentEventsTableBody.innerHTML = '';
508
+ }
509
+ const row = recentEventsTableBody.insertRow(0); // Insert at top
510
+ const timeCell = row.insertCell(0);
511
+ const scoreCell = row.insertCell(1);
512
+ const statusCell = row.insertCell(2);
513
+ const typeCell = row.insertCell(3);
514
+
515
+ timeCell.textContent = now.toLocaleTimeString();
516
+ scoreCell.textContent = result.score.toFixed(2);
517
+ statusCell.textContent = result.status;
518
+ statusCell.classList.add(result.is_anomaly ? 'text-danger' : 'text-success'); // Add color
519
+ typeCell.textContent = result.attack_type;
520
+
521
+ // Update Attack Breakdown Pie Chart
522
+ attackTypeCounts[result.attack_type]++;
523
+ } else {
524
+ // Always count benign events too, just for the pie chart
525
+ attackTypeCounts['Benign']++;
526
+ }
527
+ updateAttackBreakdownChart(); // Update pie chart
528
+
529
+ } catch (error) {
530
+ console.error("Fetch Error:", error);
531
+ anomalyStatusP.textContent = `Failed to connect to backend: ${error.message}. Is the Flask server running?`;
532
+ anomalyStatusP.style.color = '#dc3545';
533
+ }
534
+ }
535
+
536
+ // Update dashboard metrics
537
+ async function updateMetrics() {
538
+ try {
539
+ const response = await fetch('/api/metrics');
540
+ const metrics = await response.json();
541
+ document.getElementById('totalTransactions').textContent = metrics.totalTransactions.toLocaleString();
542
+ document.getElementById('threatsDetected').textContent = metrics.threatsDetected.toLocaleString();
543
+ document.getElementById('blockedAttempts').textContent = metrics.blockedAttempts.toLocaleString();
544
+ document.getElementById('activeUsers').textContent = metrics.activeUsers.toLocaleString();
545
+ } catch (error) {
546
+ console.error("Error fetching metrics:", error);
547
+ }
548
+ }
549
+
550
+ // Update Daily Attack Breakdown Pie Chart data
551
+ function updateAttackBreakdownChart() {
552
+ attackBreakdownChart.data.datasets[0].data = Object.values(attackTypeCounts);
553
+ attackBreakdownChart.update();
554
+ }
555
+
556
+ function startSimulation() {
557
+ if (isSimulationRunning) return; // Prevent multiple intervals
558
+
559
+ simulationIntervalId = setInterval(() => {
560
+ sendLogForAnalysis(); // Send random log
561
+ updateMetrics(); // Update general metrics
562
+ }, 2000); // Update every 2 seconds
563
+
564
+ isSimulationRunning = true;
565
+ beginSimulationBtn.disabled = true;
566
+ stopSimulationBtn.disabled = false;
567
+ simulationStatusSpan.textContent = "Simulation Running";
568
+ simulationStatusSpan.classList.remove('bg-info', 'bg-warning');
569
+ simulationStatusSpan.classList.add('bg-success');
570
+ console.log("Simulation started.");
571
+ }
572
+
573
+ function stopSimulation() {
574
+ clearInterval(simulationIntervalId);
575
+ isSimulationRunning = false;
576
+ beginSimulationBtn.disabled = false;
577
+ stopSimulationBtn.disabled = true;
578
+ simulationStatusSpan.textContent = "Simulation Stopped";
579
+ simulationStatusSpan.classList.remove('bg-success');
580
+ simulationStatusSpan.classList.add('bg-warning');
581
+ console.log("Simulation stopped.");
582
+ }
583
+
584
+ // Initial setup and event listeners
585
+ document.addEventListener('DOMContentLoaded', () => {
586
+ initializeAnomalyScoreChart();
587
+ initializeAttackBreakdownChart();
588
+ updateMetrics(); // Load initial metrics and display "Waiting for data..."
589
+
590
+ // Attach event listeners to buttons
591
+ beginSimulationBtn.addEventListener('click', startSimulation);
592
+ stopSimulationBtn.addEventListener('click', stopSimulation);
593
+ });
594
+ </script>
595
+ </body>
596
+ </html>
zero_day_encoder_model.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ac1b03784b431f49910c82c888f642098dcf6986d1ff5a9467eae4522c30ff9f
3
+ size 83102