MUFASA25 commited on
Commit
d90bb5e
·
verified ·
1 Parent(s): 4f54bf0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +313 -7
app.py CHANGED
@@ -3,11 +3,26 @@ import torch
3
  from transformers import AutoTokenizer, AutoModelForSequenceClassification
4
  import logging
5
  import re
 
 
 
 
 
 
6
 
7
- # Configure logging (minimal)
8
  logging.basicConfig(level=logging.INFO)
9
  logger = logging.getLogger(__name__)
10
 
 
 
 
 
 
 
 
 
 
11
  # Model configuration
12
  MODEL_NAME = "cybersectony/phishing-email-detection-distilbert_v2.4.1"
13
 
@@ -26,6 +41,50 @@ Higher percentages indicate greater certainty.
26
  tokenizer = None
27
  model = None
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  def load_model():
30
  """Load the model and tokenizer with basic error handling"""
31
  global tokenizer, model
@@ -49,9 +108,9 @@ def is_valid_email_text(text):
49
  return True, ""
50
 
51
  def get_colored_bar(percentage):
52
- """Create a simple colored bar based on percentage"""
53
  if percentage >= 85:
54
- color = "🟢" if percentage >= 85 else "🟥"
55
  elif percentage >= 50:
56
  color = "🟡"
57
  else:
@@ -59,8 +118,11 @@ def get_colored_bar(percentage):
59
  bar_length = max(1, int(percentage / 5)) # Scale to 20 characters
60
  return color * bar_length + "⚪" * (20 - bar_length)
61
 
62
- def predict_email(email_text):
63
- """Simplified prediction with actual labels and colored bars"""
 
 
 
64
  # Input validation
65
  valid, message = is_valid_email_text(email_text)
66
  if not valid:
@@ -97,7 +159,251 @@ def predict_email(email_text):
97
  # Get top prediction
98
  max_label, max_prob = max(results.items(), key=lambda x: x[1])
99
 
100
- # Risk levels with higher threshold (85%)
101
- if "phishing" in max_label.lower() or "suspicious" in max_label.lower():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
 
 
 
103
 
 
 
 
3
  from transformers import AutoTokenizer, AutoModelForSequenceClassification
4
  import logging
5
  import re
6
+ from flask import Flask, request, jsonify, render_template_string, redirect, url_for
7
+ from flask_login import LoginManager, UserMixin, login_required, login_user, logout_user, current_user
8
+ import sqlite3
9
+ from functools import wraps
10
+ from datetime import datetime
11
+ import bleach
12
 
13
+ # Configure logging
14
  logging.basicConfig(level=logging.INFO)
15
  logger = logging.getLogger(__name__)
16
 
17
+ # Flask app setup
18
+ app = Flask(__name__)
19
+ app.secret_key = 'secure_gov_key_2025' # Replace with a secure key in production
20
+
21
+ # Initialize Flask-Login
22
+ login_manager = LoginManager()
23
+ login_manager.init_app(app)
24
+ login_manager.login_view = "login"
25
+
26
  # Model configuration
27
  MODEL_NAME = "cybersectony/phishing-email-detection-distilbert_v2.4.1"
28
 
 
41
  tokenizer = None
42
  model = None
43
 
44
+ # User class for Flask-Login
45
+ class User(UserMixin):
46
+ def __init__(self, user_id, role):
47
+ self.id = user_id
48
+ self.role = role
49
+
50
+ # Database setup
51
+ def init_db():
52
+ with sqlite3.connect('phishguardian.db') as conn:
53
+ c = conn.cursor()
54
+ c.execute('''CREATE TABLE IF NOT EXISTS users
55
+ (id TEXT PRIMARY KEY, username TEXT, password TEXT, role TEXT)''')
56
+ c.execute('''CREATE TABLE IF NOT EXISTS analysis_logs
57
+ (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT, email_text TEXT,
58
+ result TEXT, timestamp TEXT)''')
59
+ # Add default admin user (password: 'admin123' for demo, use hashed passwords in production)
60
+ c.execute("INSERT OR IGNORE INTO users (id, username, password, role) VALUES (?, ?, ?, ?)",
61
+ ('admin1', 'admin', 'admin123', 'Admin'))
62
+ conn.commit()
63
+
64
+ # Load user for Flask-Login
65
+ @login_manager.user_loader
66
+ def load_user(user_id):
67
+ with sqlite3.connect('phishguardian.db') as conn:
68
+ c = conn.cursor()
69
+ c.execute("SELECT id, role FROM users WHERE id = ?", (user_id,))
70
+ user = c.fetchone()
71
+ if user:
72
+ return User(user[0], user[1])
73
+ return None
74
+
75
+ # RBAC decorator
76
+ def role_required(*roles):
77
+ def decorator(f):
78
+ @wraps(f)
79
+ def decorated_function(*args, **kwargs):
80
+ if not current_user.is_authenticated:
81
+ return redirect(url_for('login'))
82
+ if current_user.role not in roles:
83
+ return render_template_string("<h1>403 Forbidden</h1><p>Unauthorized role.</p>")
84
+ return f(*args, **kwargs)
85
+ return decorated_function
86
+ return decorator
87
+
88
  def load_model():
