/** * Content Script Loader * Dynamically injects enabled modules into the page context */ // Module instances registry const moduleInstances = new Map(); // Module metadata const MODULE_METADATA = { captchaSolver: { filename: 'CaptchaSolverModule.js', className: 'CaptchaSolverModule', instanceKey: '__captchaSolverInstance' }, hcaptchaBypass: { filename: 'HCaptchaBypassModule.js', className: 'HCaptchaBypassModule', instanceKey: '__hcaptchaBypassInstance' }, threeDSecure: { filename: 'ThreeDSecureHandlerModule.js', className: 'ThreeDSecureHandlerModule', instanceKey: '__threeDSecureInstance' }, gogPayment: { filename: 'GogPaymentHandlerModule.js', className: 'GogPaymentHandlerModule', instanceKey: '__gogPaymentInstance' }, autoFill: { filename: 'AutoFillHandlerModule.js', className: 'AutoFillHandlerModule', instanceKey: '__autoFillInstance' }, fetchSpy: { filename: 'FetchInterceptorModule.js', className: 'FetchInterceptorModule', instanceKey: '__fetchSpyInstance' }, paymentHandler: { filename: 'PaymentHandlerModule.js', className: 'PaymentHandlerModule', instanceKey: '__paymentHandlerInstance' } }; // Initialize content script console.log('[ContentScript] Initializing...'); // Load enabled modules loadEnabledModules(); // Listen for config changes from background chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.type === 'CONFIG_CHANGED') { console.log('[ContentScript] Config changed, reloading modules...'); handleConfigChange(message.changes); } sendResponse({ success: true }); }); // Listen for module events from page context window.addEventListener('message', (event) => { // Only accept messages from same window if (event.source !== window) return; const message = event.data; // Forward module events to background if (message && typeof message === 'object' && message.type && message.type.startsWith('CAPTCHA_SOLVER_') || message.type === 'CARD_GENERATED' || message.type === 'FORM_FILLED' || message.type === 'PAYMENT_CAPTURED') { chrome.runtime.sendMessage({ type: 'MODULE_EVENT', payload: message }).catch(err => { console.error('[ContentScript] Failed to send event to background:', err); }); } }); /** * Load all enabled modules from storage */ async function loadEnabledModules() { try { const config = await chrome.storage.sync.get(['modules', 'globalSettings', 'apiKeys']); console.log('[ContentScript] Loaded config:', config); // Check master switch if (!config.globalSettings?.masterEnabled) { console.log('[ContentScript] Master switch disabled, skipping module load'); return; } // Load each enabled module for (const [moduleName, moduleConfig] of Object.entries(config.modules || {})) { if (moduleConfig.enabled) { await loadModule(moduleName, moduleConfig.config, config.apiKeys); } } console.log('[ContentScript] All enabled modules loaded'); } catch (error) { console.error('[ContentScript] Failed to load modules:', error); } } /** * Load a single module */ async function loadModule(moduleName, config, apiKeys) { if (moduleInstances.has(moduleName)) { console.log(`[ContentScript] Module ${moduleName} already loaded`); return; } const metadata = MODULE_METADATA[moduleName]; if (!metadata) { console.error(`[ContentScript] Unknown module: ${moduleName}`); return; } console.log(`[ContentScript] Loading module: ${moduleName}`); try { // Inject module script into page context const script = document.createElement('script'); script.src = chrome.runtime.getURL(`content/modules/${metadata.filename}`); script.onload = () => { console.log(`[ContentScript] Module script loaded: ${moduleName}`); // Initialize module in page context via postMessage window.postMessage({ type: 'INIT_MODULE', moduleName, className: metadata.className, instanceKey: metadata.instanceKey, config: { ...config, apiKey: apiKeys?.[config.apiService] || config.apiKey } }, '*'); }; script.onerror = (error) => { console.error(`[ContentScript] Failed to load module script: ${moduleName}`, error); }; // Inject before any page scripts (document.head || document.documentElement).appendChild(script); moduleInstances.set(moduleName, { metadata, script }); } catch (error) { console.error(`[ContentScript] Error loading module ${moduleName}:`, error); } } /** * Unload a module */ function unloadModule(moduleName) { const instance = moduleInstances.get(moduleName); if (!instance) { console.log(`[ContentScript] Module ${moduleName} not loaded`); return; } console.log(`[ContentScript] Unloading module: ${moduleName}`); // Send destroy message to page context window.postMessage({ type: 'DESTROY_MODULE', moduleName, instanceKey: instance.metadata.instanceKey }, '*'); // Remove script element if (instance.script && instance.script.parentNode) { instance.script.parentNode.removeChild(instance.script); } moduleInstances.delete(moduleName); } /** * Handle configuration changes */ async function handleConfigChange(changes) { // Reload config from storage const config = await chrome.storage.sync.get(['modules', 'globalSettings', 'apiKeys']); // Handle master switch if (changes.globalSettings) { if (!config.globalSettings.masterEnabled) { // Master disabled - unload all modules console.log('[ContentScript] Master switch disabled, unloading all modules'); for (const moduleName of moduleInstances.keys()) { unloadModule(moduleName); } return; } } // Handle individual module changes if (changes.modules) { for (const [moduleName, moduleConfig] of Object.entries(config.modules || {})) { const wasEnabled = moduleInstances.has(moduleName); const shouldBeEnabled = moduleConfig.enabled && config.globalSettings?.masterEnabled; if (shouldBeEnabled && !wasEnabled) { // Load module await loadModule(moduleName, moduleConfig.config, config.apiKeys); } else if (!shouldBeEnabled && wasEnabled) { // Unload module unloadModule(moduleName); } else if (shouldBeEnabled && wasEnabled) { // Module config changed - reload unloadModule(moduleName); await loadModule(moduleName, moduleConfig.config, config.apiKeys); } } } } console.log('[ContentScript] Initialized');