// gmail_scanner.js console.log("PhishGuard AI: Gmail Scanner loaded."); // Gmail's DOM can change, but commonly the email text is stored in elements with class '.a3s' or '.ii.gt' const EMAIL_BODY_SELECTOR = '.a3s, .ii.gt'; // Function to inject a visible warning banner into the Gmail UI function injectWarningBanner(emailContainer, message) { // Prevent duplicate banners if one is already injected if (emailContainer.parentNode.querySelector('.phishguard-banner')) { return; } const banner = document.createElement('div'); banner.className = 'phishguard-banner'; // Styling the banner to look native but urgent, fitting Google's Material Design banner.style.backgroundColor = '#fce8e6'; banner.style.color = '#c5221f'; banner.style.border = '1px solid #faa59f'; banner.style.borderRadius = '8px'; banner.style.padding = '12px 16px'; // Added margin to ensure it doesn't overlap text awkwardly banner.style.margin = '16px auto'; banner.style.fontFamily = '"Google Sans", Roboto, Arial, sans-serif'; banner.style.fontSize = '14px'; banner.style.fontWeight = '500'; banner.style.lineHeight = '20px'; banner.style.display = 'flex'; banner.style.alignItems = 'center'; banner.style.boxShadow = '0 1px 2px 0 rgba(60,64,67,0.3), 0 1px 3px 1px rgba(60,64,67,0.15)'; // Add SVG Icon for warning const iconSvg = ` `; const textContent = document.createElement('span'); textContent.innerText = message || '🚨 PhishGuard Warning: This email contains suspicious links.'; // Construct the banner banner.innerHTML = iconSvg; banner.appendChild(textContent); // Insert banner at the top of the email container. // By inserting before the email container, we keep it visible at the top of the body. if (emailContainer.parentNode) { emailContainer.parentNode.insertBefore(banner, emailContainer); } } // Helper function to extract all unique URLs from the email body function extractUrlsFromBody(emailContainer) { const links = emailContainer.querySelectorAll('a[href]'); const urls = new Set(); // Use a Set to store unique URLs links.forEach(link => { const href = link.href; // Basic filter to ignore mailto: or javascript: links, and only keep http/https if (href && (href.startsWith('http://') || href.startsWith('https://'))) { urls.add(href); } }); return Array.from(urls); } // Function to safely extract the sender's actual email address function extractSenderEmail(emailContainer) { // Gmail usually groups each email message into a container block. // We traverse up to find a common parent containing both header and body. // '.kv' or 'table' or '.adn' is often the parent wrapper for an individual message. let messageWrapper = emailContainer.closest('.adn') || emailContainer.closest('.kv') || document; // The sender element usually has the class '.gD' and contains the 'email' attribute. const senderElement = messageWrapper.querySelector('.gD'); if (senderElement && senderElement.getAttribute('email')) { return senderElement.getAttribute('email'); } // Fallback: Sometimes the email address is enclosed in brackets inside a '.go' element. const fallbackSenderElement = messageWrapper.querySelector('.go'); if (fallbackSenderElement && fallbackSenderElement.innerText) { // e.g. "" -> matched and extracted const match = fallbackSenderElement.innerText.match(/<([^>]+)>/); if (match && match[1]) { return match[1]; } } return "Unknown Sender"; } // Function to handle newly opened emails function handleEmailOpened(emailContainer) { // Prevent re-scanning the same email element if (emailContainer.dataset.pgScanned === "true") { return; } console.log("PhishGuard AI: New email thread opened. Extracting data..."); // Mark as scanned emailContainer.dataset.pgScanned = "true"; // 1. Extract plain text content const emailBodyText = emailContainer.innerText; // 2. Extract embedded URLs const urls = extractUrlsFromBody(emailContainer); // 3. Extract sender email address const sender = extractSenderEmail(emailContainer); // 4. Extract subject line (.hP is a standard class for Gmail's main subject line) // Sometimes the subject might be in a '.bog' element. We'll default to 'h2.hP'. const subjectElement = document.querySelector('h2.hP') || document.querySelector('.bog'); const subject = subjectElement ? subjectElement.innerText.trim() : "No Subject Found"; // Package the extracted data into a JSON payload const emailPayload = { sender: sender, subject: subject, body: emailBodyText, urls: urls, timestamp: new Date().toISOString() }; console.log("PhishGuard AI extracted payload:", emailPayload); // Send background message to service worker chrome.runtime.sendMessage( { action: "analyzeEmail", data: emailPayload }, (response) => { if (chrome.runtime.lastError) { console.error("PhishGuard AI: Error communicating with background script:", chrome.runtime.lastError); return; } console.log("PhishGuard AI Background Analysis Response:", response); // Assume the background script returns `response.analysis` containing `probability` or `isPhishing` flag const analysis = response && response.analysis ? response.analysis : {}; if (analysis.isPhishing === true || analysis.probability > 0.70) { console.warn("PhishGuard AI: High risk email detected! Injecting banner..."); injectWarningBanner( emailContainer, '🚨 PhishGuard Warning: This email contains suspicious links and exhibits high-risk phishing behavior.' ); } } ); } // Set up a MutationObserver to watch for DOM changes // This effectively detects when Gmail dynamically loads an individual email view into the DOM const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if (mutation.type === 'childList') { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { // Check if the added node itself is the email body container if (node.matches && node.matches(EMAIL_BODY_SELECTOR)) { handleEmailOpened(node); } // Also search securely within the added node structure for the email body if (node.querySelectorAll) { const emailBodies = node.querySelectorAll(EMAIL_BODY_SELECTOR); emailBodies.forEach(body => handleEmailOpened(body)); } } }); } } }); // Start observing the document body for deeper added nodes (like when navigating between emails) observer.observe(document.body, { childList: true, subtree: true }); console.log("PhishGuard AI: MutationObserver is listening for email thread opens.");