89
  """Load the model and tokenizer with basic error handling"""
90
  global tokenizer, model
 
108
  return True, ""
109
 
110
  def get_colored_bar(percentage):
111
+ """Create a colored bar based on percentage"""
112
  if percentage >= 85:
113
+ color = "🟢"
114
  elif percentage >= 50:
115
  color = "🟡"
116
  else:
 
118
  bar_length = max(1, int(percentage / 5)) # Scale to 20 characters
119
  return color * bar_length + "⚪" * (20 - bar_length)
120
 
121
+ def predict_email(email_text, user_id):
122
+ """Prediction with actual labels and colored bars"""
123
+ # Sanitize input
124
+ email_text = bleach.clean(email_text, tags=[], strip=True)
125
+
126
  # Input validation
127
  valid, message = is_valid_email_text(email_text)
128
  if not valid:
 
159
  # Get top prediction
160
  max_label, max_prob = max(results.items(), key=lambda x: x[1])
161
 
162
+ # Risk levels with 85% threshold
163
+ if "phishing" in max_label.lower() or "suspicious" in max_label.lower():
164
+ risk_level = "⚠️ Risky" if max_prob >= 85 else "⚡ Low Risk"
165
+ elif "spam" in max_label.lower():
166
+ risk_level = "🗑️ Spam" if max_prob >= 85 else "⚡ Low Risk"
167
+ else:
168
+ risk_level = "✅ Safe" if max_prob >= 85 else "❓ Uncertain"
169
+
170
+ # Format output
171
+ output = f"Result: {risk_level}\n"
172
+ output += f"Top Prediction: {max_label} ({max_prob:.1f}%)\n"
173
+ output += "Details:\n"
174
+ for label, prob in sorted(results.items(), key=lambda x: x[1], reverse=True):
175
+ output += f"{label}: {prob:.1f}% {get_colored_bar(prob)}\n"
176
+
177
+ # Simple recommendation
178
+ if "phishing" in max_label.lower() or "suspicious" in max_label.lower():
179
+ output += "Advice: Avoid clicking links or sharing info."
180
+ elif "spam" in max_label.lower():
181
+ output += "Advice: Mark as spam or delete."
182
+ else:
183
+ output += "Advice: Appears safe, but stay cautious."
184
+
185
+ # Log analysis
186
+ with sqlite3.connect('phishguardian.db') as conn:
187
+ c = conn.cursor()
188
+ c.execute("INSERT INTO analysis_logs (user_id, email_text, result, timestamp) VALUES (?, ?, ?, ?)",
189
+ (user_id, email_text[:1000], output, datetime.utcnow().isoformat()))
190
+ conn.commit()
191
+
192
+ return output
193
+
194
+ except Exception as e:
195
+ logger.error(f"Error during prediction: {e}")
196
+ return f"❌ Error: Analysis failed - {str(e)}"
197
+
198
+ # Flask routes
199
+ @app.route('/')
200
+ def index():
201
+ if not current_user.is_authenticated:
202
+ return redirect(url_for('login'))
203
+ return render_template_string("""
204
+ <!DOCTYPE html>
205
+ <html>
206
+ <head>
207
+ <title>PhishGuardian - MDA Email System</title>
208
+ <style>
209
+ body { font-family: Arial, sans-serif; margin: 20px; background-color: #f4f4f9; }
210
+ h1 { color: #333; }
211
+ .container { max-width: 800px; margin: auto; }
212
+ textarea { width: 100%; height: 200px; margin-bottom: 10px; }
213
+ button { padding: 10px 20px; margin-right: 10px; }
214
+ pre { background-color: #fff; padding: 15px; border: 1px solid #ddd; }
215
+ .error { color: red; }
216
+ </style>
217
+ </head>
218
+ <body>
219
+ <div class="container">
220
+ <h1>🛡️ PhishGuardian - MDA Email System</h1>
221
+ <p>Analyze emails for safety. Paste email text below.</p>
222
+ <p><b>Labels</b>: Legitimate (safe), Phishing (scam), Suspicious (questionable), Spam (junk). Percentages show confidence (0-100%).</p>
223
+ {% if current_user.is_authenticated %}
224
+ <p>Logged in as: {{ current_user.id }} ({{ current_user.role }}) | <a href="{{ url_for('logout') }}">Logout</a></p>
225
+ {% if current_user.role in ['Admin', 'Analyst'] %}
226
+ <form method="POST" action="{{ url_for('analyze') }}">
227
+ <textarea name="email_text" placeholder="Paste email here..."></textarea>
228
+ <button type="submit">🔍 Check</button>
229
+ <button type="button" onclick="document.querySelector('textarea').value=''">🗑️ Clear</button>
230
+ </form>
231
+ {% if result %}
232
+ <h3>Results</h3>
233
+ <pre>{{ result }}</pre>
234
+ {% endif %}
235
+ {% endif %}
236
+ {% if current_user.role in ['Admin', 'Auditor'] %}
237
+ <p><a href="{{ url_for('view_logs') }}">View Analysis Logs</a></p>
238
+ {% endif %}
239
+ {% if current_user.role == 'Admin' %}
240
+ <p><a href="{{ url_for('manage_users') }}">Manage Users</a></p>
241
+ {% endif %}
242
+ {% endif %}
243
+ </div>
244
+ </body>
245
+ </html>
246
+ """, result=request.args.get('result', ''))
247
+
248
+ @app.route('/login', methods=['GET', 'POST'])
249
+ def login():
250
+ if request.method == 'POST':
251
+ username = bleach.clean(request.form['username'])
252
+ password = bleach.clean(request.form['password'])
253
+ with sqlite3.connect('phishguardian.db') as conn:
254
+ c = conn.cursor()
255
+ c.execute("SELECT id, role FROM users WHERE username = ? AND password = ?", (username, password))
256
+ user = c.fetchone()
257
+ if user:
258
+ login_user(User(user[0], user[1]))
259
+ return redirect(url_for('index'))
260
+ return render_template_string("<h1>Login Failed</h1><p>Invalid credentials.</p>")
261
+ return render_template_string("""
262
+ <!DOCTYPE html>
263
+ <html>
264
+ <head>
265
+ <title>Login - PhishGuardian</title>
266
+ <style>
267
+ body { font-family: Arial, sans-serif; margin: 20px; background-color: #f4f4f9; }
268
+ .container { max-width: 400px; margin: auto; }
269
+ input { width: 100%; padding: 10px; margin-bottom: 10px; }
270
+ button { padding: 10px 20px; }
271
+ </style>
272
+ </head>
273
+ <body>
274
+ <div class="container">
275
+ <h1>Login</h1>
276
+ <form method="POST">
277
+ <input type="text" name="username" placeholder="Username" required>
278
+ <input type="password" name="password" placeholder="Password" required>
279
+ <button type="submit">Login</button>
280
+ </form>
281
+ </div>
282
+ </body>
283
+ </html>
284
+ """)
285
+
286
+ @app.route('/logout')
287
+ @login_required
288
+ def logout():
289
+ logout_user()
290
+ return redirect(url_for('login'))
291
+
292
+ @app.route('/analyze', methods=['POST'])
293
+ @role_required('Admin', 'Analyst')
294
+ def analyze():
295
+ email_text = request.form['email_text']
296
+ result = predict_email(email_text, current_user.id)
297
+ return redirect(url_for('index', result=result))
298
+
299
+ @app.route('/logs')
300
+ @role_required('Admin', 'Auditor')
301
+ def view_logs():
302
+ with sqlite3.connect('phishguardian.db') as conn:
303
+ c = conn.cursor()
304
+ c.execute("SELECT user_id, email_text, result, timestamp FROM analysis_logs ORDER BY timestamp DESC")
305
+ logs = c.fetchall()
306
+ logs_html = "<h3>Analysis Logs</h3><ul>" + "".join(
307
+ f"<li><b>{log[3]}</b> | User: {log[0]} | Email: {log[1][:50]}... | Result: {log[2][:100]}...</li>"
308
+ for log in logs
309
+ ) + "</ul>"
310
+ return render_template_string("""
311
+ <!DOCTYPE html>
312
+ <html>
313
+ <head>
314
+ <title>Logs - PhishGuardian</title>
315
+ <style>
316
+ body { font-family: Arial, sans-serif; margin: 20px; background-color: #f4f4f9; }
317
+ .container { max-width: 800px; margin: auto; }
318
+ ul { list-style-type: none; padding: 0; }
319
+ li { margin-bottom: 10px; }
320
+ </style>
321
+ </head>
322
+ <body>
323
+ <div class="container">
324
+ <h1>Analysis Logs</h1>
325
+ <p><a href="{{ url_for('index') }}">Back to Home</a></p>
326
+ {{ logs_html | safe }}
327
+ </div>
328
+ </body>
329
+ </html>
330
+ """, logs_html=logs_html)
331
+
332
+ @app.route('/users', methods=['GET', 'POST'])
333
+ @role_required('Admin')
334
+ def manage_users():
335
+ if request.method == 'POST':
336
+ username = bleach.clean(request.form['username'])
337
+ password = bleach.clean(request.form['password'])
338
+ role = bleach.clean(request.form['role'])
339
+ user_id = f"user_{datetime.utcnow().timestamp()}"
340
+ with sqlite3.connect('phishguardian.db') as conn:
341
+ c = conn.cursor()
342
+ c.execute("INSERT INTO users (id, username, password, role) VALUES (?, ?, ?, ?)",
343
+ (user_id, username, password, role))
344
+ conn.commit()
345
+ return redirect(url_for('manage_users'))
346
+ with sqlite3.connect('phishguardian.db') as conn:
347
+ c = conn.cursor()
348
+ c.execute("SELECT id, username, role FROM users")
349
+ users = c.fetchall()
350
+ users_html = "<h3>Users</h3><ul>" + "".join(
351
+ f"<li>ID: {user[0]} | Username: {user[1]} | Role: {user[2]}</li>" for user in users
352
+ ) + "</ul>"
353
+ return render_template_string("""
354
+ <!DOCTYPE html>
355
+ <html>
356
+ <head>
357
+ <title>Manage Users - PhishGuardian</title>
358
+ <style>
359
+ body { font-family: Arial, sans-serif; margin: 20px; background-color: #f4f4f9; }
360
+ .container { max-width: 800px; margin: auto; }
361
+ input, select { width: 100%; padding: 10px; margin-bottom: 10px; }
362
+ button { padding: 10px 20px; }
363
+ ul { list-style-type: none; padding: 0; }
364
+ </style>
365
+ </head>
366
+ <body>
367
+ <div class="container">
368
+ <h1>Manage Users</h1>
369
+ <p><a href="{{ url_for('index') }}">Back to Home</a></p>
370
+ <form method="POST">
371
+ <input type="text" name="username" placeholder="Username" required>
372
+ <input type="password" name="password" placeholder="Password" required>
373
+ <select name="role">
374
+ <option value="Admin">Admin</option>
375
+ <option value="Analyst">Analyst</option>
376
+ <option value="Auditor">Auditor</option>
377
+ </select>
378
+ <button type="submit">Add User</button>
379
+ </form>
380
+ {{ users_html | safe }}
381
+ </div>
382
+ </body>
383
+ </html>
384
+ """, users_html=users_html)
385
+
386
+ # Example emails
387
+ example_legitimate = """Dear Customer,
388
+ Thank you for your purchase from TechStore. Your order #ORD-2024-001234 is processed.
389
+ Order Details:
390
+ - Product: Wireless Headphones
391
+ - Amount: $79.99
392
+ - Delivery: 3-5 days
393
+ Best regards,
394
+ TechStore"""
395
+ example_phishing = """URGENT!!!
396
+ Your account is COMPROMISED! Click here to secure: http://fake-site.com/verify
397
+ Act NOW or your account will be suspended!
398
+ Security Team"""
399
+ example_neutral = """Hi team,
400
+ Reminder: meeting tomorrow at 2 PM. Bring project updates.
401
+ Thanks,
402
+ Sarah"""
403
 
404
+ # Initialize database and load model
405
+ init_db()
406
+ load_model()
407
 
408
+ if __name__ == "__main__":
409
+ app.run(ssl_context='adhoc', host='0.0.0.0', port=5000)