Files
2026-10-09 15:53:24 +07:00

239 lines
7.6 KiB
JavaScript

// Global configuration reference for backward compatibility
// configManager is available via window.configManager from config-manager.js
let config = window.configManager.getConfig();
// Initialization
async function init() {
await configManager.load();
config = configManager.getConfig(); // Update global reference
setupProxyListener();
// Subscribe to configuration changes
configManager.addListener((event, data) => {
config = configManager.getConfig(); // Update global reference
});
}
// Setup proxy listener
// SECURITY NOTE: The extension only routes traffic through user-configured proxies.
// No data is collected or transmitted externally. All proxy settings are user-controlled.
function setupProxyListener() {
// Listen for all URLs to apply domain-specific proxy routing
// This permission is required but only routes traffic through user-specified proxies
browser.proxy.onRequest.addListener(
handleProxyRequest,
{ urls: ["<all_urls>"] }
);
// Listener for automatic proxy authentication
// SECURITY NOTE: Credentials are only used for proxy authentication and stored locally
browser.webRequest.onAuthRequired.addListener(
handleAuthRequired,
{ urls: ["<all_urls>"] },
["blocking"]
);
// Track tabs to determine origin domain for proxy configuration
// SECURITY NOTE: Only tracks domain names, no URL content or personal data
browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === 'loading' && tab.url) {
updateTabOrigin(tabId, tab.url);
}
});
browser.tabs.onRemoved.addListener((tabId) => {
delete config.activeTabs[tabId];
});
}
// Extract domain from URL
function getDomainFromUrl(url) {
try {
const urlObj = new URL(url);
return urlObj.hostname.replace(/^www\./, '');
} catch (e) {
return null;
}
}
// Determine origin for tab
function updateTabOrigin(tabId, url) {
const domain = getDomainFromUrl(url);
if (domain) {
config.activeTabs[tabId] = domain;
}
}
// Get proxy settings for domain
function getProxyConfigForDomain(domain) {
return config.domains[domain];
}
// Proxy request handler
function handleProxyRequest(requestInfo) {
const { tabId, url, originUrl, type } = requestInfo;
// Determine request domain
let domain;
if (originUrl) {
// For sub-requests use origin
domain = getDomainFromUrl(originUrl);
} else if (tabId in config.activeTabs) {
// For main requests use stored tab origin
domain = config.activeTabs[tabId];
} else {
// Fallback option
domain = getDomainFromUrl(url);
}
if (!domain) {
return { type: 'direct' };
}
// Check domain configuration
const proxyConfig = getProxyConfigForDomain(domain);
if (!proxyConfig || !proxyConfig.enabled) {
return { type: 'direct' };
}
// Form proxy object
const proxyObj = {
type: proxyConfig.type,
host: proxyConfig.host,
port: parseInt(proxyConfig.port, 10)
};
// Add authentication if present
if (proxyConfig.username) {
proxyObj.username = proxyConfig.username;
}
if (proxyConfig.password) {
proxyObj.password = proxyConfig.password;
}
return proxyObj;
}
// Authentication request handler
function handleAuthRequired(details) {
const { url, originUrl, tabId, isProxy, realm } = details;
// Process only proxy authentication
if (!isProxy) {
return {};
}
// Determine request domain
let domain;
if (originUrl) {
domain = getDomainFromUrl(originUrl);
} else if (tabId in config.activeTabs) {
domain = config.activeTabs[tabId];
} else {
domain = getDomainFromUrl(url);
}
if (!domain) {
return {};
}
// Get proxy configuration for domain
const proxyConfig = getProxyConfigForDomain(domain);
if (!proxyConfig || !proxyConfig.enabled || !proxyConfig.username || !proxyConfig.password) {
return {};
}
// Return credentials for authentication
return {
authCredentials: {
username: proxyConfig.username,
password: proxyConfig.password
}
};
}
// Message handler from other extension parts
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'getConfig') {
sendResponse({ config: configManager.getConfig() });
} else if (message.action === 'updateDomain') {
configManager.updateDomain(message.domain, message.domainConfig)
.then(() => sendResponse({ success: true }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true; // Async response
} else if (message.action === 'removeDomain') {
configManager.removeDomain(message.domain)
.then(() => sendResponse({ success: true }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true; // Async response
} else if (message.action === 'toggleProxy') {
// Quick enable/disable proxy for domain
const domain = message.domain;
const enabled = message.enabled;
const domainConfig = configManager.getDomainConfig(domain);
if (domainConfig) {
// If domain is already configured, just change enabled
domainConfig.enabled = enabled;
configManager.updateDomain(domain, domainConfig)
.then(() => sendResponse({ success: true }))
.catch(error => sendResponse({ success: false, error: error.message }));
} else {
// If domain is not configured, send error
sendResponse({ success: false, error: 'Domain not configured' });
}
return true; // Async response
} else if (message.action === 'reloadConfig') {
configManager.reload()
.then(() => sendResponse({ success: true }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true; // Async response
} else if (message.action === 'getProfiles') {
sendResponse({ profiles: configManager.getProfiles() });
} else if (message.action === 'updateProfile') {
configManager.updateProfile(message.profileName, message.profileConfig)
.then(() => sendResponse({ success: true }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true; // Async response
} else if (message.action === 'removeProfile') {
configManager.removeProfile(message.profileName)
.then(() => sendResponse({ success: true }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true; // Async response
} else if (message.action === 'getProfile') {
sendResponse({ profile: configManager.getProfileConfig(message.profileName) });
} else if (message.action === 'updateSettings') {
configManager.updateSettings(message.settings || {})
.then(() => sendResponse({ success: true, settings: configManager.getConfig().settings }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true;
} else if (message.action === 'clearAllDomains') {
configManager.config.domains = {};
configManager.save()
.then(() => sendResponse({ success: true }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true;
} else if (message.action === 'clearAllProfiles') {
configManager.config.profiles = {};
configManager.save()
.then(() => sendResponse({ success: true }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true;
} else if (message.action === 'clearEverything') {
configManager.config.domains = {};
configManager.config.profiles = {};
configManager.save()
.then(() => sendResponse({ success: true }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true;
}
});
// Initialization on load
init();