commit 2dcd2a1b94a170ce2a4ca705d4005d7aa9fc213f Author: Alicja Date: Fri May 31 22:49:37 2024 +0200 Moving the project to the final repository diff --git a/backend/.idea/.gitignore b/backend/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/backend/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/backend/.idea/.name b/backend/.idea/.name new file mode 100644 index 0000000..5c7471e --- /dev/null +++ b/backend/.idea/.name @@ -0,0 +1 @@ +backend.py \ No newline at end of file diff --git a/backend/.idea/backend.iml b/backend/.idea/backend.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/backend/.idea/backend.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/backend/.idea/inspectionProfiles/profiles_settings.xml b/backend/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/backend/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/backend/.idea/misc.xml b/backend/.idea/misc.xml new file mode 100644 index 0000000..a377feb --- /dev/null +++ b/backend/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/backend/.idea/modules.xml b/backend/.idea/modules.xml new file mode 100644 index 0000000..e066844 --- /dev/null +++ b/backend/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/backend/backend.py b/backend/backend.py new file mode 100644 index 0000000..6d375c7 --- /dev/null +++ b/backend/backend.py @@ -0,0 +1,202 @@ +from flask import Flask, request, jsonify, session +from flask_cors import CORS +import imaplib +import email +from email.header import decode_header +from sklearn.feature_extraction.text import TfidfVectorizer +from sklearn.naive_bayes import MultinomialNB +import traceback +import json +import os + +app = Flask(__name__) +CORS(app) +app.secret_key = 'your_secret_key' + +SAFE_EMAILS_FILE = 'safe_emails.json' + +# Load safe emails from file +def load_safe_emails(): + if os.path.exists(SAFE_EMAILS_FILE): + with open(SAFE_EMAILS_FILE, 'r') as file: + return json.load(file) + return [] + +# Save safe emails to file +def save_safe_emails(safe_emails): + with open(SAFE_EMAILS_FILE, 'w') as file: + json.dump(safe_emails, file) + +safe_emails = load_safe_emails() + +# Dane treningowe +training_data = [ + ("Urgent account verification", "support@example.com", 1), + ("Meeting agenda", "boss@example.com", 0), + ("Password reset request", "no-reply@example.com", 1), + ("Team lunch schedule", "hr@example.com", 0), + ("Suspicious login attempt", "security@example.com", 1), + ("Project update", "colleague@example.com", 0), + ("Verify your email address", "verification@example.com", 1), + ("Weekly report", "manager@example.com", 0), + ("Your account has been suspended", "no-reply@example.com", 1), + ("Company policy update", "admin@example.com", 0), + ("Immediate action required", "alert@example.com", 1), + ("Holiday party invitation", "events@example.com", 0), + ("Important security update", "security@example.com", 1), + ("Monthly performance review", "boss@example.com", 0), + ("Claim your prize now", "lottery@example.com", 1), + ("Training session details", "training@example.com", 0), + ("Unauthorized access detected", "alert@example.com", 1), + ("Office relocation notice", "admin@example.com", 0), + ("Confirm your subscription", "newsletter@example.com", 1), + ("Sales team meeting", "sales@example.com", 0), + ("Your payment is overdue", "billing@example.com", 1), + ("Client feedback", "client@example.com", 0), + ("Update your account details", "update@example.com", 1), + ("Social event invitation", "social@example.com", 0), + ("Action required: Update password", "security@example.com", 1), + ("New project assignment", "manager@example.com", 0), + ("Notice of data breach", "security@example.com", 1), + ("Weekly newsletter", "newsletter@example.com", 0), + ("Re: Your recent purchase", "support@example.com", 1), + ("Performance appraisal meeting", "hr@example.com", 0), + ("Important account notice", "no-reply@example.com", 1), + ("Quarterly earnings report", "finance@example.com", 0), + ("Urgent: Verify your identity", "security@example.com", 1), + ("Birthday celebration", "events@example.com", 0), +] + +subjects = [x[0] for x in training_data] +senders = [x[1] for x in training_data] +labels = [x[2] for x in training_data] + +# Połączenie tytułów i nadawców +combined_features = [s + ' ' + senders[i] for i, s in enumerate(subjects)] +vectorizer = TfidfVectorizer() +X = vectorizer.fit_transform(combined_features) +y = labels + +model = MultinomialNB() +model.fit(X, y) + +@app.route('/login', methods=['POST']) +def login(): + data = request.get_json() + username = data.get('username') + password = data.get('password') + + try: + mail = imaplib.IMAP4_SSL('imap.wp.pl') + mail.login(username, password) + session['username'] = username + session['password'] = password + return jsonify({'message': 'Login successful'}), 200 + except imaplib.IMAP4.error as e: + print(f'Login failed: {e}') + return jsonify({'message': 'Login failed'}), 401 + except Exception as e: + print('Error during login:', e) + traceback.print_exc() + return jsonify({'message': 'Internal server error'}), 500 + +@app.route('/check_mail', methods=['GET']) +def check_mail(): + if 'username' not in session or 'password' not in session: + return jsonify({'message': 'Not logged in'}), 401 + + username = session['username'] + password = session['password'] + + try: + mail = imaplib.IMAP4_SSL('imap.wp.pl') + mail.login(username, password) + mail.select('INBOX') + result, data = mail.search(None, 'ALL') + email_ids = data[0].split()[-10:] # Pobierz ostatnie 10 e-maili + emails = [] + + for e_id in email_ids: + result, email_data = mail.fetch(e_id, '(RFC822)') + raw_email = email_data[0][1] + msg = email.message_from_bytes(raw_email) + subject = decode_header_value(msg['subject']) + sender = decode_header_value(msg['from']) + is_phishing = detect_phishing(subject, sender, e_id.decode()) + emails.append({'subject': subject, 'from': sender, 'is_phishing': is_phishing, 'id': e_id.decode()}) + + return jsonify(emails), 200 + except Exception as e: + print('Error during email check:', e) + traceback.print_exc() + return jsonify({'message': 'Internal server error'}), 500 + +@app.route('/logout', methods=['POST']) +def logout(): + try: + session.pop('username', None) + session.pop('password', None) + return jsonify({'message': 'Logged out'}), 200 + except Exception as e: + print('Error during logout:', e) + traceback.print_exc() + return jsonify({'message': 'Internal server error'}), 500 + +@app.route('/mark_safe/', methods=['POST']) +def mark_safe(email_id): + global safe_emails + safe_emails.append(email_id) + save_safe_emails(safe_emails) + print(f'Email {email_id} marked as safe') + return jsonify({"message": f"Email {email_id} marked as safe"}), 200 + +@app.route('/move_trash/', methods=['POST']) +def move_trash(email_id): + if 'username' not in session or 'password' not in session: + return jsonify({'message': 'Not logged in'}), 401 + + username = session['username'] + password = session['password'] + + try: + mail = imaplib.IMAP4_SSL('imap.wp.pl') + mail.login(username, password) + mail.select('INBOX') + print(f'Trying to move email ID {email_id} to Trash') # Logging email ID + mail.store(email_id, '+FLAGS', '\\Deleted') + mail.expunge() + print(f'Email {email_id} deleted') # Logging deletion + return jsonify({"message": f"Email {email_id} deleted"}), 200 + except Exception as e: + print(f'Error during moving email to trash: {e}') + traceback.print_exc() + return jsonify({'message': 'Internal server error'}), 500 + +def decode_header_value(value): + parts = decode_header(value) + header_parts = [] + for part, encoding in parts: + if isinstance(part, bytes): + try: + if encoding: + header_parts.append(part.decode(encoding)) + else: + header_parts.append(part.decode('utf-8')) + except (LookupError, UnicodeDecodeError): + header_parts.append(part.decode('utf-8', errors='ignore')) + else: + header_parts.append(part) + return ''.join(header_parts) + +def detect_phishing(subject, sender, email_id): + if email_id in safe_emails: + return False # If email is marked as safe, it's not phishing + + phishing_keywords = ['urgent', 'verify', 'account', 'suspend', 'login'] + phishing_senders = ['support@example.com', 'no-reply@example.com'] + if any(keyword in subject.lower() for keyword in phishing_keywords) or sender.lower() in phishing_senders: + return True + return False + +if __name__ == '__main__': + app.run(port=5000) diff --git a/backend/safe_emails.json b/backend/safe_emails.json new file mode 100644 index 0000000..5c46c44 --- /dev/null +++ b/backend/safe_emails.json @@ -0,0 +1 @@ +["3", "13", "14", "15"] \ No newline at end of file diff --git a/extension/background.js b/extension/background.js new file mode 100644 index 0000000..540f1cd --- /dev/null +++ b/extension/background.js @@ -0,0 +1,51 @@ +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (message.type === 'phishing-detected') { + const emails = message.emails; + let notificationTitle = 'You are safe!'; + let notificationMessage = 'No phishing emails detected.'; + + const phishingEmails = emails.filter(email => email.is_phishing); + if (phishingEmails.length > 0) { + notificationTitle = 'You are in danger!'; + notificationMessage = `Email from ${phishingEmails[0].from} titled "${phishingEmails[0].subject}" has been identified as phishing.`; + + chrome.windows.create({ + url: 'notification.html', + type: 'popup', + width: 300, + height: 200 + }, function(window) { + chrome.storage.local.set({ + notificationTitle: notificationTitle, + notificationMessage: notificationMessage, + emailId: phishingEmails[0].id + }); + }); + } else { + chrome.windows.create({ + url: 'notification.html', + type: 'popup', + width: 300, + height: 200 + }, function(window) { + chrome.storage.local.set({ + notificationTitle: notificationTitle, + notificationMessage: notificationMessage, + emailId: null + }); + }); + } + } else if (message.type === 'mark-safe') { + fetch(`http://localhost:5000/mark_safe/${message.emailId}`, { + method: 'POST' + }).then(response => response.json()) + .then(data => console.log(data)) + .catch(error => console.error('Error:', error)); + } else if (message.type === 'move-trash') { + fetch(`http://localhost:5000/move_trash/${message.emailId}`, { + method: 'POST' + }).then(response => response.json()) + .then(data => console.log(data)) + .catch(error => console.error('Error:', error)); + } +}); diff --git a/extension/icon128.png b/extension/icon128.png new file mode 100644 index 0000000..650f0ec Binary files /dev/null and b/extension/icon128.png differ diff --git a/extension/icon16.png b/extension/icon16.png new file mode 100644 index 0000000..5bc6e8c Binary files /dev/null and b/extension/icon16.png differ diff --git a/extension/icon48.png b/extension/icon48.png new file mode 100644 index 0000000..7a38d41 Binary files /dev/null and b/extension/icon48.png differ diff --git a/extension/manifest.json b/extension/manifest.json new file mode 100644 index 0000000..f33e495 --- /dev/null +++ b/extension/manifest.json @@ -0,0 +1,28 @@ +{ + "manifest_version": 3, + "name": "PhishGuardian", + "version": "1.0", + "permissions": ["storage", "activeTab", "scripting", "notifications"], + "host_permissions": [ + "http://localhost:5000/*" + ], + "background": { + "service_worker": "background.js" + }, + "action": { + "default_popup": "popup.html", + "default_icon": { + "16": "icon16.png", + "48": "icon48.png", + "128": "icon128.png" + } + }, + "icons": { + "16": "icon16.png", + "48": "icon48.png", + "128": "icon128.png" + }, + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'" + } +} diff --git a/extension/notification.html b/extension/notification.html new file mode 100644 index 0000000..2ffc778 --- /dev/null +++ b/extension/notification.html @@ -0,0 +1,17 @@ + + + + + + Notification + + + +
+

