/* * This file is part of Privacy Badger * Copyright (C) 2014 Electronic Frontier Foundation * Derived from Adblock Plus * Copyright (C) 2006-2013 Eyeo GmbH * * Privacy Badger is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * Privacy Badger is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Privacy Badger. If not, see . */ window.POPUP_INITIALIZED = false; window.SLIDERS_DONE = false; var constants = require("constants"); var FirefoxAndroid = require("firefoxandroid"); var htmlUtils = require("htmlutils").htmlUtils; let POPUP_DATA = {}; /* if they aint seen the comic*/ function showNagMaybe() { var $nag = $("#instruction"); var $outer = $("#instruction-outer"); let intro_page_url = chrome.runtime.getURL("/skin/firstRun.html"); function _setSeenComic(cb) { chrome.runtime.sendMessage({ type: "seenComic" }, cb); } function _setSeenLearningPrompt(cb) { chrome.runtime.sendMessage({ type: "seenLearningPrompt" }, cb); } function _hideNag() { $nag.fadeOut(); $outer.fadeOut(); } function _showNag() { $nag.show(); $outer.show(); // Attach event listeners $('#fittslaw').on("click", function (e) { e.preventDefault(); _setSeenComic(() => { _hideNag(); }); }); $("#intro-reminder-btn").on("click", function () { // If there is a firstRun.html tab, switch to the tab. // Otherwise, create a new tab chrome.tabs.query({url: intro_page_url}, function (tabs) { if (tabs.length == 0) { chrome.tabs.create({ url: intro_page_url }); } else { chrome.tabs.update(tabs[0].id, {active: true}, function (tab) { chrome.windows.update(tab.windowId, {focused: true}); }); } _setSeenComic(() => { window.close(); }); }); }); } function _showError(error_text) { $('#instruction-text').hide(); $('#error-text').show().find('a') .attr('id', 'critical-error-link') .css({ padding: '5px', display: 'inline-block', width: 'auto', }); $('#error-message').text(error_text); $('#fittslaw').on("click", function (e) { e.preventDefault(); _hideNag(); }); $nag.show(); $outer.show(); } function _showLearningPrompt() { $('#instruction-text').hide(); $("#learning-prompt-btn").on("click", function () { chrome.tabs.create({ url: "https://www.eff.org/badger-evolution" }); _setSeenLearningPrompt(function () { window.close(); }); }); $('#fittslaw').on("click", function (e) { e.preventDefault(); _setSeenLearningPrompt(function () { _hideNag(); }); }); $('#learning-prompt-div').show(); $nag.show(); $outer.show(); } if (POPUP_DATA.showLearningPrompt) { _showLearningPrompt(); } else if (!POPUP_DATA.seenComic) { chrome.tabs.query({active: true, currentWindow: true}, function (focusedTab) { // Show the popup instruction if the active tab is not firstRun.html page if (!focusedTab[0].url.startsWith(intro_page_url)) { _showNag(); } }); } else if (POPUP_DATA.criticalError) { _showError(POPUP_DATA.criticalError); } } /** * Init function. Showing/hiding popup.html elements and setting up event handler */ function init() { showNagMaybe(); $("#activate_site_btn").on("click", activateOnSite); $("#deactivate_site_btn").on("click", deactivateOnSite); $("#donate").on("click", function() { chrome.tabs.create({ url: "https://supporters.eff.org/donate/support-privacy-badger" }); }); $('#error_input').on('input propertychange', function() { // No easy way of sending message on popup close, send message for every change chrome.runtime.sendMessage({ type: 'saveErrorText', tabId: POPUP_DATA.tabId, errorText: $("#error_input").val() }); }); let overlay = $('#overlay'); // show error layout if the user was writing an error report if (POPUP_DATA.hasOwnProperty('errorText') && POPUP_DATA.errorText) { overlay.toggleClass('active'); } $("#error").on("click", function() { overlay.toggleClass('active'); }); $("#report-cancel").on("click", function() { clearSavedErrorText(); closeOverlay(); }); $("#report-button").on("click", function() { $(this).prop("disabled", true); $("#report-cancel").prop("disabled", true); send_error($("#error_input").val()); }); $("#report_close").on("click", function (e) { e.preventDefault(); clearSavedErrorText(); closeOverlay(); }); $('#blockedResourcesContainer').on('change', 'input:radio', updateOrigin); $('#blockedResourcesContainer').on('click', '.userset .honeybadgerPowered', revertDomainControl); $("#version").text( chrome.i18n.getMessage("version", chrome.runtime.getManifest().version) ); // improve on Firefox's built-in options opening logic if (typeof browser == "object" && typeof browser.runtime.getBrowserInfo == "function") { browser.runtime.getBrowserInfo().then(function (info) { if (info.name == "Firefox") { $("#options").on("click", function (e) { e.preventDefault(); openPage(chrome.runtime.getURL("/skin/options.html")); }); $("#help").on("click", function (e) { e.preventDefault(); openPage(this.getAttribute('href')); }); } }); } $("#share").on("click", function (e) { e.preventDefault(); share(); }); $("#share_close").on("click", function (e) { e.preventDefault(); $("#share_overlay").toggleClass('active', false); }); $("#copy-button").on("click", function() { $("#share_output").select(); document.execCommand('copy'); $(this).text(chrome.i18n.getMessage("copy_button_copied")); }); window.POPUP_INITIALIZED = true; } function openPage(url) { // first get the active tab chrome.tabs.query({ active: true, lastFocusedWindow: true }, (tabs) => { let activeTab = tabs[0], tabProps = { url, windowId: activeTab.windowId, active: true, index: activeTab.index + 1, openerTabId: activeTab.id }; // create the new tab try { chrome.tabs.create(tabProps); } catch (e) { // TODO workaround for pre-57 Firefox delete tabProps.openerTabId; chrome.tabs.create(tabProps); } window.close(); }); } function clearSavedErrorText() { chrome.runtime.sendMessage({ type: 'removeErrorText', tabId: POPUP_DATA.tabId }); } /** * Close the error reporting overlay */ function closeOverlay() { $('#overlay').toggleClass('active', false); $("#report-success").hide(); $("#report-fail").hide(); $("#error_input").val(""); } /** * Send errors to PB error reporting server * * @param {String} message The message to send */ function send_error(message) { // get the latest domain list from the background page chrome.runtime.sendMessage({ type: "getPopupData", tabId: POPUP_DATA.tabId, tabUrl: POPUP_DATA.tabUrl }, (response) => { const origins = response.origins; if (!origins) { return; } let out = { browser: window.navigator.userAgent, fqdn: response.tabHost, message: message, url: response.tabUrl, version: chrome.runtime.getManifest().version }; for (let origin in origins) { let action = origins[origin]; // adjust action names for error reporting if (action == constants.USER_ALLOW) { action = "usernoaction"; } else if (action == constants.USER_BLOCK) { action = "userblock"; } else if (action == constants.USER_COOKIEBLOCK) { action = "usercookieblock"; } else if (action == constants.ALLOW) { action = "noaction"; } else if (action == constants.BLOCK || action == constants.COOKIEBLOCK) { // no need to adjust action } else if (action == constants.DNT || action == constants.NO_TRACKING) { action = "notracking"; } if (out[action]) { out[action] += ","+origin; } else { out[action] = origin; } } var sendReport = $.ajax({ type: "POST", url: "https://privacybadger.org/reporting", data: JSON.stringify(out), contentType: "application/json" }); sendReport.done(function() { $("#error_input").val(""); $("#report-success").slideDown(); clearSavedErrorText(); setTimeout(function() { $("#report-button").prop("disabled", false); $("#report-cancel").prop("disabled", false); closeOverlay(); }, 3000); }); sendReport.fail(function() { $("#report-fail").slideDown(); setTimeout(function() { $("#report-button").prop("disabled", false); $("#report-cancel").prop("disabled", false); $("#report-fail").slideUp(); }, 3000); }); }); } /** * activate PB for site event handler */ function activateOnSite() { $("#activate_site_btn").toggle(); $("#deactivate_site_btn").toggle(); $("#blockedResourcesContainer").show(); chrome.runtime.sendMessage({ type: "activateOnSite", tabHost: POPUP_DATA.tabHost, tabId: POPUP_DATA.tabId, tabUrl: POPUP_DATA.tabUrl }, () => { chrome.tabs.reload(POPUP_DATA.tabId); window.close(); }); } /** * de-activate PB for site event handler */ function deactivateOnSite() { $("#activate_site_btn").toggle(); $("#deactivate_site_btn").toggle(); $("#blockedResourcesContainer").hide(); chrome.runtime.sendMessage({ type: "deactivateOnSite", tabHost: POPUP_DATA.tabHost, tabId: POPUP_DATA.tabId, tabUrl: POPUP_DATA.tabUrl }, () => { chrome.tabs.reload(POPUP_DATA.tabId); window.close(); }); } /** * Open the share overlay */ function share() { $("#share_overlay").toggleClass('active'); let share_msg = chrome.i18n.getMessage("share_base_message"); // only add language about found trackers if we actually found trackers // (but regardless of whether we are actually blocking them) if (POPUP_DATA.noTabData) { $("#share_output").val(share_msg); return; } let origins = POPUP_DATA.origins; let originsArr = []; if (origins) { originsArr = Object.keys(origins); } if (!originsArr.length) { $("#share_output").val(share_msg); return; } originsArr = htmlUtils.sortDomains(originsArr); let tracking = []; for (let origin of originsArr) { let action = origins[origin]; if (action == constants.BLOCK || action == constants.COOKIEBLOCK) { tracking.push(origin); } } if (tracking.length) { share_msg += "\n\n"; share_msg += chrome.i18n.getMessage( "share_tracker_header", [tracking.length, POPUP_DATA.tabHost]); share_msg += "\n\n"; share_msg += tracking.join("\n"); } $("#share_output").val(share_msg); } /** * Handler to undo user selection for a tracker */ function revertDomainControl(event) { event.preventDefault(); let origin = $(event.target).parent().data('origin'); chrome.runtime.sendMessage({ type: "revertDomainControl", origin: origin }, () => { chrome.tabs.reload(POPUP_DATA.tabId); window.close(); }); } /** * Refresh the content of the popup window * * @param {Integer} tabId The id of the tab */ function refreshPopup() { window.SLIDERS_DONE = false; // must be a special browser page, if (POPUP_DATA.noTabData) { // show the "nothing to do here" message $('#blockedResourcesContainer').hide(); $('#special-browser-page').show(); // hide inapplicable buttons $('#deactivate_site_btn').hide(); $('#error').hide(); // activate tooltips $('.tooltip').tooltipster(); window.SLIDERS_DONE = true; return; } // revert any hiding/showing above for cases when refreshPopup gets called // more than once for the same popup, such as during functional testing $('#blockedResourcesContainer').show(); $('#special-browser-page').hide(); $('#deactivate_site_btn').show(); $('#error').show(); // toggle activation buttons if privacy badger is not enabled for current url if (!POPUP_DATA.enabled) { $("#blockedResourcesContainer").hide(); $("#activate_site_btn").show(); $("#deactivate_site_btn").hide(); $("#disabled-site-message").show(); $("#title").addClass("faded-bw-color-scheme"); } // if there is any saved error text, fill the error input with it if (POPUP_DATA.hasOwnProperty('errorText')) { $("#error_input").val(POPUP_DATA.errorText); } let origins = POPUP_DATA.origins; let originsArr = []; if (origins) { originsArr = Object.keys(origins); } if (!originsArr.length) { // hide the number of trackers and slider instructions message // if no sliders will be displayed $("#instructions-many-trackers").hide(); // show "no trackers" message $("#instructions-no-trackers").show(); if (POPUP_DATA.learnLocally && POPUP_DATA.showNonTrackingDomains) { // show the "no third party resources on this site" message $("#no-third-parties").show(); } // activate tooltips $('.tooltip').tooltipster(); window.SLIDERS_DONE = true; return; } let printable = []; let unblockedTrackers = []; let nonTracking = []; originsArr = htmlUtils.sortDomains(originsArr); for (let origin of originsArr) { let action = origins[origin]; if (action == constants.NO_TRACKING) { nonTracking.push(origin); } else if (action == constants.ALLOW) { unblockedTrackers.push(origin); } else { let show_breakage_warning = ( action == constants.USER_BLOCK && POPUP_DATA.cookieblocked.hasOwnProperty(origin) ); printable.push( htmlUtils.getOriginHtml(origin, action, show_breakage_warning) ); } } if (POPUP_DATA.learnLocally && unblockedTrackers.length) { printable.push( '
' + chrome.i18n.getMessage("not_yet_blocked_header") + '
' ); unblockedTrackers.forEach(domain => { printable.push( htmlUtils.getOriginHtml(domain, constants.ALLOW) ); }); // reduce margin if we have hasn't-decided-yet-to-block domains to show $("#instructions-no-trackers").css("margin", "10px 0"); } if (POPUP_DATA.learnLocally && POPUP_DATA.showNonTrackingDomains && nonTracking.length) { printable.push( '
' + chrome.i18n.getMessage("non_tracker") + '
' ); for (let i = 0; i < nonTracking.length; i++) { printable.push( htmlUtils.getOriginHtml(nonTracking[i], constants.NO_TRACKING) ); } // reduce margin if we have non-tracking domains to show $("#instructions-no-trackers").css("margin", "10px 0"); } if (printable.length) { // get containing HTML for domain list along with toggle legend icons $("#blockedResources")[0].innerHTML = htmlUtils.getTrackerContainerHtml(); } // activate tooltips $('.tooltip').tooltipster(); if (POPUP_DATA.trackerCount === 0) { // hide multiple trackers message $("#instructions-many-trackers").hide(); // show "no trackers" message $("#instructions-no-trackers").show(); } else { $('#instructions-many-trackers').html(chrome.i18n.getMessage( "popup_instructions", [ POPUP_DATA.trackerCount, "" ] )).find(".tooltip").tooltipster(); } function renderDomains() { const CHUNK = 1; let $printable = $(printable.splice(0, CHUNK).join("")); // Hide elements for removing origins (controlled from the options page). // Popup shows what's loaded for the current page so it doesn't make sense // to have removal ability here. $printable.find('.removeOrigin').hide(); $printable.appendTo('#blockedResourcesInner'); // activate tooltips $('#blockedResourcesInner .tooltip:not(.tooltipstered)').tooltipster( htmlUtils.DOMAIN_TOOLTIP_CONF); if (printable.length) { requestAnimationFrame(renderDomains); } else { window.SLIDERS_DONE = true; } } if (printable.length) { requestAnimationFrame(renderDomains); } else { window.SLIDERS_DONE = true; } } /** * Update the user preferences displayed in the domain list for this origin. * These UI changes will later be used to update user preferences data. * * @param {Event} event Click event triggered by user. */ function updateOrigin() { // get the origin and new action for it let $radio = $(this), action = $radio.val(), $switchContainer = $radio.parents('.switch-container').first(); // update slider color via CSS $switchContainer.removeClass([ constants.BLOCK, constants.COOKIEBLOCK, constants.ALLOW, constants.NO_TRACKING].join(" ")).addClass(action); let $clicker = $radio.parents('.clicker').first(), origin = $clicker.data('origin'), show_breakage_warning = ( action == constants.BLOCK && POPUP_DATA.cookieblocked.hasOwnProperty(origin) ); htmlUtils.toggleBlockedStatus($clicker, true, show_breakage_warning); // reinitialize the domain tooltip $clicker.find('.origin-inner').tooltipster('destroy'); $clicker.find('.origin-inner').attr( 'title', htmlUtils.getActionDescription(action, origin)); $clicker.find('.origin-inner').tooltipster(htmlUtils.DOMAIN_TOOLTIP_CONF); // persist the change saveToggle(origin, action); } /** * Save the user setting for a domain by messaging the background page. */ function saveToggle(origin, action) { chrome.runtime.sendMessage({ type: "savePopupToggle", origin, action, tabId: POPUP_DATA.tabId }); } function getTab(callback) { // Temporary fix for Firefox Android if (!FirefoxAndroid.hasPopupSupport) { FirefoxAndroid.getParentOfPopup(callback); return; } chrome.tabs.query({active: true, lastFocusedWindow: true}, function(t) { callback(t[0]); }); } /** * Workaround for geckodriver being unable to modify page globals. */ function setPopupData(data) { POPUP_DATA = data; } $(function () { $.tooltipster.setDefaults(htmlUtils.TOOLTIPSTER_DEFAULTS); getTab(function (tab) { chrome.runtime.sendMessage({ type: "getPopupData", tabId: tab.id, tabUrl: tab.url }, (response) => { setPopupData(response); refreshPopup(); init(); }); }); });