完成扩展
This commit is contained in:
229
extension/content/content.js
Normal file
229
extension/content/content.js
Normal file
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* 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');
|
||||
Reference in New Issue
Block a user