uBlock/src/js/storage.js

783 lines
25 KiB
JavaScript
Raw Normal View History

2014-06-24 00:42:43 +02:00
/*******************************************************************************
µBlock - a Chromium browser extension to block requests.
2015-02-13 18:10:10 +01:00
Copyright (C) 2014-2015 Raymond Hill
2014-06-24 00:42:43 +02:00
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/
2015-02-24 00:31:29 +01:00
/* global YaMD5, µBlock, vAPI, punycode, publicSuffixList */
'use strict';
2014-06-24 00:42:43 +02:00
/******************************************************************************/
µBlock.getBytesInUse = function() {
var getBytesInUseHandler = function(bytesInUse) {
µBlock.storageUsed = bytesInUse;
};
vAPI.storage.getBytesInUse(null, getBytesInUseHandler);
2014-06-24 00:42:43 +02:00
};
/******************************************************************************/
2014-10-07 14:59:35 +02:00
µBlock.saveLocalSettings = function(callback) {
if ( typeof callback !== 'function' ) {
callback = this.noopFunc;
}
if ( this.localSettingsModifyTime <= this.localSettingsSaveTime ) {
callback();
return;
}
this.localSettingsSaveTime = Date.now();
vAPI.storage.set(this.localSettings, callback);
2014-06-24 00:42:43 +02:00
};
/******************************************************************************/
// Save local settings regularly. Not critical.
µBlock.asyncJobs.add(
'autoSaveLocalSettings',
null,
µBlock.saveLocalSettings.bind(µBlock),
2015-02-24 19:48:03 +01:00
4 * 60 * 1000,
2014-06-24 00:42:43 +02:00
true
);
/******************************************************************************/
µBlock.saveUserSettings = function() {
vAPI.storage.set(this.userSettings);
2014-06-24 00:42:43 +02:00
};
/******************************************************************************/
µBlock.savePermanentFirewallRules = function() {
this.userSettings.dynamicFilteringString = this.permanentFirewall.toString();
this.XAL.keyvalSetOne('dynamicFilteringString', this.userSettings.dynamicFilteringString);
};
/******************************************************************************/
µBlock.saveWhitelist = function() {
var bin = {
'netWhitelist': this.stringFromWhitelist(this.netWhitelist)
};
vAPI.storage.set(bin);
this.netWhitelistModifyTime = Date.now();
};
/******************************************************************************/
2014-07-13 02:32:44 +02:00
µBlock.saveUserFilters = function(content, callback) {
return this.assets.put(this.userFiltersPath, content, callback);
};
/******************************************************************************/
µBlock.loadUserFilters = function(callback) {
return this.assets.get(this.userFiltersPath, callback);
};
/******************************************************************************/
µBlock.appendUserFilters = function(content) {
2015-02-24 00:31:29 +01:00
if ( content.length === 0 ) {
return;
}
2014-09-08 23:46:58 +02:00
var µb = this;
2015-02-24 00:31:29 +01:00
var onCompiledListLoaded = function(details) {
var snfe = µb.staticNetFilteringEngine;
var cfe = µb.cosmeticFilteringEngine;
var acceptedCount = snfe.acceptedCount + cfe.acceptedCount;
var duplicateCount = snfe.duplicateCount + cfe.duplicateCount;
µb.applyCompiledFilters(details.content);
var entry = µb.remoteBlacklists[µb.userFiltersPath];
entry.entryCount = snfe.acceptedCount + cfe.acceptedCount - acceptedCount;
entry.entryUsedCount = entry.entryCount - snfe.duplicateCount - cfe.duplicateCount + duplicateCount;
µb.staticNetFilteringEngine.freeze();
µb.cosmeticFilteringEngine.freeze();
};
2014-07-13 02:32:44 +02:00
var onSaved = function(details) {
if ( details.error ) {
return;
}
2015-02-24 00:31:29 +01:00
µb.getCompiledFilterList(µb.userFiltersPath, onCompiledListLoaded);
2014-07-13 02:32:44 +02:00
};
2014-09-08 23:46:58 +02:00
2014-07-13 02:32:44 +02:00
var onLoaded = function(details) {
if ( details.error ) {
return;
}
2014-07-13 18:57:20 +02:00
if ( details.content.indexOf(content.trim()) !== -1 ) {
2014-07-13 02:32:44 +02:00
return;
}
2015-03-06 06:36:45 +01:00
µb.saveUserFilters(details.content.trim() + '\n\n' + content.trim(), onSaved);
2014-07-13 02:32:44 +02:00
};
2014-09-08 23:46:58 +02:00
2015-02-24 00:31:29 +01:00
this.loadUserFilters(onLoaded);
2014-07-13 02:32:44 +02:00
};
/******************************************************************************/
2014-07-25 22:12:20 +02:00
µBlock.getAvailableLists = function(callback) {
var availableLists = {};
var relocationMap = {};
2014-06-24 00:42:43 +02:00
2015-02-25 22:51:04 +01:00
var fixLocation = function(location) {
// https://github.com/gorhill/uBlock/issues/418
// We now support built-in external filter lists
if ( /^https?:/.test(location) === false ) {
location = 'assets/thirdparties/' + location;
}
return location;
};
2014-07-25 22:12:20 +02:00
// selected lists
var onSelectedListsLoaded = function(store) {
var µb = µBlock;
2014-07-25 22:12:20 +02:00
var lists = store.remoteBlacklists;
var locations = Object.keys(lists);
var location, availableEntry, storedEntry;
2014-07-25 22:12:20 +02:00
while ( location = locations.pop() ) {
storedEntry = lists[location];
// New location?
if ( relocationMap.hasOwnProperty(location) ) {
µb.purgeFilterList(location);
location = relocationMap[location];
}
availableEntry = availableLists[location];
if ( availableEntry === undefined ) {
µb.purgeFilterList(location);
2014-07-25 22:12:20 +02:00
continue;
}
availableEntry.off = storedEntry.off || false;
µb.assets.setHomeURL(location, availableEntry.homeURL);
if ( storedEntry.entryCount !== undefined ) {
availableEntry.entryCount = storedEntry.entryCount;
}
if ( storedEntry.entryUsedCount !== undefined ) {
availableEntry.entryUsedCount = storedEntry.entryUsedCount;
2014-07-25 22:12:20 +02:00
}
// This may happen if the list name was pulled from the list content
if ( availableEntry.title === '' && storedEntry.title !== '' ) {
availableEntry.title = storedEntry.title;
}
2014-06-24 00:42:43 +02:00
}
2014-07-25 22:12:20 +02:00
callback(availableLists);
2014-06-24 00:42:43 +02:00
};
2014-07-25 22:12:20 +02:00
// built-in lists
var onBuiltinListsLoaded = function(details) {
var location, locations;
try {
locations = JSON.parse(details.content);
} catch (e) {
locations = {};
}
var entry;
2014-07-25 22:12:20 +02:00
for ( location in locations ) {
if ( locations.hasOwnProperty(location) === false ) {
continue;
}
entry = locations[location];
2015-02-25 22:51:04 +01:00
location = fixLocation(location);
// Migrate obsolete location to new location, if any
if ( typeof entry.oldLocation === 'string' ) {
2015-02-25 22:51:04 +01:00
entry.oldLocation = fixLocation(entry.oldLocation);
relocationMap[entry.oldLocation] = location;
}
availableLists[location] = entry;
2014-06-24 00:42:43 +02:00
}
2014-07-25 22:12:20 +02:00
// Now get user's selection of lists
vAPI.storage.get(
2014-07-25 22:12:20 +02:00
{ 'remoteBlacklists': availableLists },
onSelectedListsLoaded
2014-06-24 00:42:43 +02:00
);
};
2014-07-25 22:12:20 +02:00
// permanent lists
var location;
var lists = this.permanentLists;
for ( location in lists ) {
if ( lists.hasOwnProperty(location) === false ) {
continue;
}
availableLists[location] = lists[location];
}
// custom lists
var c;
var locations = this.userSettings.externalLists.split('\n');
for ( var i = 0; i < locations.length; i++ ) {
location = locations[i].trim();
c = location.charAt(0);
if ( location === '' || c === '!' || c === '#' ) {
continue;
}
// Coarse validation
if ( /[^0-9A-Za-z!*'();:@&=+$,\/?%#\[\]_.~-]/.test(location) ) {
continue;
}
availableLists[location] = {
title: '',
group: 'custom',
external: true
};
}
// get built-in block lists.
this.assets.get('assets/ublock/filter-lists.json', onBuiltinListsLoaded);
};
/******************************************************************************/
2015-02-24 00:31:29 +01:00
µBlock.createShortUniqueId = function(path) {
var md5 = YaMD5.hashStr(path);
return md5.slice(0, 4) + md5.slice(-4);
};
µBlock.createShortUniqueId.idLength = 8;
/******************************************************************************/
2014-09-08 23:46:58 +02:00
µBlock.loadFilterLists = function(callback) {
2015-02-24 00:31:29 +01:00
//quickProfiler.start('µBlock.loadFilterLists()');
2014-07-25 22:12:20 +02:00
var µb = this;
2015-02-24 00:31:29 +01:00
var filterlistsCount = 0;
2014-07-25 22:12:20 +02:00
2014-09-08 23:46:58 +02:00
if ( typeof callback !== 'function' ) {
callback = this.noopFunc;
}
2015-02-24 00:31:29 +01:00
var onDone = function() {
µb.staticNetFilteringEngine.freeze();
2014-09-08 23:46:58 +02:00
µb.cosmeticFilteringEngine.freeze();
vAPI.storage.set({ 'remoteBlacklists': µb.remoteBlacklists });
2015-02-24 19:48:03 +01:00
//quickProfiler.stop(0);
2015-02-24 00:31:29 +01:00
vAPI.messaging.broadcast({ what: 'allFilterListsReloaded' });
2014-09-08 23:46:58 +02:00
callback();
2015-02-24 00:31:29 +01:00
µb.toSelfieAsync();
2014-07-25 22:12:20 +02:00
};
2015-02-24 00:31:29 +01:00
var applyCompiledFilters = function(path, compiled) {
var snfe = µb.staticNetFilteringEngine;
var cfe = µb.cosmeticFilteringEngine;
var acceptedCount = snfe.acceptedCount + cfe.acceptedCount;
var duplicateCount = snfe.duplicateCount + cfe.duplicateCount;
µb.applyCompiledFilters(compiled);
if ( µb.remoteBlacklists.hasOwnProperty(path) ) {
var entry = µb.remoteBlacklists[path];
entry.entryCount = snfe.acceptedCount + cfe.acceptedCount - acceptedCount;
2015-03-02 17:01:21 +01:00
entry.entryUsedCount = entry.entryCount - (snfe.duplicateCount + cfe.duplicateCount - duplicateCount);
2014-06-24 00:42:43 +02:00
}
};
2015-02-24 00:31:29 +01:00
var onCompiledListLoaded = function(details) {
applyCompiledFilters(details.path, details.content);
filterlistsCount -= 1;
if ( filterlistsCount === 0 ) {
onDone();
}
};
var onFilterListsReady = function(lists) {
2014-07-25 22:12:20 +02:00
µb.remoteBlacklists = lists;
2015-02-24 00:31:29 +01:00
2014-09-08 23:46:58 +02:00
µb.cosmeticFilteringEngine.reset();
2015-02-24 00:31:29 +01:00
µb.staticNetFilteringEngine.reset();
2014-09-08 23:46:58 +02:00
µb.destroySelfie();
2014-06-24 00:42:43 +02:00
2015-02-24 00:31:29 +01:00
// We need to build a complete list of assets to pull first: this is
// because it *may* happens that some load operations are synchronous:
// This happens for assets which do not exist, ot assets with no
// content.
var toLoad = [];
for ( var path in lists ) {
if ( lists.hasOwnProperty(path) === false ) {
2014-06-24 00:42:43 +02:00
continue;
}
2015-02-24 00:31:29 +01:00
if ( lists[path].off ) {
continue;
}
toLoad.push(path);
2015-02-06 07:20:04 +01:00
}
2015-02-24 00:31:29 +01:00
filterlistsCount = toLoad.length;
if ( filterlistsCount === 0 ) {
onDone();
return;
}
var i = toLoad.length;
while ( i-- ) {
µb.getCompiledFilterList(toLoad[i], onCompiledListLoaded);
2014-06-24 00:42:43 +02:00
}
};
2015-02-24 00:31:29 +01:00
this.getAvailableLists(onFilterListsReady);
2014-06-24 00:42:43 +02:00
};
/******************************************************************************/
2015-02-24 00:31:29 +01:00
µBlock.getCompiledFilterListPath = function(path) {
return 'cache://compiled-filter-list:' + this.createShortUniqueId(path);
};
/******************************************************************************/
2014-06-24 00:42:43 +02:00
2015-02-24 00:31:29 +01:00
µBlock.getCompiledFilterList = function(path, callback) {
var compiledPath = this.getCompiledFilterListPath(path);
var µb = this;
2014-06-24 00:42:43 +02:00
2015-02-24 00:31:29 +01:00
var onRawListLoaded = function(details) {
if ( details.content !== '' ) {
2015-02-25 00:29:58 +01:00
var listMeta = µb.remoteBlacklists[path];
if ( listMeta && listMeta.title === '' ) {
var matches = details.content.slice(0, 1024).match(/(?:^|\n)!\s*Title:([^\n]+)/i);
if ( matches !== null ) {
listMeta.title = matches[1].trim();
}
}
2015-02-24 00:31:29 +01:00
//console.debug('µBlock.getCompiledFilterList/onRawListLoaded: compiling "%s"', path);
details.content = µb.compileFilters(details.content);
µb.assets.put(compiledPath, details.content);
}
callback(details);
};
2014-09-25 21:44:18 +02:00
2015-02-24 00:31:29 +01:00
var onCompiledListLoaded = function(details) {
if ( details.content === '' ) {
//console.debug('µBlock.getCompiledFilterList/onCompiledListLoaded: no compiled version for "%s"', path);
µb.assets.get(path, onRawListLoaded);
return;
}
//console.debug('µBlock.getCompiledFilterList/onCompiledListLoaded: using compiled version for "%s"', path);
details.path = path;
callback(details);
};
2014-09-25 21:44:18 +02:00
2015-02-24 00:31:29 +01:00
this.assets.get(compiledPath, onCompiledListLoaded);
};
2015-02-24 00:31:29 +01:00
/******************************************************************************/
2015-02-24 00:31:29 +01:00
µBlock.purgeCompiledFilterList = function(path) {
this.assets.purge(this.getCompiledFilterListPath(path));
2014-09-25 21:44:18 +02:00
};
/******************************************************************************/
µBlock.purgeFilterList = function(path) {
this.purgeCompiledFilterList(path);
this.assets.purge(path);
};
/******************************************************************************/
2014-09-25 21:44:18 +02:00
2015-02-24 00:31:29 +01:00
µBlock.compileFilters = function(rawText) {
2014-09-25 21:44:18 +02:00
var rawEnd = rawText.length;
2015-02-24 00:31:29 +01:00
var compiledFilters = [];
2014-06-24 00:42:43 +02:00
// Useful references:
// https://adblockplus.org/en/filter-cheatsheet
// https://adblockplus.org/en/filters
var staticNetFilteringEngine = this.staticNetFilteringEngine;
2014-09-08 23:46:58 +02:00
var cosmeticFilteringEngine = this.cosmeticFilteringEngine;
2015-01-23 17:32:49 +01:00
var reIsWhitespaceChar = /\s/;
var reMaybeLocalIp = /^[\d:f]/;
var reIsLocalhostRedirect = /\s+(?:broadcasthost|local|localhost|localhost\.localdomain)(?=\s|$)/;
var reLocalIp = /^(?:0\.0\.0\.0|127\.0\.0\.1|::1|fe80::1%lo0)/;
2015-02-24 00:31:29 +01:00
2014-06-24 00:42:43 +02:00
var lineBeg = 0, lineEnd, currentLineBeg;
2015-01-23 17:32:49 +01:00
var line, lineRaw, c, pos;
2014-06-24 00:42:43 +02:00
while ( lineBeg < rawEnd ) {
lineEnd = rawText.indexOf('\n', lineBeg);
2014-09-25 21:44:18 +02:00
if ( lineEnd === -1 ) {
2014-06-24 00:42:43 +02:00
lineEnd = rawText.indexOf('\r', lineBeg);
2014-09-25 21:44:18 +02:00
if ( lineEnd === -1 ) {
2014-06-24 00:42:43 +02:00
lineEnd = rawEnd;
}
}
// rhill 2014-04-18: The trim is important here, as without it there
// could be a lingering `\r` which would cause problems in the
// following parsing code.
2015-01-23 17:32:49 +01:00
line = lineRaw = rawText.slice(lineBeg, lineEnd).trim();
2014-06-24 00:42:43 +02:00
currentLineBeg = lineBeg;
lineBeg = lineEnd + 1;
2015-01-23 17:32:49 +01:00
if ( line.length === 0 ) {
continue;
}
2014-06-24 00:42:43 +02:00
// Strip comments
c = line.charAt(0);
if ( c === '!' || c === '[' ) {
continue;
}
2014-09-25 21:44:18 +02:00
// Parse or skip cosmetic filters
2015-01-23 17:32:49 +01:00
// All cosmetic filters are caught here
2015-02-24 00:31:29 +01:00
if ( cosmeticFilteringEngine.compile(line, compiledFilters) ) {
2014-09-25 21:44:18 +02:00
continue;
2014-06-24 00:42:43 +02:00
}
2015-01-23 17:32:49 +01:00
// Whatever else is next can be assumed to not be a cosmetic filter
// Most comments start in first column
2014-06-24 00:42:43 +02:00
if ( c === '#' ) {
continue;
}
2015-01-23 17:32:49 +01:00
// Catch comments somewhere on the line
// Remove:
// ... #blah blah blah
// ... # blah blah blah
// Don't remove:
// ...#blah blah blah
// because some ABP filters uses the `#` character (URL fragment)
pos = line.indexOf('#');
if ( pos !== -1 && reIsWhitespaceChar.test(line.charAt(pos - 1)) ) {
line = line.slice(0, pos).trim();
}
2014-06-24 00:42:43 +02:00
// https://github.com/gorhill/httpswitchboard/issues/15
// Ensure localhost et al. don't end up in the ubiquitous blacklist.
2015-01-23 17:32:49 +01:00
// With hosts files, we need to remove local IP redirection
if ( reMaybeLocalIp.test(c) ) {
// Ignore hosts file redirect configuration
// 127.0.0.1 localhost
// 255.255.255.255 broadcasthost
if ( reIsLocalhostRedirect.test(line) ) {
continue;
}
line = line.replace(reLocalIp, '').trim();
}
if ( line.length === 0 ) {
continue;
}
2014-06-24 00:42:43 +02:00
2015-02-24 00:31:29 +01:00
//staticNetFilteringEngine.add(line);
staticNetFilteringEngine.compile(line, compiledFilters);
}
return compiledFilters.join('\n');
};
2014-06-24 00:42:43 +02:00
2015-02-24 00:31:29 +01:00
/******************************************************************************/
2014-06-24 00:42:43 +02:00
2015-02-24 00:31:29 +01:00
µBlock.applyCompiledFilters = function(rawText) {
var skipCosmetic = !this.userSettings.parseAllABPHideFilters;
var staticNetFilteringEngine = this.staticNetFilteringEngine;
var cosmeticFilteringEngine = this.cosmeticFilteringEngine;
var lineBeg = 0;
var rawEnd = rawText.length;
while ( lineBeg < rawEnd ) {
lineBeg = cosmeticFilteringEngine.fromCompiledContent(rawText, lineBeg, skipCosmetic);
lineBeg = staticNetFilteringEngine.fromCompiledContent(rawText, lineBeg);
2014-06-24 00:42:43 +02:00
}
};
/******************************************************************************/
2015-02-24 00:31:29 +01:00
// `switches` contains the filter lists for which the switch must be revisited.
2014-06-24 00:42:43 +02:00
2015-02-24 00:31:29 +01:00
µBlock.reloadFilterLists = function(switches, update) {
var µb = this;
2014-09-15 20:28:07 +02:00
var onFilterListsReady = function() {
µb.loadUpdatableAssets({ update: update, psl: update });
};
2014-06-24 00:42:43 +02:00
2015-02-24 00:31:29 +01:00
var onPurgeDone = function() {
// Toggle switches, if any
if ( switches === undefined ) {
onFilterListsReady();
return;
}
var filterLists = µb.remoteBlacklists;
2014-06-24 00:42:43 +02:00
var i = switches.length;
while ( i-- ) {
2014-09-15 20:28:07 +02:00
if ( filterLists.hasOwnProperty(switches[i].location) === false ) {
2014-06-24 00:42:43 +02:00
continue;
}
2014-09-15 20:28:07 +02:00
filterLists[switches[i].location].off = !!switches[i].off;
2014-06-24 00:42:43 +02:00
}
// Save switch states
vAPI.storage.set({ 'remoteBlacklists': filterLists }, onFilterListsReady);
2015-02-24 00:31:29 +01:00
};
// If we must update, we need to purge the compiled versions of
// obsolete assets.
if ( update !== true ) {
onPurgeDone();
return;
2014-06-24 00:42:43 +02:00
}
2015-02-24 00:31:29 +01:00
var onMetadataReady = function(metadata) {
var filterLists = µb.remoteBlacklists;
var entry;
// Purge obsolete filter lists
for ( var path in filterLists ) {
if ( filterLists.hasOwnProperty(path) === false ) {
continue;
}
if ( metadata.hasOwnProperty(path) === false ) {
continue;
}
entry = metadata[path];
if ( entry.repoObsolete !== true && entry.cacheObsolete !== true ) {
continue;
}
µb.purgeCompiledFilterList(path);
}
// Purge obsolete PSL
if ( metadata.hasOwnProperty(µb.pslPath) === false ) {
entry = metadata[µb.pslPath];
if ( entry.repoObsolete === true ) {
µb.assets.purge('cache://compiled-publicsuffixlist');
}
}
onPurgeDone();
};
this.assets.metadata(onMetadataReady);
2014-06-24 00:42:43 +02:00
};
/******************************************************************************/
µBlock.loadPublicSuffixList = function(callback) {
2015-02-24 00:31:29 +01:00
var µb = this;
var path = µb.pslPath;
var compiledPath = 'cache://compiled-publicsuffixlist';
2014-09-08 23:46:58 +02:00
if ( typeof callback !== 'function' ) {
callback = this.noopFunc;
}
2015-02-24 00:31:29 +01:00
var onRawListLoaded = function(details) {
if ( details.content !== '' ) {
//console.debug('µBlock.loadPublicSuffixList/onRawListLoaded: compiling "%s"', path);
2014-06-24 00:42:43 +02:00
publicSuffixList.parse(details.content, punycode.toASCII);
2015-02-24 00:31:29 +01:00
µb.assets.put(compiledPath, JSON.stringify(publicSuffixList.toSelfie()));
}
callback();
};
var onCompiledListLoaded = function(details) {
if ( details.content === '' ) {
//console.debug('µBlock.loadPublicSuffixList/onCompiledListLoaded: no compiled version for "%s"', path);
µb.assets.get(path, onRawListLoaded);
return;
2014-06-24 00:42:43 +02:00
}
2015-02-24 00:31:29 +01:00
//console.debug('µBlock.loadPublicSuffixList/onCompiledListLoaded: using compiled version for "%s"', path);
publicSuffixList.fromSelfie(JSON.parse(details.content));
2014-09-08 23:46:58 +02:00
callback();
2014-06-24 00:42:43 +02:00
};
2015-02-24 00:31:29 +01:00
this.assets.get(compiledPath, onCompiledListLoaded);
2014-06-24 00:42:43 +02:00
};
/******************************************************************************/
// Load updatable assets
2014-09-08 23:46:58 +02:00
µBlock.loadUpdatableAssets = function(details) {
var µb = this;
details = details || {};
var update = details.update !== false;
2014-08-21 04:34:22 +02:00
this.assets.autoUpdate = update || this.userSettings.autoUpdate;
this.assets.autoUpdateDelay = this.updateAssetsEvery;
2014-08-21 01:39:49 +02:00
2014-09-08 23:46:58 +02:00
var onFiltersReady = function() {
if ( update ) {
2015-02-13 18:10:10 +01:00
µb.assetUpdater.restart();
2014-09-08 23:46:58 +02:00
}
};
var onPSLReady = function() {
µb.loadFilterLists(onFiltersReady);
};
if ( details.psl !== false ) {
this.loadPublicSuffixList(onPSLReady);
} else {
this.loadFilterLists(onFiltersReady);
2014-08-21 01:39:49 +02:00
}
2014-06-24 00:42:43 +02:00
};
/******************************************************************************/
2014-09-08 23:46:58 +02:00
µBlock.toSelfie = function() {
var selfie = {
2015-02-24 00:31:29 +01:00
magic: this.systemSettings.selfieMagic,
2014-09-08 23:46:58 +02:00
publicSuffixList: publicSuffixList.toSelfie(),
filterLists: this.remoteBlacklists,
staticNetFilteringEngine: this.staticNetFilteringEngine.toSelfie(),
2014-09-11 22:00:50 +02:00
cosmeticFilteringEngine: this.cosmeticFilteringEngine.toSelfie()
2014-09-08 23:46:58 +02:00
};
vAPI.storage.set({ selfie: selfie });
2015-02-15 13:16:31 +01:00
//console.debug('storage.js > µBlock.toSelfie()');
2014-09-08 23:46:58 +02:00
};
// This is to be sure the selfie is generated in a sane manner: the selfie will
// be generated if the user doesn't change his filter lists selection for
2014-09-08 23:46:58 +02:00
// some set time.
2014-09-25 21:44:18 +02:00
2014-09-08 23:46:58 +02:00
µBlock.toSelfieAsync = function(after) {
if ( typeof after !== 'number' ) {
after = this.selfieAfter;
}
this.asyncJobs.add(
'toSelfie',
null,
this.toSelfie.bind(this),
after,
false
);
};
/******************************************************************************/
µBlock.destroySelfie = function() {
vAPI.storage.remove('selfie');
2015-02-13 18:10:10 +01:00
this.asyncJobs.remove('toSelfie');
2015-02-24 00:31:29 +01:00
//console.debug('µBlock.destroySelfie()');
2014-09-08 23:46:58 +02:00
};
/******************************************************************************/
2015-02-13 18:10:10 +01:00
µBlock.updateStartHandler = function() {
var µb = this;
2015-02-13 18:10:10 +01:00
var onListsReady = function(lists) {
for ( var location in lists ) {
if ( lists.hasOwnProperty(location) === false ) {
continue;
}
if ( lists[location].off ) {
continue;
}
µb.assetUpdater.add(location);
}
2014-09-08 23:46:58 +02:00
};
2015-02-13 18:10:10 +01:00
this.getAvailableLists(onListsReady);
this.assetUpdater.add(this.pslPath);
this.assetUpdater.add('assets/ublock/mirror-candidates.txt');
};
2014-09-08 23:46:58 +02:00
2015-02-13 18:10:10 +01:00
/******************************************************************************/
2015-01-24 18:06:22 +01:00
2015-02-24 00:31:29 +01:00
µBlock.assetUpdatedHandler = function(details) {
var path = details.path || '';
if ( this.remoteBlacklists.hasOwnProperty(path) === false ) {
return;
}
var entry = this.remoteBlacklists[path];
if ( entry.off ) {
return;
}
// Compile the list while we have the raw version in memory
//console.debug('µBlock.getCompiledFilterList/onRawListLoaded: compiling "%s"', path);
this.assets.put(
this.getCompiledFilterListPath(path),
this.compileFilters(details.content)
);
};
/******************************************************************************/
2015-02-13 18:10:10 +01:00
µBlock.updateCompleteHandler = function(details) {
var µb = this;
var updatedCount = details.updatedCount;
2015-02-13 18:10:10 +01:00
// Assets are supposed to have been all updated, avoid fetching from
// remote servers.
µb.assets.allowRemoteFetch = false;
2014-09-08 23:46:58 +02:00
var onFiltersReady = function() {
2015-02-13 18:10:10 +01:00
µb.assets.allowRemoteFetch = true;
2014-09-08 23:46:58 +02:00
};
var onPSLReady = function() {
2015-02-13 18:10:10 +01:00
if ( updatedCount !== 0 ) {
2015-02-15 13:16:31 +01:00
//console.debug('storage.js > µBlock.updateCompleteHandler: reloading filter lists');
2015-02-13 18:10:10 +01:00
µb.loadFilterLists(onFiltersReady);
} else {
2014-12-15 20:37:09 +01:00
onFiltersReady();
2014-09-08 23:46:58 +02:00
}
};
2015-02-13 18:10:10 +01:00
if ( details.hasOwnProperty('assets/ublock/mirror-candidates.txt') ) {
/* TODO */
}
2014-09-08 23:46:58 +02:00
2015-02-13 18:10:10 +01:00
if ( details.hasOwnProperty(this.pslPath) ) {
2015-02-15 13:16:31 +01:00
//console.debug('storage.js > µBlock.updateCompleteHandler: reloading PSL');
2015-02-13 18:10:10 +01:00
this.loadPublicSuffixList(onPSLReady);
updatedCount -= 1;
} else {
onPSLReady();
}
2014-06-24 00:42:43 +02:00
};
2015-02-24 00:31:29 +01:00
/******************************************************************************/
µBlock.assetCacheRemovedHandler = (function() {
var barrier = false;
var handler = function(paths) {
if ( barrier ) {
return;
}
barrier = true;
var i = paths.length;
var path;
while ( i-- ) {
path = paths[i];
if ( this.remoteBlacklists.hasOwnProperty(path) ) {
//console.debug('µBlock.assetCacheRemovedHandler: decompiling "%s"', path);
this.purgeCompiledFilterList(path);
continue;
}
if ( path === this.pslPath ) {
//console.debug('µBlock.assetCacheRemovedHandler: decompiling "%s"', path);
this.assets.purge('cache://compiled-publicsuffixlist');
continue;
}
}
this.destroySelfie();
barrier = false;
};
return handler;
})();