diff --git a/src/manifest.json b/src/manifest.json index b058623..ef5d392 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -21,7 +21,7 @@ "web_accessible_resources": [ { "matches": ["http://*/*", "https://*/*"], - "resources": ["scripts/*.js", "scripts/platform/*.js"] + "resources": ["scripts/*.js", "scripts/platform/*.js", "config/filters/*.filter"] } ], diff --git a/src/scripts/background/check.js b/src/scripts/background/check.js index 8a90503..80141b6 100644 --- a/src/scripts/background/check.js +++ b/src/scripts/background/check.js @@ -10,10 +10,25 @@ import {background, global} from "/scripts/secretariat.js"; export default class BackgroundCheck { update = {}; + status = {}; constructor () { - this.manager = new EntryManager(); - this.updater(); + const main = () => { + global.read([`ready`]).then((STATE) => { + if (STATE && !this.status[`ready`]) { + this.manager = new EntryManager(); + this.updater(); + + this.status[`ready`] = true; + }; + + if (this.status[`ready`]) { + (this.status.wait) ? this.status.wait.cancel() : false; + }; + }); + }; + + this.status.wait = new background(() => {main();}) }; updater() { @@ -26,94 +41,96 @@ export default class BackgroundCheck { if (!(typeof DURATION_PREFERENCES).includes(`obj`) || !DURATION_PREFERENCES || Array.isArray(DURATION_PREFERENCES)) { DURATION_PREFERENCES = {}; DURATION_PREFERENCES[`duration`] = 24; - + // Write it. - return(await global.write([`settings`, `sync`], DURATION_PREFERENCES, -1, {"silent": true})); - } else {return (true)}; + return(global.write([`settings`, `sync`, `duration`], DURATION_PREFERENCES[`duration`], -1, {"silent": true})); + } else {return(true)}; + }; + + // Set the filter management. + let filter = new FilterManager(); + + /* + Run the update. + + @return {Promise} the last update status. + */ + const updater_run = async () => { + filter.update(); + + // Update the last update time. + return(await global.write([`settings`,`sync`,`last`], Date.now(), -1, {"silent": true})); + }; + + /* + Check if it's time to update the filters through comparing the difference of the current time and the last updated time to the expected duration. + */ + async function updater_check() { + let TIME = {}; + TIME[`now`] = Date.now(); + TIME[`last`] = await global.read([`settings`,`sync`,`last`], -1); + + // Run if the last time is not set or if the difference is greater than the expected duration. + return (TIME[`last`] ? ((TIME[`now`] - TIME[`last`]) > DURATION_PREFERENCES[`duration`]) : true); + }; + + // Set the interval. + let updater_set = () => { + this.update[`checker`] = setInterval(async () => { + // Update the filters. + updater_run(); + }, DURATION_PREFERENCES[`duration`]); }; - setDefaults().then((result) => { - if (result) { - /* - Check if it's time to update the filters through comparing the difference of the current time and the last updated time to the expected duration. - */ - async function updater_check() { - let TIME = {}; - TIME[`now`] = Date.now(); - TIME[`last`] = await global.read([`settings`,`sync`,`last`], -1); + /* + Reset the interval. + */ + const updater_reset = () => { + // Cancel the interval. + (this.update[`checker`]) ? clearInterval(this.update[`checker`]) : false; - // Run if the last time is not set or if the difference is greater than the expected duration. - return (TIME[`last`] ? ((TIME[`now`] - TIME[`last`]) > DURATION_PREFERENCES[`duration`]) : true); + // Run the updater, if necessary. + (updater_check()) + ? updater_run() + : false; + + // Start the new interval. + updater_set(); + } + + const updater_background = () => { + this.update[`background`] = async () => { + if ((await global.read([`settings`, `sync`, `duration`])) ? (await global.read([`settings`, `sync`, `duration`] * (60 ** 2) * 1000 != DURATION_PREFERENCES[`duration`])) : false) { + if (await global.global.read([`settings`, `sync`, `duration`])) { + // Get the new time. + DURATION_PREFERENCES[`duration`] = await global.read([`settings`, `sync`, `duration`]) * (60 ** 2) * 1000; + + // Reset the updater. + updater_reset(); + } }; + }; - /* - Run the update. + // Set the background checker. + new background(() => {return(this.update.background())}); + } + + if (!(DURATION_PREFERENCES)) { + DURATION_PREFERENCES = {}; + }; - @return {Promise} the promise that, once resolved, contains the last update status. - */ - const updater_run = async () => { - filter.update(); + // Convert DURATION_PREFERENCES[`duration`]) from hrs to milliseconds. + if (DURATION_PREFERENCES[`duration`]) { + DURATION_PREFERENCES[`duration`] = DURATION_PREFERENCES[`duration`] * (60 ** 2) * 1000; + }; - // Update the last time. - return(await global.write([`settings`,`sync`,`last`], Date.now(), -1)); - }; + // When the browser is started, run the updater immediately only when the filters are not updated yet. + (updater_check() || !DURATION_PREFERENCES) + ? updater_run() + : false; - // Set the interval. - let updater_set = () => { - this.update[`checker`] = setInterval(async () => { - // Update the filters. - updater_run(); - }, DURATION_PREFERENCES[`duration`]); - }; - - /* - Reset the interval. - */ - const updater_reset = () => { - // Cancel the interval. - (this.update[`checker`]) ? clearInterval(this.update[`checker`]) : false; - - // Run the updater, if necessary. - (updater_check()) - ? updater_run() - : false; - - // Start the new interval. - updater_set(); - } - - const updater_background = () => { - this.update[`background`] = async () => { - if ((await global.read([`settings`, `sync`, `duration`])) ? (await global.read([`settings`, `sync`, `duration`] * (60 ** 2) * 1000 != DURATION_PREFERENCES[`duration`])) : false) { - if (await global.global.read([`settings`, `sync`, `duration`])) { - // Get the new time. - DURATION_PREFERENCES[`duration`] = await global.global.read([`settings`, `sync`, `duration`]) * (60 ** 2) * 1000; - - // Reset the updater. - updater_reset(); - } - }; - }; - - // Set the background checker. - new background(() => {return(this.update.background())}); - } - - // Convert DURATION_PREFERENCES[`duration`]) from hrs to milliseconds. - DURATION_PREFERENCES[`duration`] = DURATION_PREFERENCES[`duration`] * (60 ** 2) * 1000; - - // Set the filter management. - let filter = new FilterManager(); - - // When the browser is started, run the updater immediately only when the filters are not updated yet. - (updater_check()) - ? updater_run() - : false; - - // Run the background. - updater_background(); - } - }); + // Run the background. + updater_background(); }) } }; diff --git a/src/scripts/background/importer.js b/src/scripts/background/importer.js index b372509..475fd7b 100644 --- a/src/scripts/background/importer.js +++ b/src/scripts/background/importer.js @@ -6,6 +6,8 @@ This script provides installation run scripts. // File importation import {template, global} from "../secretariat.js"; import pointer from "../data/pointer.js"; +import {URLs} from "../utils/URLs.js"; +import net from "../utils/net.js"; // The URL for the configuration file const config = chrome.runtime.getURL("config/config.json"); @@ -41,21 +43,58 @@ export default class BackgroundImporter { .then(async (jsonData) => { let configuration = jsonData; - // Run the storage initialization. - delete configuration[`OOBE`]; - template.set(configuration); + if ((configuration) ? Object.keys(configuration).length : false) { + // Run the storage initialization. + delete configuration[`OOBE`]; + + // Replace local URLs of filters to corresponding chrome extension pages. + const checkURL = async () => { + if (((typeof configuration[`settings`][`filters`]).includes(`obj`) && configuration[`settings`][`filters`]) ? Object.keys(configuration[`settings`][`filters`]).length : false) { + let FILTERS = {}; + FILTERS[`current`] = configuration[`settings`][`filters`]; + FILTERS[`updated`] = {}; + + for (let FILTER_NUMBER = 0; FILTER_NUMBER < Object.keys(FILTERS[`current`]).length; FILTER_NUMBER++) { + let SOURCE = Object.keys(FILTERS[`current`])[FILTER_NUMBER]; + + // Check if the URL is invalid. + if (!(URLs.test(SOURCE))) { + // Set the URL. + let ORIGIN = {"raw": SOURCE}; + + // If it is, it's most likely located within the extension. + ORIGIN[`local`] = chrome.runtime.getURL(`config/filters/`.concat(ORIGIN[`raw`])); + + // Attempt to verify the existence of the file. + if (await net.download(ORIGIN[`local`], `json`, true)) { + FILTERS[`updated`][ORIGIN[`local`]] = FILTERS[`current`][ORIGIN[`raw`]]; + }; + } else { + FILTERS[`updated`][SOURCE] = FILTERS[`current`][SOURCE]; + }; + }; + configuration[`settings`][`filters`] = FILTERS[`updated`]; + return(FILTERS[`updated`]); + }; + }; + await checkURL(); + + // Set the template. + template.set(configuration); + await global.write([`ready`], true, -1); + }; }) .catch((error) => { console.error(error); }); - } - + }; + trigger() { chrome.runtime.onInstalled.addListener((details) => { (details.reason == chrome.runtime.OnInstalledReason.INSTALL) ? this.hello() : null; this.setup(); }); - } + }; // main function constructor () { diff --git a/src/scripts/filters.js b/src/scripts/filters.js index 2ed9bfb..451cee8 100644 --- a/src/scripts/filters.js +++ b/src/scripts/filters.js @@ -71,43 +71,47 @@ export default class FilterManager { if (((typeof (FILTERS_ALL)).includes(`obj`) && !Array.isArray(FILTERS_ALL) && FILTERS_ALL) ? Object.keys(FILTERS_ALL).length > 0 : false) { for (let FILTER_URL_INDEX = 0; FILTER_URL_INDEX < Object.keys(FILTERS_ALL).length; FILTER_URL_INDEX++) { let FILTER_URL = (Object.keys(FILTERS_ALL, 1))[FILTER_URL_INDEX]; - if (FILTER_URL.includes(`://`)) { + + // Test the URL. + if (URLs.test(FILTER_URL)) { filters.enqueue(FILTER_URL); } } } - } + }; if (!filters.isEmpty()) { + // Inform the user of download state. + new logging (texts.localized(`settings_filters_update_status`)); + while (!filters.isEmpty()) { let filter_URL = filters.dequeue(); - // Inform the user of download state. - new logging (texts.localized(`settings_filters_update_status`), filter_URL); + try { + let DOWNLOAD = await net.download(filter_URL, `JSON`, false, true); + + // Only work when the filter is valid. + if (DOWNLOAD) { + // Write the filter to storage. + if (!(await global.write(["filters", filter_URL], DOWNLOAD, -1, {"silent": true, "strict": true}))) { + throw ReferenceError; + }; - // Create promise of downloading. - let filter_download = net.download(filter_URL, `JSON`, false, true); - filter_download - .then(async function (result) { - // Only work when the filter is valid. - if (result) { - // Write the filter to storage. - await global.write(["filters", filter_URL], result, -1, {"silent": true}); - - // Add the filter to the sync list. - if ((await global.read(["settings", `filters`])) ? !((Object.keys(await global.read(["settings", `filters`]))).includes(filter_URL)) : true) { - global.write(["settings", `filters`, filter_URL], true, 1, {"silent": true}); - }; - - // Notify that the update is completed. - new logging(texts.localized(`settings_filters_update_status_complete`),filter_URL); - } - }) - .catch((error) => { - // Inform the user of the download failure. - logging.error(error.name, texts.localized(`settings_filters_update_status_failure`, null, [error.name, filter_URL]), error.stack); - }); - } + // Add the filter to the sync list. + if (((await global.read(["settings", `filters`])) ? !((Object.keys(await global.read(["settings", `filters`]))).includes(filter_URL)) : true) + ? (!(await global.write(["settings", `filters`, filter_URL], true, 1, {"silent": true}))) + : false) { + throw ReferenceError; + }; + }; + } catch (error) { + // Inform the user of the download failure. + logging.error(error.name, texts.localized(`settings_filters_update_status_failure`, null, [error.name, filter_URL]), error.stack); + }; + }; + + // Notify that the update is completed. + new logging(texts.localized(`settings_filters_update_status_complete`)); } else { // Inform the user of the download being unnecessary. logging.warn(texts.localized(`settings_filters_update_stop`)); diff --git a/src/scripts/secretariat.js b/src/scripts/secretariat.js index c322cd1..fc2691a 100644 --- a/src/scripts/secretariat.js +++ b/src/scripts/secretariat.js @@ -94,7 +94,7 @@ class global { static async write(path, data, CLOUD = -1, OPTIONS = {}) { let DATA_INJECTED = {}; - async function verify (NAME, DATA) { + async function verify (NAME, DATA, OPTIONS) { let DATA_CHECK = {}; // Verify the presence of the data. @@ -117,11 +117,24 @@ class global { }; // Get all data and set a blank value if it doesn't exist yet. - DATA_ALL = await global.read(null, CLOUD); - DATA_ALL = ((DATA_ALL != null && DATA_ALL != undefined && (typeof DATA_ALL).includes(`obj`)) ? Object.keys(DATA_ALL).length <= 0 : true) + if (CLOUD == 0 || CLOUD == null) { + const ORIGINS = {}; + ORIGINS[-1] = `local`; + ORIGINS[1] = `global`; + + for (let SOURCE = -1; SOURCE != 0 && SOURCE < 2; SOURCE = SOURCE + 2) { + DATA_ALL[ORIGINS[SOURCE]] = await global.read(null, CLOUD); + }; + + CLOUD = (DATA_ALL[`local`] != null) ? -1 : 1; + } else { + DATA_ALL = await global.read(null, CLOUD); + }; + + DATA_ALL = ((!(typeof DATA_ALL).includes(`undef`)) ? ((DATA_ALL != null && (typeof DATA_ALL).includes(`obj`)) ? Object.keys(DATA_ALL).length <= 0 : true) : false) ? {} : DATA_ALL; - + // Set the data name. let DATA_NAME = (!(Array.isArray(path)) && path && path != undefined) ? String(path).trim().split(",") @@ -130,15 +143,14 @@ class global { // Merge! DATA_INJECTED = nested.dictionary.set(DATA_ALL, (DATA_NAME != null) ? [...DATA_NAME] : DATA_NAME, data, OPTIONS); - // If cloud is not selected, get where the data is already existent. - (CLOUD == 0 || CLOUD == null) - ? (CLOUD = (DATA_ALL[`local`] != null) ? -1 : 1) - : false; - // Write! - chrome.storage[(CLOUD > 0) ? `sync` : `local`].set(DATA_INJECTED); - GUI_INFO[`log`] ? GUI_INFO[`log`].clear() : false; - return ((OPTIONS[`verify`] != null ? (OPTIONS[`verify`]) : true) ? verify(DATA_NAME, data) : true); + return(chrome.storage[(CLOUD > 0) ? `sync` : `local`].set(DATA_INJECTED).then(async () => { + GUI_INFO[`log`] ? GUI_INFO[`log`].clear() : false; + return (((OPTIONS[`verify`] != null ? (OPTIONS[`verify`]) : true) ? await verify(DATA_NAME, data, OPTIONS) : true)); + }).catch((err) => { + logging.error((new texts(`error_msg_save_failed`)).localized, DATA_NAME.join(` → `), JSON.stringify(data)) + return (false); + })); } /* @@ -257,7 +269,6 @@ export async function compare(PATH, DATA) { return (RESULT); } - let COMPARISON = {}; COMPARISON[`test`] = (PATH) ? DATA : DATA[1]; COMPARISON[`against`] = (PATH) ? (await global.read((Array.isArray(PATH)) ? [...PATH] : PATH)) : DATA[0]; @@ -285,8 +296,7 @@ class template { }) }); - // Merge the data. - // Managed > Synchronized > Imported > Local + // Merge the data, such that Managed > Synchronized > Imported > Local. // Set managed preferences. managed.reinforce(); @@ -310,16 +320,15 @@ class template { ? global.write(PREFERENCE[`name`], PREFERENCES[`all`][`build`][PREFERENCE[`name`]], -1) : false; }); - } + }; + }; /* Use our preferences when handling the data. */ static configure() { - chrome.storage.session.setAccessLevel( - {accessLevel: 'TRUSTED_AND_UNTRUSTED_CONTEXTS'} - ); + chrome.storage.session.setAccessLevel({accessLevel: 'TRUSTED_AND_UNTRUSTED_CONTEXTS'}); } }