// Vault1984 Content Script // Detect login forms and notify background function detectForms() { const forms = document.querySelectorAll('form'); let loginForms = 0; forms.forEach(form => { const hasPassword = form.querySelector('input[type="password"]'); const hasUsername = form.querySelector('input[type="text"], input[type="email"], input[name*="user"], input[name*="email"], input[name*="login"]'); if (hasPassword || hasUsername) { loginForms++; } }); // Also check for standalone password fields const standalonePasswords = document.querySelectorAll('input[type="password"]:not(form input)'); loginForms += standalonePasswords.length; chrome.runtime.sendMessage({ action: 'formsDetected', count: loginForms }); return loginForms; } // Get all form fields for mapping function getFormFields() { const fields = []; const inputs = document.querySelectorAll('input:not([type="hidden"]):not([type="submit"]):not([type="button"])'); inputs.forEach(input => { const label = findLabel(input); fields.push({ selector: getSelector(input), label: label, type: input.type, name: input.name, placeholder: input.placeholder, autocomplete: input.autocomplete }); }); return fields; } // Find label for an input function findLabel(input) { // Check for associated label if (input.id) { const label = document.querySelector(`label[for="${input.id}"]`); if (label) return label.textContent.trim(); } // Check for wrapping label const parent = input.closest('label'); if (parent) { const text = parent.textContent.replace(input.value, '').trim(); if (text) return text; } // Check aria-label if (input.getAttribute('aria-label')) { return input.getAttribute('aria-label'); } // Use placeholder or name as fallback return input.placeholder || input.name || input.type; } // Generate a unique selector for an element function getSelector(el) { if (el.id) return '#' + el.id; if (el.name) return `[name="${el.name}"]`; // Build a path selector const path = []; while (el && el !== document.body) { let selector = el.tagName.toLowerCase(); if (el.className) { selector += '.' + el.className.trim().split(/\s+/).join('.'); } path.unshift(selector); el = el.parentElement; } return path.join(' > '); } // Fill fields by selector function fillFields(fields) { Object.entries(fields).forEach(([label, selector]) => { try { const el = document.querySelector(selector); if (el) { el.value = label; // label here is actually the value el.dispatchEvent(new Event('input', { bubbles: true })); el.dispatchEvent(new Event('change', { bubbles: true })); } } catch (e) { console.error('Vault1984: Failed to fill field', selector, e); } }); } // Listen for messages from background chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === 'fillFields') { fillFields(request.fields); sendResponse({ success: true }); } if (request.action === 'getFormFields') { const fields = getFormFields(); sendResponse({ success: true, fields }); } }); // Detect forms on page load setTimeout(detectForms, 500); // Re-detect on dynamic content changes const observer = new MutationObserver(() => { detectForms(); }); observer.observe(document.body, { childList: true, subtree: true });