230 lines
6.6 KiB
JavaScript
230 lines
6.6 KiB
JavaScript
/**
|
|
* 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');
|