import SubstitutionEngine from '../lib/substitution-engine.js'; import SmartPatterns from '../lib/smart-patterns.js'; import SecretScanner from '../lib/secret-scanner.js'; import Storage from '../lib/storage.js'; import api from '../lib/browser-polyfill.js'; // --- State --- let mappings = []; let identity = {}; let settings = {}; // --- DOM refs --- const $ = (sel) => document.querySelector(sel); const $$ = (sel) => document.querySelectorAll(sel); // --- Init --- document.addEventListener('DOMContentLoaded', async () => { mappings = await Storage.getMappings(); identity = await Storage.getIdentity(); settings = await Storage.getSettings(); renderMappings(); renderActivity(); loadIdentityForm(); updateStatusDot(); checkFirstRun(); $('#enableToggle').checked = settings.enabled; // Tab switching $$('.tab').forEach((tab) => { tab.addEventListener('click', () => { $$('.tab').forEach((t) => t.classList.remove('active')); $$('.tab-content').forEach((c) => c.classList.remove('active')); tab.classList.add('active'); $(`#tab-${tab.dataset.tab}`).classList.add('active'); if (tab.dataset.tab === 'activity') renderActivity(); if (tab.dataset.tab === 'test') { // Reload identity from storage in case it was just saved Storage.getIdentity().then((id) => { identity = id; updateIdentityStatus(); }); } }); }); // Enable toggle $('#enableToggle').addEventListener('change', async (e) => { settings.enabled = e.target.checked; await Storage.saveSettings(settings); updateStatusDot(); api.runtime.sendMessage({ type: 'update:settings', settings, }); }); // Reveal mode toggle $('#btnReveal').addEventListener('click', async () => { settings.revealMode = !settings.revealMode; await Storage.saveSettings(settings); $('#btnReveal').classList.toggle('active', settings.revealMode); api.runtime.sendMessage({ type: 'update:settings', settings, }); }); $('#btnReveal').classList.toggle('active', settings.revealMode); // Save identity $('#btnSaveIdentity').addEventListener('click', saveIdentity); // Add mapping $('#btnAdd').addEventListener('click', addMapping); $('#inputSub').addEventListener('keydown', (e) => { if (e.key === 'Enter') addMapping(); }); // Clear log $('#btnClearLog').addEventListener('click', async () => { await Storage.clearLog(); renderActivity(); }); // Test tab - live diff + reveal $('#testInput').addEventListener('input', renderTestDiff); $('#revealInput').addEventListener('input', renderRevealDiff); $('#btnCopyRevealed').addEventListener('click', copyRevealedText); // Test mode toggle (strip vs reveal) $$('.test-mode-btn').forEach((btn) => { btn.addEventListener('click', () => { $$('.test-mode-btn').forEach((b) => b.classList.remove('active')); btn.classList.add('active'); const mode = btn.dataset.mode; $('#stripMode').style.display = mode === 'strip' ? 'block' : 'none'; $('#revealMode').style.display = mode === 'reveal' ? 'block' : 'none'; }); }); // Options link $('#btnOptions').addEventListener('click', (e) => { e.preventDefault(); api.runtime.openOptionsPage(); }); }); // --- Identity --- function loadIdentityForm() { const first = (identity.names || []).find(n => n.type === 'first'); const last = (identity.names || []).find(n => n.type === 'last'); const email = (identity.emails || [])[0]; const user = (identity.usernames || [])[0]; const phone = (identity.phones || [])[0]; if (first) { $('#idFirstReal').value = first.real || ''; $('#idFirstSub').value = first.substitute || ''; } if (last) { $('#idLastReal').value = last.real || ''; $('#idLastSub').value = last.substitute || ''; } if (email) { $('#idEmailReal').value = email.real || ''; $('#idEmailSub').value = email.substitute || ''; } $('#idCatchAllEmail').value = identity.catchAllEmail || ''; if (user) { $('#idUserReal').value = user.real || ''; $('#idUserSub').value = user.substitute || ''; } const host = (identity.hostnames || [])[0]; if (host) { $('#idHostReal').value = host.real || ''; $('#idHostSub').value = host.substitute || ''; } if (phone) { $('#idPhoneReal').value = phone.real || ''; $('#idPhoneSub').value = phone.substitute || ''; } } async function saveIdentity() { const names = []; const firstReal = $('#idFirstReal').value.trim(); const firstSub = $('#idFirstSub').value.trim(); if (firstReal && firstSub) { names.push({ real: firstReal, substitute: firstSub, type: 'first' }); } const lastReal = $('#idLastReal').value.trim(); const lastSub = $('#idLastSub').value.trim(); if (lastReal && lastSub) { names.push({ real: lastReal, substitute: lastSub, type: 'last' }); } const emails = []; const emailReal = $('#idEmailReal').value.trim(); const emailSub = $('#idEmailSub').value.trim(); if (emailReal && emailSub) { emails.push({ real: emailReal, substitute: emailSub }); } const usernames = []; const userReal = $('#idUserReal').value.trim(); const userSub = $('#idUserSub').value.trim(); if (userReal && userSub) { usernames.push({ real: userReal, substitute: userSub }); } const hostnames = []; const hostReal = $('#idHostReal').value.trim(); const hostSub = $('#idHostSub').value.trim(); if (hostReal && hostSub) { hostnames.push({ real: hostReal, substitute: hostSub }); } const phones = []; const phoneReal = $('#idPhoneReal').value.trim(); const phoneSub = $('#idPhoneSub').value.trim(); if (phoneReal && phoneSub) { phones.push({ real: phoneReal, substitute: phoneSub }); } identity = { names, emails, usernames, hostnames, phones, catchAllEmail: $('#idCatchAllEmail').value.trim(), emailDomains: identity.emailDomains || [], enabled: identity.enabled || { emails: true, names: true, usernames: true, phones: true, paths: true }, }; await Storage.saveIdentity(identity); checkFirstRun(); // Flash save button const btn = $('#btnSaveIdentity'); btn.textContent = 'Saved!'; btn.style.background = '#059669'; setTimeout(() => { btn.textContent = 'Save Identity'; btn.style.background = ''; }, 1500); } // --- First-Run Check --- function checkFirstRun() { const hasNames = (identity.names || []).length > 0; const hasEmails = (identity.emails || []).length > 0 || !!identity.catchAllEmail; const hasUsernames = (identity.usernames || []).length > 0; const hasMappings = mappings.length > 0; // Show banner if nothing is configured at all const isConfigured = hasNames || hasEmails || hasUsernames || hasMappings; const banner = $('#firstRunBanner'); banner.style.display = isConfigured ? 'none' : 'flex'; // Also update the status dot — orange if unconfigured const dot = $('#statusDot'); if (!isConfigured && settings.enabled) { dot.classList.add('off-site'); dot.classList.remove('disabled'); } else { dot.classList.remove('off-site'); } } // --- Add Mapping --- async function addMapping() { const real = $('#inputReal').value.trim(); const sub = $('#inputSub').value.trim(); const category = $('#inputCategory').value; const caseSensitive = $('#inputCaseSensitive').checked; if (!real || !sub) return; const mapping = await Storage.addMapping({ real, substitute: sub, category, caseSensitive, }); mappings.push(mapping); renderMappings(); // Clear inputs $('#inputReal').value = ''; $('#inputSub').value = ''; $('#inputCaseSensitive').checked = false; $('#inputReal').focus(); } // --- Render Mappings --- function renderMappings() { const list = $('#mappingList'); if (mappings.length === 0) { list.innerHTML = '