diff --git a/_locales/de/messages.json b/_locales/de/messages.json index 358036b..a976ef8 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -189,6 +189,43 @@ "description": "" }, + "persistentRndClearInterval_title": { + "message": "Löschintervall der persistenten Daten", + "description": "" + }, + "persistentRndClearInterval_description": { + "message": "Nach dem eingestellten Intervall werden die persistenten Daten automatisch gelöscht. (Null eingeben, um es zu deaktivieren.)", + "description": "" + }, + "persistentRndClearIntervalUnit_options.seconds": { + "message": "Sekunden", + "description": "" + }, + "persistentRndClearIntervalUnit_options.minutes": { + "message": "Minuten", + "description": "" + }, + "persistentRndClearIntervalUnit_options.hours": { + "message": "Stunden", + "description": "" + }, + "persistentRndClearIntervalUnit_options.days": { + "message": "Tage", + "description": "" + }, + "persistentRndClearIntervalUnit_options.weeks": { + "message": "Wochen", + "description": "" + }, + "persistentRndClearIntervalUnit_options.months": { + "message": "Monate", + "description": "" + }, + "persistentRndClearIntervalUnit_options.years": { + "message": "Jahre", + "description": "" + }, + "clearPersistentRnd_title": { "message": "Persistenten Speicher leeren", "description": "" diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 5a71678..fb8e2a1 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -189,6 +189,43 @@ "description": "" }, + "persistentRndClearInterval_title": { + "message": "Clear interval of the persistent data", + "description": "" + }, + "persistentRndClearInterval_description": { + "message": "After the specified interval the persistent data is cleared automatically. (Enter zero to disable.)", + "description": "" + }, + "persistentRndClearIntervalUnit_options.seconds": { + "message": "seconds", + "description": "" + }, + "persistentRndClearIntervalUnit_options.minutes": { + "message": "minutes", + "description": "" + }, + "persistentRndClearIntervalUnit_options.hours": { + "message": "hours", + "description": "" + }, + "persistentRndClearIntervalUnit_options.days": { + "message": "days", + "description": "" + }, + "persistentRndClearIntervalUnit_options.weeks": { + "message": "weeks", + "description": "" + }, + "persistentRndClearIntervalUnit_options.months": { + "message": "months", + "description": "" + }, + "persistentRndClearIntervalUnit_options.years": { + "message": "years", + "description": "" + }, + "clearPersistentRnd_title": { "message": "Clear persistent random storage", "description": "" diff --git a/lib/logging.js b/lib/logging.js index 7bfd49b..3d289ef 100644 --- a/lib/logging.js +++ b/lib/logging.js @@ -85,13 +85,13 @@ metaLog("logging queue cleared"); } }; - settings.on("isStillDefault", scope.clearQueue); + settings.loaded.then(scope.clearQueue); scope.error = error; scope.warning = warning; scope.message = message; scope.notice = notice; scope.verbose = verbose; - + require.emit("./logging"); metaLog("logging available"); diff --git a/lib/main.js b/lib/main.js index bba2533..c334b75 100644 --- a/lib/main.js +++ b/lib/main.js @@ -9,33 +9,13 @@ const {error, warning, message, notice, verbose, } = logging; const lists = require("./lists"); logging.setPrefix("main script"); + const persistentRndStorage = require("./persistentRndStorage"); message("start of background script"); message("waiting for settings to be loaded"); settings.onloaded(function(){ notice("everything loaded"); - notice("build persistent storage"); - var persistentRnd = Object.create(null); - try { - let storedData = JSON.parse(settings.persistentRndStorage); - for (var domain in storedData){ - var value = storedData[domain]; - if ( - Array.isArray(value) && - value.length === 128 && - value.every(function(value){ - return typeof value === "number" && value >= 0 && value < 256; - }) - ){ - persistentRnd[domain] = value; - } - } - } - catch(e){ - // JSON is not valid -> ignore it - } - function updateContentScripts(){ message("update content scripts"); notice("build settings blob"); @@ -51,24 +31,26 @@ warning("TODO: register content scripts -> have to wait for the API to be released"); } updateContentScripts(); + persistentRndStorage.init(); message("register non port message listener"); browser.runtime.onMessage.addListener(function(data){ notice("got data without port", data); + var keys = Object.keys(data); if (data["canvasBlocker-new-domain-rnd"]){ - verbose("got new domain rnd", data["canvasBlocker-new-domain-rnd"]); - data["canvasBlocker-set-domain-rnd"] = data["canvasBlocker-new-domain-rnd"]; - persistentRnd[data["canvasBlocker-new-domain-rnd"].domain] = data["canvasBlocker-new-domain-rnd"].rnd; - if (settings.storePersistentRnd){ - settings.persistentRndStorage = JSON.stringify(persistentRnd); + persistentRndStorage.setDomainData( + data["canvasBlocker-new-domain-rnd"].domain, + data["canvasBlocker-new-domain-rnd"].rnd + ); + if (keys.length === 1){ + return; } updateContentScripts(); } if (data["canvasBlocker-clear-domain-rnd"]){ - verbose("domain rnd cleared"); - persistentRnd = Object.create(null); - if (settings.storePersistentRnd){ - settings.persistentRndStorage = JSON.stringify(persistentRnd); + persistentRndStorage.clear(); + if (keys.length === 1){ + return; } updateContentScripts(); } @@ -84,10 +66,10 @@ browser.runtime.onConnect.addListener(function(port){ notice("got port", port); verbose("send back the tab id", port.sender.tab.id); - verbose("send back the persistent random seeds", persistentRnd); + verbose("send back the persistent random seeds", persistentRndStorage.persistentRnd); port.postMessage({ tabId: port.sender.tab.id, - persistentRnd: persistentRnd + persistentRnd: persistentRndStorage.persistentRnd }); var url = new URL(port.sender.url); port.onMessage.addListener(function(data){ @@ -116,9 +98,6 @@ }); } }); - settings.on("storePersistentRnd", function({newValue}){ - settings.persistentRndStorage = newValue? JSON.stringify(persistentRnd): ""; - }); // hide page action when a tab is refreshed browser.tabs.onUpdated.addListener(function(tabId, data){ diff --git a/lib/persistentRndStorage.js b/lib/persistentRndStorage.js new file mode 100644 index 0000000..758099c --- /dev/null +++ b/lib/persistentRndStorage.js @@ -0,0 +1,111 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +(function(){ + "use strict"; + + var scope; + if ((typeof exports) !== "undefined"){ + scope = exports; + } + else { + scope = {}; + window.scope.persistentRndStorage = scope; + } + + + const settings = require("./settings"); + const logging = require("./logging"); + + scope.persistentRnd = Object.create(null); + scope.init = function init(){ + logging.message("initializing persistent rng storage"); + + logging.notice("build persistent storage"); + + if (settings.storePersistentRnd){ + try { + let storedData = JSON.parse(settings.persistentRndStorage); + for (var domain in storedData){ + var value = storedData[domain]; + if ( + Array.isArray(value) && + value.length === 128 && + value.every(function(value){ + return typeof value === "number" && value >= 0 && value < 256; + }) + ){ + scope.persistentRnd[domain] = value; + } + } + } + catch (e){ + // JSON is not valid -> ignore it + } + } + else { + settings.persistentRndStorage = ""; + settings.lastPersistentRndClearing = Date.now(); + } + + registerTimeout(); + + logging.notice("register settings change event listener"); + settings.on(["persistentRndClearIntervalValue", "persistentRndClearIntervalUnit"], function(){ + window.clearTimeout(clearTimeout); + registerTimeout(); + }); + settings.on("storePersistentRnd", function({newValue}){ + settings.persistentRndStorage = newValue? JSON.stringify(scope.persistentRnd): ""; + }); + }; + + const getInterval = function(){ + var units = { + seconds: 1000, + minutes: 60 * 1000, + hours: 60 * 60 * 1000, + days: 24 * 60 * 60 * 1000, + weeks: 7 * 24 * 60 * 60 * 1000, + months: 30 * 24 * 60 * 60 * 1000, + years: 365 * 24 * 60 * 60 * 1000, + }; + return function getInterval(){ + return settings.persistentRndClearIntervalValue * units[settings.persistentRndClearIntervalUnit] || 0; + }; + }(); + + let clearTimeout; + function registerTimeout(){ + var interval = getInterval(); + if (interval > 0){ + var timeout = settings.lastPersistentRndClearing + interval - Date.now(); + logging.message("registering persistent rng data clearing timeout. Clearing in ", timeout, "ms"); + clearTimeout = window.setTimeout(clear, timeout); + } + } + function broadcast(data){ + browser.tabs.query({}).then(function(tabs){ + tabs.forEach(function(tab){ + browser.tabs.sendMessage(tab.id, data); + }); + }); + } + function clear(){ + logging.verbose("domain rnd cleared"); + scope.persistentRnd = Object.create(null); + settings.persistentRndStorage = JSON.stringify(scope.persistentRnd); + settings.lastPersistentRndClearing = Date.now(); + registerTimeout(); + broadcast({"canvasBlocker-clear-domain-rnd": true}); + } + function setDomainData(domain, rnd){ + logging.verbose("got new domain rnd for ", domain, ":", rnd); + scope.persistentRnd[domain] = rnd; + settings.persistentRndStorage = JSON.stringify(scope.persistentRnd); + broadcast({"canvasBlocker-set-domain-rnd": {domain, rnd}}); + } + + scope.clear = clear; + scope.setDomainData = setDomainData; +}()); \ No newline at end of file diff --git a/lib/randomSupplies.js b/lib/randomSupplies.js index dc53014..5e97656 100644 --- a/lib/randomSupplies.js +++ b/lib/randomSupplies.js @@ -12,6 +12,8 @@ window.scope.randomSupplies = {}; scope = window.scope.randomSupplies; } + + const settings = require("./settings"); function getDomain(window){ if (!window.location.href || window.location.href === "about:blank"){ @@ -26,6 +28,26 @@ } var persistentRnd = Object.create(null); + settings.onloaded(function(){ + try { + let storedData = JSON.parse(settings.persistentRndStorage); + for (var domain in storedData){ + var value = storedData[domain]; + if ( + Array.isArray(value) && + value.length === 128 && + value.every(function(value){ + return typeof value === "number" && value >= 0 && value < 256; + }) + ){ + persistentRnd[domain] = value; + } + } + } + catch (e){ + // JSON is not valid -> ignore it + } + }); const getPersistentRnd = (function(){ browser.runtime.onMessage.addListener(function(data){ diff --git a/lib/settingDefinitions.js b/lib/settingDefinitions.js index c71d23b..87fae41 100644 --- a/lib/settingDefinitions.js +++ b/lib/settingDefinitions.js @@ -59,6 +59,19 @@ name: "storePersistentRnd", defaultValue: false }, + { + name: "persistentRndClearIntervalValue", + defaultValue: 0 + }, + { + name: "persistentRndClearIntervalUnit", + defaultValue: "days", + options: ["seconds", "minutes", "hours", "days", "weeks", "months", "years"] + }, + { + name: "lastPersistentRndClearing", + defaultValue: 0 + }, { name: "askOnlyOnce", defaultValue: true diff --git a/lib/settings.js b/lib/settings.js index 725477b..d451fde 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -98,11 +98,18 @@ }).forEach(...args); }; scope.on = function onSettingsChange(name, callback){ - if (eventHandler.hasOwnProperty(name)){ - eventHandler[name].push(callback); + if (Array.isArray(name)){ + name.forEach(function(name){ + onSettingsChange(name, callback); + }); } else { - logging.warning("Unable to register event handler for unknown setting", name); + if (eventHandler.hasOwnProperty(name)){ + eventHandler[name].push(callback); + } + else { + logging.warning("Unable to register event handler for unknown setting", name); + } } }; diff --git a/manifest.json b/manifest.json index 048ef43..ce7f192 100644 --- a/manifest.json +++ b/manifest.json @@ -13,6 +13,7 @@ "lib/settings.js", "lib/logging.js", "lib/lists.js", + "lib/persistentRndStorage.js", "lib/main.js" ] }, diff --git a/options/options.css b/options/options.css index 7c45cd6..edba211 100644 --- a/options/options.css +++ b/options/options.css @@ -25,4 +25,13 @@ input[type=""], input[type="text"], input[type="number"], select { width: 100%; box-sizing: border-box; +} +*.multiple2 { + width: 50% !important; +} +*.multiple3 { + width: 33% !important; +} +*.multiple4 { + width: 25% !important; } \ No newline at end of file diff --git a/options/options.js b/options/options.js index 87b4ec3..5f09ab6 100644 --- a/options/options.js +++ b/options/options.js @@ -31,7 +31,13 @@ settingsDisplay.forEach(function(display){ var setting = settings.getDefinition(display.name); if (!setting){ - if (callbacks[display.name]){ + if (display.inputs){ + setting = { + name: display.name, + inputs: display.inputs.map(settings.getDefinition) + }; + } + else if (callbacks[display.name]){ setting = { name: display.name, action: callbacks[display.name] diff --git a/options/optionsGui.js b/options/optionsGui.js index 8787747..2eae93e 100644 --- a/options/optionsGui.js +++ b/options/optionsGui.js @@ -140,6 +140,14 @@ if (setting.action){ interaction = createButton(setting); } + else if (setting.inputs){ + interaction = document.createElement("span"); + setting.inputs.forEach(function(inputSetting){ + var input = createInput(inputSetting); + input.classList.add("multiple" + setting.inputs.length); + interaction.appendChild(input); + }); + } else { interaction = createInput(setting); } diff --git a/options/settingsDisplay.js b/options/settingsDisplay.js index 34c3ebf..ca83bde 100644 --- a/options/settingsDisplay.js +++ b/options/settingsDisplay.js @@ -51,6 +51,15 @@ "displayAdvancedSettings": [true] } }, + { + "name": "persistentRndClearInterval", + "inputs": ["persistentRndClearIntervalValue", "persistentRndClearIntervalUnit"], + "displayDependencies": { + "blockMode": ["fakeReadout", "fakeInput"], + "rng": ["persistent"], + "displayAdvancedSettings": [true] + } + }, { "name": "clearPersistentRnd", "displayDependencies": { diff --git a/releaseNotes.txt b/releaseNotes.txt index 7dcfb9c..f954318 100644 --- a/releaseNotes.txt +++ b/releaseNotes.txt @@ -1,10 +1,11 @@ Version 0.4.1: changes: - improved design of the page action display - - + - Enabled Firefox ESR + - persistent random generator data is always stored in the settings but cleared on restart if the store flag is not set new features: - - + - setting to set an interval to clear the persistent random generator data fixes: - unnecessary check for context type in getImageData broke websites