Spaces:
Running
Running
File size: 7,750 Bytes
bebe233 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | // 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 = `
<svg focusable="false" width="24" height="24" viewBox="0 0 24 24" style="fill: #c5221f; margin-right: 16px; flex-shrink: 0;">
<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"></path>
</svg>
`;
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. "<sender@example.com>" -> 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.");
|