Spaces:
Running
Running
| /** | |
| * PhishShield β background.js (Service Worker) v1.2 | |
| * Handles extension lifecycle, badge updates, and inter-component messaging. | |
| * | |
| * NOTE: Make sure your popup saves scan records with these exact field names: | |
| * subject β email subject line | |
| * sender β from address | |
| * risk_level β "High Risk" | "Medium Risk" | "Low Risk" | "Safe" | |
| * risk_score β number 0β10 | |
| * is_phishing β boolean | |
| * timestamp β Date.now() milliseconds | |
| * xai_explanation β AI explanation string (optional) | |
| * rag_match β RAG match string (optional) | |
| */ | |
| ; | |
| // ββ Badge config βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| const BADGE_CONFIG = { | |
| "High Risk": { text: "!", color: "#dc2626" }, | |
| "Medium Risk": { text: "!!", color: "#d97706" }, | |
| "Low Risk": { text: "β²", color: "#1e6aff" }, | |
| "Safe": { text: "β", color: "#10b981" }, | |
| }; | |
| // ββ Badge helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function setBadge(tabId, riskLevel) { | |
| const cfg = BADGE_CONFIG[riskLevel]; | |
| if (!cfg) { clearBadge(tabId); return; } | |
| chrome.action.setBadgeText({ tabId, text: cfg.text }); | |
| chrome.action.setBadgeBackgroundColor({ tabId, color: cfg.color }); | |
| chrome.action.setBadgeTextColor?.({ tabId, color: "#ffffff" }); | |
| } | |
| function clearBadge(tabId) { | |
| chrome.action.setBadgeText({ tabId, text: "" }); | |
| } | |
| // ββ Risk severity helper βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function shouldWarn(riskLevel) { | |
| return riskLevel === "High Risk" || riskLevel === "Medium Risk"; | |
| } | |
| // ββ Message listener βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { | |
| // Popup β background: analysis complete β update badge + optionally inject banner | |
| if (msg.action === "analysisComplete") { | |
| const tabId = msg.tabId; | |
| setBadge(tabId, msg.riskLevel); | |
| if (msg.isPhishing && shouldWarn(msg.riskLevel)) { | |
| chrome.tabs.sendMessage(tabId, { | |
| action: "showWarning", | |
| riskLevel: msg.riskLevel, | |
| reason: msg.reason, | |
| badgeColor: BADGE_CONFIG[msg.riskLevel]?.color ?? "#dc2626", | |
| }).catch(() => {}); | |
| } | |
| sendResponse({ ok: true }); | |
| return true; | |
| } | |
| // Clear badge on explicit request | |
| if (msg.action === "clearBadge") { | |
| clearBadge(sender.tab?.id); | |
| sendResponse({ ok: true }); | |
| return true; | |
| } | |
| // Popup requests the latest history entry count for the badge label | |
| if (msg.action === "getHistoryCount") { | |
| chrome.storage.local.get("scan_history", (res) => { | |
| const count = (res.scan_history || []).length; | |
| sendResponse({ count }); | |
| }); | |
| return true; | |
| } | |
| }); | |
| // ββ Tab lifecycle ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| chrome.tabs.onUpdated.addListener((tabId, changeInfo) => { | |
| if (changeInfo.status === "loading") { | |
| clearBadge(tabId); | |
| } | |
| }); | |
| // ββ Storage: prune history to 200 entries ββββββββββββββββββββββββββββββββββββββ | |
| chrome.storage.onChanged.addListener((changes, area) => { | |
| if (area !== "local" || !changes.scan_history) return; | |
| const history = changes.scan_history.newValue || []; | |
| if (history.length > 200) { | |
| const pruned = history.slice(history.length - 200); | |
| chrome.storage.local.set({ scan_history: pruned }); | |
| } | |
| }); | |
| // ββ Install / Update βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| chrome.runtime.onInstalled.addListener(({ reason }) => { | |
| if (reason === "install") { | |
| console.log("[PhishShield] Installed β ready to protect your inbox. π‘"); | |
| chrome.storage.local.set({ scan_history: [] }); | |
| } else if (reason === "update") { | |
| console.log("[PhishShield] Updated to latest version."); | |
| } | |
| }); | |