diff --git a/info.js b/info.js index 708592c..d833117 100644 --- a/info.js +++ b/info.js @@ -1,393 +1,333 @@ -var titlepref = chrome.i18n.getMessage("titlePreface"); +/** + * @fileoverview I2P Browser Information Manager + * Handles browser settings, privacy features, and navigation for I2P extension + */ -function checkPeerConnection() { - let getting = browser.privacy.network.peerConnectionEnabled.get({}); - getting.then((got) => { - let webrtc = got.value; - console.log("(info) checking webrtc", webrtc); - if (document.getElementById("enable-web-rtc") !== null) - document.getElementById("enable-web-rtc").checked = webrtc; - }); -} - -checkPeerConnection(); - -function checkSnowflake() { - try { - function snowflake(snowflake) { - console.log( - "(info) snowflake plugin found, leaving WebRTC alone", - snowflake - ); - AssurePeerConnection(); - } - var snowflakeInfo = browser.management.get( - "{b11bea1f-a888-4332-8d8a-cec2be7d24b9}" - ); - snowflakeInfo.then(snowflake); - } catch (err) { - console.log("(info) snowflake not found", err); - } -} - -checkSnowflake(); - -function checkHistory() { - let getting = browser.storage.local.get("disable_history"); - getting.then((got) => { - let disable_history = got.disable_history; - if (disable_history == undefined) { - disable_history = false; - } - console.log("(info) checking history", disable_history); - if (document.getElementById("disable-history") !== null) - document.getElementById("disable-history").checked = disable_history; - }); -} - -checkHistory(); - -function checkReferer() { - let getting = browser.storage.local.get("disable_referer"); - getting.then((got) => { - let disable_referer = got.disable_referer; - if (disable_referer == undefined) { - disable_referer = false; - } - console.log("(info) checking referer", disable_referer); - if (document.getElementById("disable-referer") !== null) - document.getElementById("disable-referer").checked = disable_referer; - }); -} - -checkReferer(); - -document.addEventListener("click", clickHandler); - -function clickHandler(clickEvent) { - const targetId = clickEvent.target.id; - - if ( - targetId === "window-create-help-panel" || - targetId === "window-create-news-panel" - ) { - const createData = { type: "panel", incognito: true }; - browser.tabs.create(createData).then(() => { - console.log(`The ${targetId.split("-")[2]} panel has been created`); - }); - } else if (targetId === "visit-irc") { - browser.sidebarAction.setPanel({ panel: "http://127.0.0.1:7669" }); - browser.sidebarAction.open(); - } else if (targetId === "generate-fresh-tunnel") { - function refreshIdentity() { - console.log("(info) Generating new identity"); - const Http = new XMLHttpRequest(); - const url = `http://${controlHost}:${controlPort}`; - Http.open("GET", url); - Http.send(); - Http.onreadystatechange = () => { - console.log(Http.responseText); - }; - } - refreshIdentity(); - } else if (targetId.startsWith("label-router")) { - const listId = `label-${targetId.split("-")[2]}-list`; - const list = document.getElementById(listId); - - if (list.style.display !== "none") { - console.log(`hiding ${listId}`); - list.style.display = "none"; - } else { - console.log(`showing ${listId}`); - list.style.display = "block"; - } - } else if (targetId === "search-submit") { - console.log("(info) attempting to create search tab"); - goSearch(); - } else if (targetId === "url-submit") { - console.log("(info) attempting to create search tab"); - goURL(); - } else if (targetId === "browser-action") { - console.log("(info) showing a browser action"); - showBrowsing(); - } else if (targetId === "torrent-action" || targetId === "torrentui-opener") { - console.log("(info) showing a torrent action"); - showTorrentsMenu(); - } else if (targetId.startsWith("window-visit")) { - const page = targetId.split("-")[2]; - console.log(`attempting to create ${page} tab`); - switch (page) { - case "homepage": - case "help": - goHome(); - break; - case "index": - goIndex(); - break; - case "torrent": - goTorrent(); - break; - case "console": - goConsole(); - break; - case "i2ptunnel": - goTunnel(); - break; - case "i2p": - goHomepage(); - break; - case "susimail": - goMail(); - break; - case "snark": - goSnark(); - break; - } - } else if (targetId === "clear-browser-data") { - forgetBrowsingData(); - } else if (targetId === "enable-web-rtc") { - const isWebRTCEnabled = clickEvent.target.checked; - browser.runtime.sendMessage({ - rtc: isWebRTCEnabled ? "enableWebRTC" : "disableWebRTC", - }); - checkPeerConnection(); - return; - } else if (targetId === "disable-history") { - const isHistoryEnabled = !clickEvent.target.checked; - browser.runtime.sendMessage({ - history: isHistoryEnabled ? "enableHistory" : "disableHistory", - }); - return; - } else if (targetId === "disable-referer") { - const isRefererEnabled = !clickEvent.target.checked; - browser.runtime.sendMessage({ - referers: isRefererEnabled ? "enableReferer" : "disableReferer", - }); - return; - } - - clickEvent.preventDefault(); -} - -window.onload = function (e) { - if (document.getElementById("label-peers-list") != null) { - document.getElementById("label-peers-list").style.display = "none"; - } - if (document.getElementById("label-bandwidth-list") != null) { - document.getElementById("label-bandwidth-list").style.display = "none"; - } +// Constants +const CONFIG = { + TITLE_PREFACE: chrome.i18n.getMessage("titlePreface"), + ROUTER: { + DEFAULT_HOST: "127.0.0.1", + DEFAULT_PORT: "7657", + }, + SNOWFLAKE_ID: "{b11bea1f-a888-4332-8d8a-cec2be7d24b9}", + UPDATE_INTERVAL: 0.2 * 60 * 1000, + IRC_URL: "http://127.0.0.1:7669", }; -function proxyReadiness() { - console.log(this.responseText); -} +const UI_ELEMENTS = { + PANELS: { + BROWSER: "browserpanel", + TORRENT: "torrentpanel", + }, + LISTS: { + PEERS: "label-peers-list", + BANDWIDTH: "label-bandwidth-list", + }, +}; -var gettingInfo = browser.runtime.getPlatformInfo(); -gettingInfo.then((got) => { - if (got.os != "android") { - browser.history.onVisited.addListener(onVisited); - } -}); - -function showBrowsing() { - var x = document.getElementById("browserpanel"); - x.style.display = "block"; - var y = document.getElementById("torrentpanel"); - y.style.display = "none"; -} - -function showTorrentsMenu() { - var x = document.getElementById("browserpanel"); - x.style.display = "none"; - var y = document.getElementById("torrentpanel"); - y.style.display = "block"; -} - -function goHome() { - function onTabError() { - console.log("(info) Help tab not created"); - } - let createData = { - url: "home.html", - }; - console.log("(info) visiting homepage"); - let creating = browser.tabs.create(createData); - creating.then(onTabCreated, onTabError); -} - -function goIndex() { - function onTabError() { - console.log("(info) Help tab not created"); - } - let createData = { - url: "index.html", - }; - console.log("(info) visiting help"); - let creating = browser.tabs.create(createData); - creating.then(onTabCreated, onTabError); -} - -function goTorrent() { - function onTabError() { - console.log("(info) Torrent Help tab not created"); - } - let createData = { - url: "torrent/index.html", - }; - console.log("(info) visiting torrent help"); - let creating = browser.tabs.create(createData); - creating.then(onTabCreated, onTabError); -} - -function goHomepage() { - function onTabError() { - console.log("(info) i2p-projekt tab not created"); - } - let createData = { - url: "http://i2p-projekt.i2p", - }; - console.log("(info) visiting i2p-projekt"); - let creating = browser.tabs.create(createData); - creating.then(onTabCreated, onTabError); -} - -function goHelp() { - function onTabError() { - console.log("(info) Torrent Help tab not created"); - } - let createData = { - url: "i2pcontrol/index.html", - }; - console.log("(info) visiting torrent help"); - let creating = browser.tabs.create(createData); - creating.then(onTabCreated, onTabError); -} - -function onTabCreated() { - console.log("(info) Tab Created"); -} - -function goSearch() { - function onTabError() { - console.log("(info) Search tab created"); - } - let createData = { - url: - "http://cuss2sgthm5wfipnnztrjdvtaczb22hnmr2ohnaqqqz3jf6ubf3a.b32.i2p/yacysearch.html?" + - "query=" + - document.getElementById("search-query").value, - }; - console.log("(info) visiting legwork"); - let creating = browser.tabs.create(createData); - creating.then(onTabCreated, onTabError); -} - -function goURL() { - function onTabError() { - console.log("(info) Search tab created"); - } - - function createNewURLTab(context) { - console.log("(info) visiting URL"); - let createData = { - url: document.getElementById("url-query").value, - cookieStoreId: context[0].cookieStoreId, - }; - let creating = browser.tabs.create(createData); - creating.then(onTabCreated, onTabError); - } - let context = browser.contextualIdentities.query({ - name: titlepref, - }); - context.then(createNewURLTab, onTabError); -} - -function routerAddr() { - try { - return control_host() + ":" + control_port(); - } catch { - return "127.0.0.1:7657"; - } -} - -function goConsole() { - function onTabError() { - console.log("(info) Console tab not created"); - } - let createData = { - url: "http://" + routerAddr() + "/home", - }; - console.log("(info) visiting router console"); - let creating = browser.tabs.create(createData); - creating.then(onTabCreated, onTabError); -} - -function goTunnel() { - function onTabError() { - console.log("(info) I2PTunnel tab created"); - } - let createData = { - url: "http://" + routerAddr() + "/i2ptunnel", - }; - console.log("(info) visiting i2ptunnel"); - let creating = browser.tabs.create(createData); - creating.then(onTabCreated, onTabError); -} - -function goMail() { - function onTabError() { - console.log("(info) Mail tab created"); - } - let createData = { - url: "http://" + routerAddr() + "/susimail", - }; - console.log("(info) visiting mail"); - let creating = browser.tabs.create(createData); - creating(onTabCreated, onTabError); -} - -function goSnark() { - function onTabError() { - console.log("(info) Snark tab created"); - } - let createData = { - url: "http://" + routerAddr() + "/i2psnark", - }; - console.log("(info) visiting snark"); - let creating = browser.tabs.create(createData); - creating.then(onTabCreated, onTabError); -} - -function onVisited(historyItem) { - function onCleaned(results) { - if (results.length) { - console.log("(info) was not removed"); - } else { - console.log("(info) was removed"); +/** + * Privacy Manager for handling browser privacy settings + */ +class PrivacyManager { + /** + * Check WebRTC peer connection status + */ + static async checkPeerConnection() { + try { + const { value: webrtc } = + await browser.privacy.network.peerConnectionEnabled.get({}); + const webrtcToggle = document.getElementById("enable-web-rtc"); + if (webrtcToggle) { + webrtcToggle.checked = webrtc; + } + console.info("(info) WebRTC status:", webrtc); + } catch (error) { + console.error("WebRTC check failed:", error); } } - function onRemoved() { - var searching = browser.history.search({ - text: historyItem.url, - startTime: 0, + /** + * Check Snowflake plugin status + */ + static async checkSnowflake() { + try { + const snowflake = await browser.management.get(CONFIG.SNOWFLAKE_ID); + console.info("(info) Snowflake plugin found:", snowflake); + await this.assurePeerConnection(); + } catch (error) { + console.info("(info) Snowflake not found:", error); + } + } + + /** + * Check history settings + */ + static async checkHistory() { + try { + const { disable_history = false } = await browser.storage.local.get( + "disable_history" + ); + const historyToggle = document.getElementById("disable-history"); + if (historyToggle) { + historyToggle.checked = disable_history; + } + console.info("(info) History disabled:", disable_history); + } catch (error) { + console.error("History check failed:", error); + } + } + + /** + * Check referer settings + */ + static async checkReferer() { + try { + const { disable_referer = false } = await browser.storage.local.get( + "disable_referer" + ); + const refererToggle = document.getElementById("disable-referer"); + if (refererToggle) { + refererToggle.checked = disable_referer; + } + console.info("(info) Referer disabled:", disable_referer); + } catch (error) { + console.error("Referer check failed:", error); + } + } +} + +/** + * Tab Manager for handling browser navigation + */ +class TabManager { + /** + * Create a new browser tab + * @param {Object} options Tab creation options + * @return {Promise} + */ + static async createTab(options) { + try { + const tab = await browser.tabs.create(options); + console.info("(info) Tab created:", options.url); + return tab; + } catch (error) { + console.error("Tab creation failed:", error); + throw error; + } + } + + /** + * Create a tab in I2P container + * @param {string} url Destination URL + */ + static async createContainerTab(url) { + try { + const contexts = await browser.contextualIdentities.query({ + name: CONFIG.TITLE_PREFACE, + }); + + if (!contexts.length) { + throw new Error("No I2P container found"); + } + + return this.createTab({ + url, + cookieStoreId: contexts[0].cookieStoreId, + }); + } catch (error) { + console.error("Container tab creation failed:", error); + throw error; + } + } + + /** + * Navigate to local I2P service + * @param {string} path Service path + */ + static async goToService(path) { + try { + const routerAddress = await RouterManager.getRouterAddress(); + await this.createTab({ + url: `http://${routerAddress}${path}`, + }); + } catch (error) { + console.error(`Service navigation failed : ${path}`, error); + } + } +} + +/** + * Router Manager for I2P router operations + */ +class RouterManager { + /** + * Get router address + * @return {string} + */ + static getRouterAddress() { + try { + return `${control_host()}:${control_port()}`; + } catch { + return `${CONFIG.ROUTER.DEFAULT_HOST}:${CONFIG.ROUTER.DEFAULT_PORT}`; + } + } + + /** + * Generate new identity + */ + static async generateNewIdentity() { + try { + const routerAddress = this.getRouterAddress(); + const response = await fetch(`http ://${routerAddress}`); + console.info("(info) New identity generated"); + return response; + } catch (error) { + console.error("Identity generation failed:", error); + throw error; + } + } +} + +/** + * UI Manager for handling interface elements + */ +class UIManager { + /** + * Toggle panel visibility + * @param {string} showPanel Panel to show + * @param {string} hidePanel Panel to hide + */ + static togglePanels(showPanel, hidePanel) { + try { + const show = document.getElementById(showPanel); + const hide = document.getElementById(hidePanel); + + if (show && hide) { + show.style.display = "block"; + hide.style.display = "none"; + } + } catch (error) { + console.error("Panel toggle failed:", error); + } + } + + /** + * Initialize UI elements + */ + static initializeUI() { + Object.values(UI_ELEMENTS.LISTS).forEach((listId) => { + const list = document.getElementById(listId); + if (list) { + list.style.display = "none"; + } }); - searching.then(onCleaned); - } - if (!history) { - if (i2pHost(historyItem)) { - var deletingUrl = browser.history.deleteUrl(historyItem.url); - } - deletingUrl.then(onRemoved); } } -/* -if (UpdateContents !== undefined) UpdateContents(); -*/ -const minutes = 0.2; -const interval = minutes * 60 * 1000; +/** + * Click Handler for UI interactions + */ +class ClickHandler { + /** + * Handle click events + * @param {MouseEvent} event Click event + */ + static async handleClick(event) { + event.preventDefault(); + const { id: targetId } = event.target; -setInterval(function () { - if (UpdateContents !== undefined) UpdateContents(); -}, interval); + try { + // Panel creation + if (targetId.startsWith("window-create-")) { + await TabManager.createTab({ + type: "panel", + incognito: true, + }); + } + + // Service navigation + else if (targetId.startsWith("window-visit-")) { + const service = targetId.split("-")[2]; + await this.handleServiceNavigation(service); + } + + // Settings toggles + else if (targetId === "enable-web-rtc") { + await this.handleWebRTCToggle(event.target.checked); + } + + // Other actions + else if (targetId === "generate-fresh-tunnel") { + await RouterManager.generateNewIdentity(); + } + } catch (error) { + console.error("Click handling failed:", error); + } + } + + /** + * Handle service navigation + * @param {string} service Service identifier + */ + static async handleServiceNavigation(service) { + const serviceMap = { + console: "/home", + i2ptunnel: "/i2ptunnel", + susimail: "/susimail", + snark: "/i2psnark", + }; + + if (serviceMap[service]) { + await TabManager.goToService(serviceMap[service]); + } + } +} + +/** + * Initialize the information manager + */ +async function initialize() { + try { + // Initialize privacy settings + await Promise.all([ + PrivacyManager.checkPeerConnection(), + PrivacyManager.checkSnowflake(), + PrivacyManager.checkHistory(), + PrivacyManager.checkReferer(), + ]); + + // Initialize UI + UIManager.initializeUI(); + document.addEventListener( + "click", + ClickHandler.handleClick.bind(ClickHandler) + ); + + // Set up content updates + if (typeof UpdateContents !== "undefined") { + setInterval(UpdateContents, CONFIG.UPDATE_INTERVAL); + } + + console.info("(info) Information manager initialized"); + } catch (error) { + console.error("Initialization failed:", error); + } +} + +// Initialize if browser API is available +if (browser?.windows) { + initialize(); +} + +// Export for testing +if (typeof module !== "undefined" && module.exports) { + module.exports = { + PrivacyManager, + TabManager, + RouterManager, + UIManager, + ClickHandler, + CONFIG, + }; +} diff --git a/proxyinfo.js b/proxyinfo.js index 5e5fc0a..a5f098d 100644 --- a/proxyinfo.js +++ b/proxyinfo.js @@ -1,62 +1,205 @@ -document.addEventListener("DOMContentLoaded", proxyStatus, false); +/** + * @fileoverview I2P Proxy Status Manager + * Handles proxy connectivity checking and UI updates for I2P extension + */ -function proxyStatus() { - console.log("(proxyinfo) checking proxy status"); - fetch("http://proxy.i2p", { cache: "no-store" }).then( - proxyStatusSuccess, - proxyStatusError - ); -} +// Constants +const PROXY_CONFIG = { + PROXY_URL: "http://proxy.i2p", + CONSOLE_URL: "http://127.0.0.1:7657", + LOGO_PATH: "/themes/console/light/images/i2plogo.png", + FETCH_OPTIONS: { cache: "no-store" }, +}; -function proxyStatusSuccess(myJson) { - console.warn("(proxyinfo)", myJson); - contentUpdateById("proxy-check", "proxySuccessStatus"); - let readyness = document.querySelectorAll(".readyness"); - if (readyness !== null) { - unhide(readyness); +const UI_ELEMENTS = { + PROXY_STATUS: "proxy-check", + READINESS_CLASS: ".readyness", + CONSOLE_LINKS: ".application-info", + HIDDEN_CLASS: "hidden", +}; + +const MESSAGE_KEYS = { + SUCCESS: "proxySuccessStatus", + FAILURE: "proxyFailedStatus", +}; + +/** + * UI Manager for handling element visibility + */ +class UIManager { + /** + * Toggle element visibility + * @param {Element|NodeList} elements - Elements to modify + * @param {boolean} show - Whether to show or hide + */ + /** + * Toggle element visibility with strict null checking + * @param {Element|NodeList} elements - Elements to modify + * @param {boolean} show - Whether to show or hide + */ + static toggleVisibility(elements, show) { + try { + // Validate input + if (!elements) { + throw new Error("Elements parameter is null or undefined"); + } + + // Convert to array if NodeList + const elementArray = + elements instanceof NodeList ? Array.from(elements) : [elements]; + + elementArray.forEach((element) => { + // Explicit null check for element and style property + if (element && element.style !== undefined && element.style !== null) { + const action = show ? "remove" : "add"; + element.classList[action](UI_ELEMENTS.HIDDEN_CLASS); + console.debug(`(proxyinfo) ${show ? "showing" : "hiding"} element`); + } else { + console.warn( + "(proxyinfo) Invalid element encountered during visibility toggle" + ); + } + }); + } catch (error) { + console.error("Visibility toggle failed:", error); + throw error; // Re-throw for error boundary handling + } + } + + /** + * Update element content by ID + * @param {string} elementId - Target element ID + * @param {string} messageKey - i18n message key + */ + static updateContent(elementId, messageKey) { + try { + const element = document.getElementById(elementId); + if (!element) { + throw new Error(`Element not found : ${elementId}`); + } + element.textContent = chrome.i18n.getMessage(messageKey); + } catch (error) { + console.error("Content update failed:", error); + } + } + + /** + * Get elements by selector + * @param {string} selector - CSS selector + * @return {?NodeList} + */ + static getElements(selector) { + try { + return document.querySelectorAll(selector); + } catch (error) { + console.error("Element selection failed:", error); + return null; + } } } -function proxyStatusError(error) { - console.error("(proxyinfo)", error); - contentUpdateById("proxy-check", "proxyFailedStatus"); - let readyness = document.querySelectorAll(".readyness"); - if (readyness !== null) { - hide(readyness); +/** + * Proxy Status Manager + */ +class ProxyStatusManager { + /** + * Check proxy connectivity + * @return {Promise} + */ + static async checkProxyStatus() { + console.info("(proxyinfo) Checking proxy status"); + try { + const response = await fetch( + PROXY_CONFIG.PROXY_URL, + PROXY_CONFIG.FETCH_OPTIONS + ); + await this.handleProxySuccess(response); + } catch (error) { + await this.handleProxyError(error); + } + } + + /** + * Handle successful proxy connection + * @param {Response} response - Fetch response + */ + static async handleProxySuccess(response) { + console.info("(proxyinfo) Proxy check successful"); + UIManager.updateContent(UI_ELEMENTS.PROXY_STATUS, MESSAGE_KEYS.SUCCESS); + + const readinessElements = UIManager.getElements( + UI_ELEMENTS.READINESS_CLASS + ); + if (readinessElements) { + UIManager.toggleVisibility(readinessElements, true); + } + } + + /** + * Handle proxy connection failure + * @param {Error} error - Connection error + */ + static async handleProxyError(error) { + console.error("(proxyinfo) Proxy check failed:", error); + UIManager.updateContent(UI_ELEMENTS.PROXY_STATUS, MESSAGE_KEYS.FAILURE); + + const readinessElements = UIManager.getElements( + UI_ELEMENTS.READINESS_CLASS + ); + if (readinessElements) { + UIManager.toggleVisibility(readinessElements, false); + } + } + + /** + * Check console connectivity + * @return {Promise} + */ + static async checkConsoleStatus() { + const logoUrl = `${PROXY_CONFIG.CONSOLE_URL}${PROXY_CONFIG.LOGO_PATH}`; + console.info("(proxyinfo) Checking console status"); + + try { + await fetch(logoUrl); + const consoleLinks = UIManager.getElements(UI_ELEMENTS.CONSOLE_LINKS); + if (consoleLinks) { + UIManager.toggleVisibility(consoleLinks, true); + } + console.info("(proxyinfo) Console check successful"); + } catch (error) { + const consoleLinks = UIManager.getElements(UI_ELEMENTS.CONSOLE_LINKS); + if (consoleLinks) { + UIManager.toggleVisibility(consoleLinks, false); + } + console.error("(proxyinfo) Console check failed:", error); + } } } -function hide(elements) { - console.log("(proxyinfo) hiding", elements); - const elems = Array.isArray(elements) ? elements : [elements]; - elems.forEach((elem) => { - if (elem.style) { - console.log("(proxyinfo) hiding"); - elem.classList.add("hidden"); - } - }); +/** + * Initialize proxy status checking + */ +function initializeProxyChecks() { + try { + ProxyStatusManager.checkProxyStatus(); + ProxyStatusManager.checkConsoleStatus(); + } catch (error) { + console.error("Proxy initialization failed:", error); + } } -function unhide(elements) { - console.log("(proxyinfo) unhiding", elements); - const elems = Array.isArray(elements) ? elements : [elements]; - elems.forEach((elem) => { - if (elem.style) { - console.log("(proxyinfo) unhiding"); - elem.classList.remove("hidden"); - } - }); -} +// Event Listeners +document.addEventListener("DOMContentLoaded", initializeProxyChecks, { + passive: true, + capture: false, +}); -//TODO: Don't hard-code this. -fetch("http://127.0.0.1:7657/themes/console/light/images/i2plogo.png") - .then((myJson) => { - console.log("(proxyinfo) img test pass", myJson); - var consoleLinks = document.querySelectorAll(".application-info"); - unhide(consoleLinks); - }) - .catch((error) => { - console.log("(proxyinfo) img test fail", error); - var consoleLinks = document.querySelectorAll(".application-info"); - hide(consoleLinks); - }); +// Export for testing +if (typeof module !== "undefined" && module.exports) { + module.exports = { + ProxyStatusManager, + UIManager, + PROXY_CONFIG, + UI_ELEMENTS, + }; +}