"
+ ]
}
]
}
diff --git a/apps/extension/src/popup/components/AdblockPanel.jsx b/apps/extension/src/popup/components/AdblockPanel.jsx
index 5eef21a..019f000 100644
--- a/apps/extension/src/popup/components/AdblockPanel.jsx
+++ b/apps/extension/src/popup/components/AdblockPanel.jsx
@@ -217,6 +217,7 @@ export function AdblockPanel() {
const [tabId, setTabId] = useState(null);
const [blocked, setBlocked] = useState(null);
const [blockedBusy, setBlockedBusy] = useState(false);
+ const [security, setSecurity] = useState(null);
const [loading, setLoading] = useState(true);
const [busy, setBusy] = useState(false);
@@ -239,11 +240,24 @@ export function AdblockPanel() {
let res = await sendMessage({ type: 'SYNC_ADBLOCK_CLOUD' });
if (!res?.success) res = await sendMessage({ type: 'GET_ADBLOCK_STATUS' });
if (res?.success) setStatus(res);
+
+ // Phishing protection keeps its own prefs (and its own cloud blob key).
+ let sec = await sendMessage({ type: 'SYNC_SECURITY_CLOUD' });
+ if (!sec?.success) sec = await sendMessage({ type: 'GET_SECURITY_STATUS' });
+ if (sec?.success) setSecurity(sec);
+
setLoading(false);
loadBlocked(tab.id);
})();
}, [loadBlocked]);
+ const applySecurity = async (message) => {
+ setBusy(true);
+ const res = await sendMessage(message);
+ if (res?.success) setSecurity(res);
+ setBusy(false);
+ };
+
const apply = async (message, optimistic) => {
setBusy(true);
if (optimistic) setStatus((s) => (s ? { ...s, ...optimistic } : s));
@@ -314,6 +328,79 @@ export function AdblockPanel() {
+ {/* Phishing & scam protection — independent of the ad/tracker blocker, so
+ it stays on for a site the user has allowlisted for ads. */}
+ {security && (
+
+
+
+
+
+
Scam & phishing
+
+ {security.enabled
+ ? `${(security.listCount || 0).toLocaleString()} dangerous sites blocked`
+ : 'Turned off'}
+
+
+
+
+ applySecurity({ type: 'SET_SECURITY_ENABLED', payload: { enabled: v } })
+ }
+ disabled={busy}
+ label="Enable phishing and scam protection"
+ />
+
+
+ {security.enabled && security.bypasses?.length > 0 && (
+
+
+ Warnings you dismissed
+
+
+ {security.bypasses.map((d) => (
+
+ {d}
+
+
+ ))}
+
+
+ )}
+
+ )}
+
{/* Per-site allowlist */}
{domain ? (
{
popup: resolve(__dirname, 'src/popup/index.html'),
background: resolve(__dirname, 'src/background/index.js'),
options: resolve(__dirname, 'src/options/index.html'),
+ blocked: resolve(__dirname, 'src/blocked/index.html'),
},
output: {
entryFileNames: '[name]/index.js',