+ + + +
+ + diff --git a/extension/notification.js b/extension/notification.js new file mode 100644 index 0000000..64a7bec --- /dev/null +++ b/extension/notification.js @@ -0,0 +1,47 @@ +document.addEventListener('DOMContentLoaded', function() { + const markSafeButton = document.getElementById('mark-safe'); + const moveTrashButton = document.getElementById('move-trash'); + const closeButton = document.getElementById('close'); + const notificationMessage = document.getElementById('notification-message'); + + chrome.storage.local.get(['notificationTitle', 'notificationMessage', 'emailId'], function(items) { + notificationMessage.textContent = items.notificationMessage; + + if (items.emailId) { + // Show action buttons if there's a phishing email + markSafeButton.style.display = 'inline-block'; + moveTrashButton.style.display = 'inline-block'; + } else { + // Hide action buttons if no phishing emails + markSafeButton.style.display = 'none'; + moveTrashButton.style.display = 'none'; + } + + markSafeButton.addEventListener('click', function() { + console.log('Mark Safe button clicked for emailId:', items.emailId); + chrome.runtime.sendMessage({ + type: 'mark-safe', + emailId: items.emailId + }, function(response) { + console.log('Mark safe response:', response); + }); + setTimeout(() => window.close(), 50); // Wait for 50ms before closing the window + }); + + moveTrashButton.addEventListener('click', function() { + console.log('Move to Trash button clicked for emailId:', items.emailId); + chrome.runtime.sendMessage({ + type: 'move-trash', + emailId: items.emailId + }, function(response) { + console.log('Move to trash response:', response); + }); + setTimeout(() => window.close(), 50); // Wait for 50ms before closing the window + }); + + closeButton.addEventListener('click', function() { + console.log('Close button clicked'); + window.close(); + }); + }); +}); diff --git a/extension/popup.html b/extension/popup.html new file mode 100644 index 0000000..5b7ad3b --- /dev/null +++ b/extension/popup.html @@ -0,0 +1,21 @@ + + + + + Phishing Email Detector + + + +
+

Login

+ + + +
+ +
+ + diff --git a/extension/popup.js b/extension/popup.js new file mode 100644 index 0000000..fa3fc67 --- /dev/null +++ b/extension/popup.js @@ -0,0 +1,92 @@ +document.addEventListener('DOMContentLoaded', function() { + const loginButton = document.getElementById('login'); + const checkMailButton = document.getElementById('check-mail'); + const logoutButton = document.getElementById('logout'); + const loginSection = document.getElementById('login-section'); + const controlSection = document.getElementById('control-section'); + + // Check if already logged in + chrome.storage.local.get(['username', 'password'], function(items) { + if (items.username && items.password) { + loginSection.style.display = 'none'; + controlSection.style.display = 'block'; + } else { + loginSection.style.display = 'block'; + controlSection.style.display = 'none'; + } + }); + + loginButton.addEventListener('click', function() { + const username = document.getElementById('username').value; + const password = document.getElementById('password').value; + + fetch('http://localhost:5000/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ username, password }), + credentials: 'include' + }) + .then(response => response.json()) + .then(data => { + alert(data.message); + if (data.message === 'Login successful') { + chrome.storage.local.set({ 'username': username, 'password': password }, function() { + loginSection.style.display = 'none'; + controlSection.style.display = 'block'; + }); + } + }) + .catch(error => { + console.error('Error during login request:', error); + alert('An error occurred while logging in'); + }); + }); + + checkMailButton.addEventListener('click', function() { + fetch('http://localhost:5000/check_mail', { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + }, + credentials: 'include' + }) + .then(response => response.json()) + .then(data => { + console.log('Check mail response:', data); + chrome.runtime.sendMessage({ + type: 'phishing-detected', + emails: data + }); + }) + .catch(error => { + console.error('Error during check mail request:', error); + alert('An error occurred while checking mail'); + }); + }); + + logoutButton.addEventListener('click', function() { + fetch('http://localhost:5000/logout', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + credentials: 'include' + }) + .then(response => response.json()) + .then(data => { + alert(data.message); + if (data.message === 'Logged out') { + chrome.storage.local.remove(['username', 'password'], function() { + loginSection.style.display = 'block'; + controlSection.style.display = 'none'; + }); + } + }) + .catch(error => { + console.error('Error during logout request:', error); + alert('An error occurred while logging out'); + }); + }); +});