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.");