完成扩展

This commit is contained in:
dela
2026-01-10 16:53:02 +08:00
parent 9eba656dbd
commit 97b162939e
31 changed files with 8436 additions and 0 deletions

View File

@@ -0,0 +1,285 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: #1a1a1a;
color: #e0e0e0;
line-height: 1.6;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 24px;
}
/* Header */
header {
text-align: center;
margin-bottom: 32px;
padding-bottom: 16px;
border-bottom: 2px solid #333;
}
header h1 {
font-size: 28px;
font-weight: 600;
color: #fff;
margin-bottom: 8px;
}
header p {
font-size: 14px;
color: #888;
}
/* Tabs */
.tabs {
display: flex;
gap: 8px;
margin-bottom: 24px;
border-bottom: 1px solid #333;
}
.tab-btn {
padding: 12px 24px;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
color: #888;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
.tab-btn:hover {
color: #fff;
}
.tab-btn.active {
color: #4CAF50;
border-bottom-color: #4CAF50;
}
/* Tab Content */
.tab-content {
display: none;
animation: fadeIn 0.3s;
}
.tab-content.active {
display: block;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.tab-content h2 {
font-size: 22px;
margin-bottom: 8px;
color: #fff;
}
.section-desc {
color: #888;
margin-bottom: 24px;
}
/* Form Elements */
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
font-size: 14px;
font-weight: 500;
margin-bottom: 8px;
color: #ccc;
}
.form-group input[type="text"],
.form-group input[type="number"],
.form-group select {
width: 100%;
padding: 10px 12px;
background: #252525;
border: 1px solid #333;
border-radius: 6px;
color: #fff;
font-size: 14px;
transition: border-color 0.2s;
}
.form-group input:focus,
.form-group select:focus {
outline: none;
border-color: #4CAF50;
}
.form-group input[type="checkbox"] {
margin-right: 8px;
cursor: pointer;
}
/* Module Config */
.module-config {
background: #252525;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
}
.module-config h3 {
font-size: 16px;
color: #4CAF50;
margin-bottom: 16px;
}
/* Buttons */
.btn-primary,
.btn-secondary,
.btn-danger {
padding: 12px 24px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
.btn-primary {
background: #4CAF50;
color: white;
}
.btn-primary:hover {
background: #45a049;
}
.btn-secondary {
background: #333;
color: white;
margin-right: 8px;
}
.btn-secondary:hover {
background: #3a3a3a;
}
.btn-danger {
background: #f44336;
color: white;
}
.btn-danger:hover {
background: #da190b;
}
/* Stats Grid */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
.stat-card {
background: #252525;
border-radius: 8px;
padding: 20px;
text-align: center;
}
.stat-number {
font-size: 32px;
font-weight: 700;
color: #4CAF50;
margin-bottom: 8px;
}
.stat-label {
font-size: 13px;
color: #888;
}
/* Data Management */
.data-actions {
margin-bottom: 24px;
}
.data-preview {
background: #252525;
border-radius: 8px;
padding: 20px;
}
.data-preview h3 {
font-size: 16px;
margin-bottom: 12px;
color: #4CAF50;
}
.data-preview pre {
background: #1a1a1a;
border: 1px solid #333;
border-radius: 4px;
padding: 16px;
overflow-x: auto;
font-size: 12px;
color: #ccc;
max-height: 400px;
overflow-y: auto;
}
/* About Section */
.about-content {
max-width: 700px;
}
.about-content h3 {
font-size: 18px;
color: #4CAF50;
margin-top: 24px;
margin-bottom: 12px;
}
.about-content p {
margin-bottom: 12px;
color: #ccc;
}
.about-content ul {
margin-left: 24px;
margin-bottom: 16px;
}
.about-content li {
margin-bottom: 8px;
color: #ccc;
}
.warning-text {
color: #ff9800;
font-weight: 600;
font-size: 16px;
margin-top: 24px;
}
/* Footer */
footer {
text-align: center;
margin-top: 48px;
padding-top: 24px;
border-top: 1px solid #333;
color: #666;
font-size: 12px;
}

View File

@@ -0,0 +1,192 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Payment Automation Suite - Settings</title>
<link rel="stylesheet" href="options.css">
</head>
<body>
<div class="container">
<header>
<h1>🔧 Payment Automation Suite - Settings</h1>
<p>Advanced configuration for authorized testing</p>
</header>
<nav class="tabs">
<button class="tab-btn active" data-tab="api">API Keys</button>
<button class="tab-btn" data-tab="modules">Module Config</button>
<button class="tab-btn" data-tab="data">Data Management</button>
<button class="tab-btn" data-tab="about">About</button>
</nav>
<!-- Tab 1: API Keys -->
<section class="tab-content active" id="tab-api">
<h2>Captcha Solver API Keys</h2>
<p class="section-desc">Configure API keys for automated captcha solving services</p>
<div class="form-group">
<label for="api-capsolver">CapSolver API Key</label>
<input type="text" id="api-capsolver" placeholder="Enter your CapSolver API key">
</div>
<div class="form-group">
<label for="api-2captcha">2Captcha API Key</label>
<input type="text" id="api-2captcha" placeholder="Enter your 2Captcha API key">
</div>
<div class="form-group">
<label for="api-nopecha">NopeCHA API Key</label>
<input type="text" id="api-nopecha" placeholder="Enter your NopeCHA API key">
</div>
<div class="form-group">
<label for="api-nocaptchaai">NoCaptchaAI API Key</label>
<input type="text" id="api-nocaptchaai" placeholder="Enter your NoCaptchaAI API key">
</div>
<button class="btn-primary" id="save-api-keys">Save API Keys</button>
</section>
<!-- Tab 2: Module Configuration -->
<section class="tab-content" id="tab-modules">
<h2>Module Configuration</h2>
<p class="section-desc">Fine-tune settings for each module</p>
<!-- Captcha Solver Config -->
<div class="module-config">
<h3>Captcha Solver</h3>
<div class="form-group">
<label for="cs-debug">
<input type="checkbox" id="cs-debug">
Debug Mode
</label>
</div>
<div class="form-group">
<label for="cs-service">API Service</label>
<select id="cs-service">
<option value="capsolver">CapSolver</option>
<option value="2captcha">2Captcha</option>
<option value="nopecha">NopeCHA</option>
<option value="nocaptchaai">NoCaptchaAI</option>
</select>
</div>
<div class="form-group">
<label for="cs-delay">Solve Delay (ms)</label>
<input type="number" id="cs-delay" min="0" max="5000" step="100">
</div>
</div>
<!-- GOG Payment Config -->
<div class="module-config">
<h3>GOG Payment Handler</h3>
<div class="form-group">
<label for="gog-bins">BIN List (comma-separated)</label>
<input type="text" id="gog-bins" placeholder="424242,411111,378282">
</div>
<div class="form-group">
<label for="gog-rotate">
<input type="checkbox" id="gog-rotate">
Auto-rotate BIN
</label>
</div>
</div>
<!-- AutoFill Config -->
<div class="module-config">
<h3>Auto Fill</h3>
<div class="form-group">
<label for="af-country">Default Country</label>
<select id="af-country">
<option value="US">United States</option>
<option value="GB">United Kingdom</option>
<option value="CN">China</option>
</select>
</div>
<div class="form-group">
<label for="af-delay">Fill Delay (ms)</label>
<input type="number" id="af-delay" min="0" max="2000" step="50">
</div>
</div>
<button class="btn-primary" id="save-module-config">Save Configuration</button>
</section>
<!-- Tab 3: Data Management -->
<section class="tab-content" id="tab-data">
<h2>Data Management</h2>
<p class="section-desc">View and manage captured data</p>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-number" id="total-captchas">0</div>
<div class="stat-label">Captchas Solved</div>
</div>
<div class="stat-card">
<div class="stat-number" id="total-forms">0</div>
<div class="stat-label">Forms Filled</div>
</div>
<div class="stat-card">
<div class="stat-number" id="total-cards">0</div>
<div class="stat-label">Cards Generated</div>
</div>
<div class="stat-card">
<div class="stat-number" id="total-payments">0</div>
<div class="stat-label">Payments Captured</div>
</div>
</div>
<div class="data-actions">
<button class="btn-secondary" id="export-json">Export as JSON</button>
<button class="btn-secondary" id="export-csv">Export as CSV</button>
<button class="btn-danger" id="clear-data">Clear All Data</button>
</div>
<div class="data-preview">
<h3>Captured Data Preview</h3>
<pre id="data-preview-content">No data captured yet</pre>
</div>
</section>
<!-- Tab 4: About -->
<section class="tab-content" id="tab-about">
<h2>About</h2>
<div class="about-content">
<h3>⚠️ Legal Disclaimer</h3>
<p>This extension is designed for <strong>authorized security testing and educational purposes only</strong>.</p>
<p>Unauthorized use of this tool against payment systems, captcha services, or any other protected systems without explicit written permission is:</p>
<ul>
<li>A violation of the Computer Fraud and Abuse Act (CFAA) in the United States</li>
<li>A violation of similar cybercrime laws in other jurisdictions</li>
<li>A breach of Terms of Service for payment gateways and captcha providers</li>
<li>A violation of PCI DSS compliance requirements</li>
</ul>
<p><strong>You must have explicit authorization</strong> from the system owner before using this extension.</p>
<h3>📋 Version Information</h3>
<p>Version: 1.0.0</p>
<p>Build: Manifest V3 (Chrome/Edge)</p>
<h3>🛡️ Responsible Use</h3>
<p>This tool should only be used in:</p>
<ul>
<li>Authorized penetration testing engagements</li>
<li>Bug bounty programs with explicit permission</li>
<li>Educational security research</li>
<li>Development and testing environments you own</li>
</ul>
<p class="warning-text">The developers of this extension assume no liability for misuse.</p>
</div>
</section>
<footer>
<p>© 2025 Payment Automation Suite - For Authorized Testing Only</p>
</footer>
</div>
<script src="options.js"></script>
</body>
</html>

View File

@@ -0,0 +1,298 @@
/**
* Options Page Logic
*/
// Tab switching
const tabBtns = document.querySelectorAll('.tab-btn');
const tabContents = document.querySelectorAll('.tab-content');
tabBtns.forEach(btn => {
btn.addEventListener('click', () => {
const targetTab = btn.dataset.tab;
// Remove active class from all
tabBtns.forEach(b => b.classList.remove('active'));
tabContents.forEach(c => c.classList.remove('active'));
// Add active class to clicked
btn.classList.add('active');
document.getElementById(`tab-${targetTab}`).classList.add('active');
});
});
// Initialize on load
document.addEventListener('DOMContentLoaded', async () => {
await loadAllSettings();
await loadStats();
await loadDataPreview();
// Set up event listeners
document.getElementById('save-api-keys').addEventListener('click', saveAPIKeys);
document.getElementById('save-module-config').addEventListener('click', saveModuleConfig);
document.getElementById('export-json').addEventListener('click', exportJSON);
document.getElementById('export-csv').addEventListener('click', exportCSV);
document.getElementById('clear-data').addEventListener('click', clearData);
});
/**
* Load all settings from storage
*/
async function loadAllSettings() {
try {
const config = await chrome.storage.sync.get(['apiKeys', 'modules']);
// Load API keys
if (config.apiKeys) {
document.getElementById('api-capsolver').value = config.apiKeys.capsolver || '';
document.getElementById('api-2captcha').value = config.apiKeys.twocaptcha || '';
document.getElementById('api-nopecha').value = config.apiKeys.nopecha || '';
document.getElementById('api-nocaptchaai').value = config.apiKeys.nocaptchaai || '';
}
// Load module configs
if (config.modules) {
// Captcha Solver
const cs = config.modules.captchaSolver?.config;
if (cs) {
document.getElementById('cs-debug').checked = cs.debug || false;
document.getElementById('cs-service').value = cs.apiService || 'capsolver';
document.getElementById('cs-delay').value = cs.solveDelay || 800;
}
// GOG Payment
const gog = config.modules.gogPayment?.config;
if (gog) {
document.getElementById('gog-bins').value = gog.bins?.join(',') || '';
document.getElementById('gog-rotate').checked = gog.autoRotateBIN || false;
}
// AutoFill
const af = config.modules.autoFill?.config;
if (af) {
document.getElementById('af-country').value = af.defaultCountry || 'US';
document.getElementById('af-delay').value = af.fillDelay || 300;
}
}
} catch (error) {
console.error('[Options] Failed to load settings:', error);
}
}
/**
* Save API Keys
*/
async function saveAPIKeys() {
const apiKeys = {
capsolver: document.getElementById('api-capsolver').value.trim(),
twocaptcha: document.getElementById('api-2captcha').value.trim(),
nopecha: document.getElementById('api-nopecha').value.trim(),
nocaptchaai: document.getElementById('api-nocaptchaai').value.trim()
};
try {
await chrome.storage.sync.set({ apiKeys });
showNotification('API keys saved successfully', 'success');
} catch (error) {
console.error('[Options] Failed to save API keys:', error);
showNotification('Failed to save API keys', 'error');
}
}
/**
* Save Module Configuration
*/
async function saveModuleConfig() {
try {
const config = await chrome.storage.sync.get(['modules']);
// Update Captcha Solver config
config.modules.captchaSolver.config.debug = document.getElementById('cs-debug').checked;
config.modules.captchaSolver.config.apiService = document.getElementById('cs-service').value;
config.modules.captchaSolver.config.solveDelay = parseInt(document.getElementById('cs-delay').value);
// Update GOG Payment config
const bins = document.getElementById('gog-bins').value.split(',').map(b => b.trim()).filter(b => b);
config.modules.gogPayment.config.bins = bins;
config.modules.gogPayment.config.autoRotateBIN = document.getElementById('gog-rotate').checked;
// Update AutoFill config
config.modules.autoFill.config.defaultCountry = document.getElementById('af-country').value;
config.modules.autoFill.config.fillDelay = parseInt(document.getElementById('af-delay').value);
await chrome.storage.sync.set(config);
showNotification('Module configuration saved successfully', 'success');
} catch (error) {
console.error('[Options] Failed to save module config:', error);
showNotification('Failed to save configuration', 'error');
}
}
/**
* Load statistics
*/
async function loadStats() {
try {
const response = await chrome.runtime.sendMessage({ type: 'GET_STATS' });
if (response && response.success) {
const stats = response.stats;
document.getElementById('total-captchas').textContent = stats.captchasSolved || 0;
document.getElementById('total-forms').textContent = stats.formsFilled || 0;
document.getElementById('total-cards').textContent = stats.cardsGenerated || 0;
document.getElementById('total-payments').textContent = stats.paymentsCaptured || 0;
}
} catch (error) {
console.error('[Options] Failed to load stats:', error);
}
}
/**
* Load data preview
*/
async function loadDataPreview() {
try {
const response = await chrome.runtime.sendMessage({ type: 'EXPORT_DATA' });
if (response && response.success) {
const data = response.data;
const preview = document.getElementById('data-preview-content');
if (data && data.length > 0) {
preview.textContent = JSON.stringify(data, null, 2);
} else {
preview.textContent = 'No data captured yet';
}
}
} catch (error) {
console.error('[Options] Failed to load data preview:', error);
}
}
/**
* Export data as JSON
*/
async function exportJSON() {
try {
const response = await chrome.runtime.sendMessage({ type: 'EXPORT_DATA' });
if (response && response.success) {
const data = response.data;
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
downloadBlob(blob, `payment-automation-data-${Date.now()}.json`);
showNotification('Data exported as JSON', 'success');
}
} catch (error) {
console.error('[Options] Failed to export JSON:', error);
showNotification('Export failed', 'error');
}
}
/**
* Export data as CSV
*/
async function exportCSV() {
try {
const response = await chrome.runtime.sendMessage({ type: 'EXPORT_DATA' });
if (response && response.success) {
const data = response.data;
if (!data || data.length === 0) {
showNotification('No data to export', 'error');
return;
}
// Convert to CSV
const headers = Object.keys(data[0]);
const csv = [
headers.join(','),
...data.map(row => headers.map(h => JSON.stringify(row[h] || '')).join(','))
].join('\n');
const blob = new Blob([csv], { type: 'text/csv' });
downloadBlob(blob, `payment-automation-data-${Date.now()}.csv`);
showNotification('Data exported as CSV', 'success');
}
} catch (error) {
console.error('[Options] Failed to export CSV:', error);
showNotification('Export failed', 'error');
}
}
/**
* Clear all captured data
*/
async function clearData() {
if (!confirm('Are you sure you want to clear all captured data? This cannot be undone.')) {
return;
}
try {
await chrome.runtime.sendMessage({ type: 'CLEAR_DATA' });
await loadDataPreview();
await loadStats();
showNotification('All data cleared', 'success');
} catch (error) {
console.error('[Options] Failed to clear data:', error);
showNotification('Failed to clear data', 'error');
}
}
/**
* Download blob as file
*/
function downloadBlob(blob, filename) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
/**
* Show notification
*/
function showNotification(message, type) {
// Create notification element
const notification = document.createElement('div');
notification.textContent = message;
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 16px 24px;
background: ${type === 'success' ? '#4CAF50' : '#f44336'};
color: white;
border-radius: 6px;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
z-index: 10000;
animation: slideIn 0.3s ease-out;
`;
document.body.appendChild(notification);
// Remove after 3 seconds
setTimeout(() => {
notification.style.animation = 'slideOut 0.3s ease-out';
setTimeout(() => {
document.body.removeChild(notification);
}, 300);
}, 3000);
}
// Add CSS animations
const style = document.createElement('style');
style.textContent = `
@keyframes slideIn {
from { transform: translateX(400px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes slideOut {
from { transform: translateX(0); opacity: 1; }
to { transform: translateX(400px); opacity: 0; }
}
`;
document.head.appendChild(style);

View File

@@ -0,0 +1,208 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
width: 350px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: #1a1a1a;
color: #e0e0e0;
}
.container {
padding: 16px;
}
/* Header */
header {
text-align: center;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 1px solid #333;
}
header h1 {
font-size: 18px;
font-weight: 600;
color: #fff;
margin-bottom: 4px;
}
.subtitle {
font-size: 11px;
color: #888;
}
/* Master Control */
.master-control {
background: #252525;
border-radius: 8px;
padding: 12px;
margin-bottom: 16px;
}
.control-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.control-label {
font-weight: 600;
font-size: 14px;
color: #fff;
}
/* Switch Component */
.switch {
position: relative;
display: inline-block;
width: 44px;
height: 24px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #444;
transition: 0.3s;
border-radius: 24px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 3px;
bottom: 3px;
background-color: white;
transition: 0.3s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #4CAF50;
}
input:checked + .slider:before {
transform: translateX(20px);
}
/* Modules Section */
.modules {
margin-bottom: 16px;
}
.modules h2 {
font-size: 13px;
font-weight: 600;
color: #aaa;
margin-bottom: 8px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.module-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 12px;
background: #252525;
border-radius: 6px;
margin-bottom: 6px;
transition: background 0.2s;
}
.module-item:hover {
background: #2a2a2a;
}
.module-info {
display: flex;
align-items: center;
gap: 8px;
}
.module-name {
font-size: 13px;
font-weight: 500;
}
.module-status {
font-size: 16px;
line-height: 1;
}
.module-status.active {
color: #4CAF50;
}
.module-status.inactive {
color: #666;
}
/* Stats Section */
.stats {
background: #252525;
border-radius: 8px;
padding: 12px;
margin-bottom: 16px;
}
.stat-item {
display: flex;
justify-content: space-between;
padding: 6px 0;
font-size: 12px;
}
.stat-label {
color: #aaa;
}
.stat-value {
color: #4CAF50;
font-weight: 600;
}
/* Footer */
footer {
text-align: center;
}
.btn-secondary {
width: 100%;
padding: 10px;
background: #333;
border: none;
border-radius: 6px;
color: #fff;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: background 0.2s;
margin-bottom: 8px;
}
.btn-secondary:hover {
background: #3a3a3a;
}
.warning {
font-size: 10px;
color: #ff9800;
margin-top: 8px;
}

View File

@@ -0,0 +1,135 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Payment Automation Suite</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div class="container">
<!-- Header -->
<header>
<h1>🔧 Payment Automation Suite</h1>
<p class="subtitle">Authorized Testing Tools</p>
</header>
<!-- Master Control -->
<section class="master-control">
<div class="control-row">
<span class="control-label">Master Control</span>
<label class="switch">
<input type="checkbox" id="masterSwitch">
<span class="slider"></span>
</label>
</div>
</section>
<!-- Module List -->
<section class="modules">
<h2>Modules</h2>
<div class="module-item">
<div class="module-info">
<span class="module-name">Captcha Solver</span>
<span class="module-status" id="status-captchaSolver"></span>
</div>
<label class="switch">
<input type="checkbox" class="module-toggle" data-module="captchaSolver">
<span class="slider"></span>
</label>
</div>
<div class="module-item">
<div class="module-info">
<span class="module-name">hCaptcha Bypass</span>
<span class="module-status" id="status-hcaptchaBypass"></span>
</div>
<label class="switch">
<input type="checkbox" class="module-toggle" data-module="hcaptchaBypass">
<span class="slider"></span>
</label>
</div>
<div class="module-item">
<div class="module-info">
<span class="module-name">3DS Handler</span>
<span class="module-status" id="status-threeDSecure"></span>
</div>
<label class="switch">
<input type="checkbox" class="module-toggle" data-module="threeDSecure">
<span class="slider"></span>
</label>
</div>
<div class="module-item">
<div class="module-info">
<span class="module-name">GOG Payment</span>
<span class="module-status" id="status-gogPayment"></span>
</div>
<label class="switch">
<input type="checkbox" class="module-toggle" data-module="gogPayment">
<span class="slider"></span>
</label>
</div>
<div class="module-item">
<div class="module-info">
<span class="module-name">Auto Fill</span>
<span class="module-status" id="status-autoFill"></span>
</div>
<label class="switch">
<input type="checkbox" class="module-toggle" data-module="autoFill">
<span class="slider"></span>
</label>
</div>
<div class="module-item">
<div class="module-info">
<span class="module-name">Fetch Spy</span>
<span class="module-status" id="status-fetchSpy"></span>
</div>
<label class="switch">
<input type="checkbox" class="module-toggle" data-module="fetchSpy">
<span class="slider"></span>
</label>
</div>
<div class="module-item">
<div class="module-info">
<span class="module-name">Payment Capture</span>
<span class="module-status" id="status-paymentHandler"></span>
</div>
<label class="switch">
<input type="checkbox" class="module-toggle" data-module="paymentHandler">
<span class="slider"></span>
</label>
</div>
</section>
<!-- Stats -->
<section class="stats">
<div class="stat-item">
<span class="stat-label">Captchas Solved:</span>
<span class="stat-value" id="stat-captchas">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Forms Filled:</span>
<span class="stat-value" id="stat-forms">0</span>
</div>
<div class="stat-item">
<span class="stat-label">Cards Generated:</span>
<span class="stat-value" id="stat-cards">0</span>
</div>
</section>
<!-- Footer -->
<footer>
<button id="openOptions" class="btn-secondary">⚙️ Advanced Settings</button>
<p class="warning">⚠️ For authorized testing only</p>
</footer>
</div>
<script src="popup.js"></script>
</body>
</html>

188
extension/ui/popup/popup.js Normal file
View File

@@ -0,0 +1,188 @@
/**
* Popup UI Logic
*/
// Debug mode flag (set to true to enable verbose logging)
const DEBUG = true;
function debugLog(...args) {
if (DEBUG) {
console.log('[Popup DEBUG]', new Date().toISOString(), ...args);
}
}
// DOM elements
const masterSwitch = document.getElementById('masterSwitch');
const moduleToggles = document.querySelectorAll('.module-toggle');
const openOptionsBtn = document.getElementById('openOptions');
// Stats elements
const statCaptchas = document.getElementById('stat-captchas');
const statForms = document.getElementById('stat-forms');
const statCards = document.getElementById('stat-cards');
// Initialize popup
document.addEventListener('DOMContentLoaded', async () => {
debugLog('=== Popup DOMContentLoaded ===');
debugLog('DOM elements found:', {
masterSwitch: !!masterSwitch,
moduleToggles: moduleToggles.length,
openOptionsBtn: !!openOptionsBtn
});
await loadConfig();
await loadStats();
// Set up event listeners
masterSwitch.addEventListener('change', handleMasterToggle);
moduleToggles.forEach(toggle => {
toggle.addEventListener('change', handleModuleToggle);
});
openOptionsBtn.addEventListener('click', () => {
debugLog('Options button clicked');
chrome.runtime.openOptionsPage();
});
// Refresh stats every 2 seconds
setInterval(loadStats, 2000);
debugLog('=== Popup initialization complete ===');
});
/**
* Load configuration from storage
*/
async function loadConfig() {
debugLog('loadConfig: Starting to load configuration');
try {
const config = await chrome.storage.sync.get(['modules', 'globalSettings']);
debugLog('loadConfig: Received config from storage:', config);
// Set master switch
if (config.globalSettings) {
masterSwitch.checked = config.globalSettings.masterEnabled || false;
debugLog('loadConfig: Master switch set to', masterSwitch.checked);
}
// Set module toggles
if (config.modules) {
moduleToggles.forEach(toggle => {
const moduleName = toggle.dataset.module;
const moduleConfig = config.modules[moduleName];
if (moduleConfig) {
toggle.checked = moduleConfig.enabled || false;
updateModuleStatus(moduleName, moduleConfig.enabled);
debugLog(`loadConfig: Module ${moduleName} set to`, toggle.checked);
}
});
}
debugLog('loadConfig: Configuration loaded successfully');
} catch (error) {
console.error('[Popup] Failed to load config:', error);
debugLog('loadConfig: ERROR -', error);
}
}
/**
* Load statistics from storage
*/
async function loadStats() {
try {
const response = await chrome.runtime.sendMessage({ type: 'GET_STATS' });
if (response && response.success) {
const stats = response.stats;
statCaptchas.textContent = stats.captchasSolved || 0;
statForms.textContent = stats.formsFilled || 0;
statCards.textContent = stats.cardsGenerated || 0;
}
} catch (error) {
console.error('[Popup] Failed to load stats:', error);
}
}
/**
* Handle master switch toggle
*/
async function handleMasterToggle(event) {
const enabled = event.target.checked;
debugLog('handleMasterToggle: User toggled master switch to', enabled);
try {
debugLog('handleMasterToggle: Sending TOGGLE_MASTER message');
const response = await chrome.runtime.sendMessage({
type: 'TOGGLE_MASTER',
enabled
});
debugLog('handleMasterToggle: Received response:', response);
if (response && response.success) {
// Update all module toggles
moduleToggles.forEach(toggle => {
toggle.checked = enabled;
const moduleName = toggle.dataset.module;
updateModuleStatus(moduleName, enabled);
});
console.log('[Popup] Master switch:', enabled ? 'ON' : 'OFF');
debugLog('handleMasterToggle: All modules updated in UI');
} else {
debugLog('handleMasterToggle: Response indicated failure:', response);
event.target.checked = !enabled; // Revert on error
}
} catch (error) {
console.error('[Popup] Failed to toggle master:', error);
debugLog('handleMasterToggle: ERROR -', error);
event.target.checked = !enabled; // Revert on error
}
}
/**
* Handle individual module toggle
*/
async function handleModuleToggle(event) {
const moduleName = event.target.dataset.module;
const enabled = event.target.checked;
debugLog(`handleModuleToggle: User toggled ${moduleName} to`, enabled);
try {
debugLog('handleModuleToggle: Sending TOGGLE_MODULE message');
const response = await chrome.runtime.sendMessage({
type: 'TOGGLE_MODULE',
moduleName,
enabled
});
debugLog('handleModuleToggle: Received response:', response);
if (response && response.success) {
updateModuleStatus(moduleName, enabled);
console.log(`[Popup] Module ${moduleName}:`, enabled ? 'ON' : 'OFF');
debugLog('handleModuleToggle: Module status updated in UI');
} else {
debugLog('handleModuleToggle: Response indicated failure:', response);
event.target.checked = !enabled; // Revert on error
}
} catch (error) {
console.error(`[Popup] Failed to toggle ${moduleName}:`, error);
debugLog('handleModuleToggle: ERROR -', error);
event.target.checked = !enabled; // Revert on error
}
}
/**
* Update module status indicator
*/
function updateModuleStatus(moduleName, enabled) {
debugLog(`updateModuleStatus: ${moduleName} = ${enabled}`);
const statusElement = document.getElementById(`status-${moduleName}`);
if (statusElement) {
statusElement.textContent = enabled ? '●' : '○';
statusElement.className = enabled ? 'module-status active' : 'module-status inactive';
}
}