work on auto-update, backup/restore/reset

pull/2/head
gorhill 10 years ago
parent b94047f9f7
commit a39bd536b5

@ -5,49 +5,6 @@
<title>µMatrix — About</title> <title>µMatrix — About</title>
<link rel="stylesheet" type="text/css" href="css/common.css"> <link rel="stylesheet" type="text/css" href="css/common.css">
<link rel="stylesheet" type="text/css" href="css/dashboard-common.css"> <link rel="stylesheet" type="text/css" href="css/dashboard-common.css">
<style>
table th {
text-align: left;
}
table td:first-child {
padding-right: 2em;
}
#allLocalAssetsUpdated {
margin-left: 1em;
color: green;
}
#assetList table tr.unchanged {
color: gray;
}
#assetList table tr td:nth-of-type(2) {
font-weight: bold;
white-space: nowrap;
}
#assetList table tr.unchanged td:nth-of-type(2) {
font-weight: normal;
}
#assetList.ooo > table {
display: none;
}
#assetList.oox > table,
#assetList.oxx > table,
#assetList.xxx > table {
display: block;
}
#assetList > p {
display: none;
}
#assetList.ooo > p.ooo {
display: block;
}
#assetList.oxx > p.oxx {
display: block;
}
#assetList.xxx > p.xxx {
display: block;
}
</style>
</head> </head>
<body> <body>
@ -64,13 +21,20 @@ table td:first-child {
<h2 data-i18n="aboutUserDataHeader"></h2> <h2 data-i18n="aboutUserDataHeader"></h2>
<div> <div>
<p><button type="button" id="backupUserDataButton" data-i18n="aboutUserDataBackupButton"></button> <p><button type="button" id="backupUserDataButton" data-i18n="aboutBackupButton"></button>
<button type="button" id="restoreUserDataButton" data-i18n="aboutUserDataRestoreButton"></button> <button type="button" id="restoreUserDataButton" data-i18n="aboutRestoreButton"></button>
<input id="restoreFilePicker" type="file" accept="text/plain" style="display:none;"> <input id="restoreFilePicker" type="file" accept="text/plain" style="display:none;">
<p style="margin-left: 2em;" data-i18n="aboutUserDataOr"> <p style="margin-left: 2em;" data-i18n="aboutOr">
<p><button type="button" id="resetUserDataButton" data-i18n="aboutUserDataResetButton"></button> <p><button type="button" id="resetUserDataButton" data-i18n="aboutResetButton"></button>
</div> </div>
<span style="display: none;" data-i18n="aboutStorageUsed"></span>
<span style="display: none;" data-i18n="aboutBackupFilename"></span>
<span style="display: none;" data-i18n="aboutRestoreConfirm"></span>
<span style="display: none;" data-i18n="aboutRestoreError"></span>
<span style="display: none;" data-i18n="aboutResetConfirm"></span>
<script src="js/udom.js"></script> <script src="js/udom.js"></script>
<script src="js/i18n.js"></script> <script src="js/i18n.js"></script>
<script src="js/dashboard-common.js"></script> <script src="js/dashboard-common.js"></script>

@ -17,6 +17,7 @@
<script src="js/matrix.js"></script> <script src="js/matrix.js"></script>
<script src="js/utils.js"></script> <script src="js/utils.js"></script>
<script src="js/assets.js"></script> <script src="js/assets.js"></script>
<script src="js/updater.js"></script>
<script src="js/httpsb.js"></script> <script src="js/httpsb.js"></script>
<script src="js/reqstats.js"></script> <script src="js/reqstats.js"></script>
<script src="js/cookies.js"></script> <script src="js/cookies.js"></script>

@ -156,8 +156,8 @@ tr.unused {
</div> </div>
<div id="requests-log" style="overflow-y:hidden"> <div id="requests-log" style="overflow-y:hidden">
<table id="requestsTable"> <table id="requestsTable">
<tr class="ro"><td>when<td>what<td><td class="fa">&#xf0b0;<td>where</tr> <tr class="ro"><td>when<td>what<td><td>where</tr>
<tr class="ro" id="requestRowTemplate"><td><td><td><a href="" style="display:none">&lt;a&gt;</a><td class="fa"><td></tr> <tr class="ro" id="requestRowTemplate"><td><td><td><a href="" style="display:none">&lt;a&gt;</a><td></tr>
</table> </table>
</div> </div>
</div> </div>

@ -19,7 +19,7 @@
Home: https://github.com/gorhill/uMatrix Home: https://github.com/gorhill/uMatrix
*/ */
/* global chrome, uDom */ /* global chrome, messaging, uDom */
/******************************************************************************/ /******************************************************************************/
@ -28,115 +28,54 @@ uDom.onLoad(function() {
/******************************************************************************/ /******************************************************************************/
var backupUserDataToFile = function() { var backupUserDataToFile = function() {
var allUserData = { var userDataReady = function(userData) {
timeStamp: Date.now(),
version: '',
userSettings: {},
scopes: '',
remoteBlacklists: {},
ubiquitousBlacklist: '',
ubiquitousWhitelist: ''
};
var userWhitelistReady = function(details) {
allUserData.ubiquitousWhitelist = details.content;
chrome.downloads.download({ chrome.downloads.download({
'url': 'data:text/plain,' + encodeURIComponent(JSON.stringify(allUserData)), 'url': 'data:text/plain,' + encodeURIComponent(JSON.stringify(userData)),
'filename': 'umatrix-alluserdata-backup.txt', 'filename': uDom('[data-i18n="aboutBackupFilename"]').text(),
'saveAs': true 'saveAs': true
}); });
}; };
var userBlacklistReady = function(details) { messaging.ask({ what: 'getAllUserData' }, userDataReady);
allUserData.ubiquitousBlacklist = details.content;
messaging.ask({ what: 'readUserUbiquitousAllowRules' }, userWhitelistReady);
};
var ruleDataReady = function(store) {
allUserData.version = store.version;
allUserData.scopes = store.scopes;
allUserData.remoteBlacklists = store.remoteBlacklists;
messaging.ask({ what: 'readUserUbiquitousBlockRules' }, userBlacklistReady);
};
var userSettingsReady = function(store) {
allUserData.userSettings = store;
chrome.storage.local.get(['version', 'scopes', 'remoteBlacklists'], ruleDataReady);
};
messaging.ask({ what: 'readUserSettings' }, userSettingsReady);
}; };
/******************************************************************************/ /******************************************************************************/
function restoreUserDataFromFile() { function restoreUserDataFromFile() {
var restartCountdown = 4;
var doCountdown = function() {
restartCountdown -= 1;
if ( restartCountdown > 0 ) {
return;
}
chrome.runtime.reload();
};
var restoreBackup = function(data) {
chrome.storage.local.set(data.userSettings, doCountdown);
var store = {
'version': data.version,
'scopes': data.scopes
};
// This case may happen if data was backed up without the user having
// changed default selection of lists.
if ( data.remoteBlacklists !== undefined ) {
store.remoteBlacklists = data.remoteBlacklists;
}
chrome.storage.local.set(store, doCountdown);
messaging.ask({
what: 'writeUserUbiquitousBlockRules',
content: data.ubiquitousBlacklist
},
doCountdown
);
messaging.ask({
what: 'writeUserUbiquitousAllowRules',
content: data.ubiquitousWhitelist
},
doCountdown
);
};
var validateBackup = function(s) { var validateBackup = function(s) {
var data; var userData = null;
try { try {
data = JSON.parse(s); userData = JSON.parse(s);
} }
catch (e) { catch (e) {
data = undefined; userData = null;
}
if ( userData === null ) {
return null;
} }
if ( typeof data !== 'object' || if ( typeof userData !== 'object' ||
typeof data.timeStamp !== 'number' || typeof userData.version !== 'string' ||
typeof data.version !== 'string' || typeof userData.when !== 'number' ||
typeof data.userSettings !== 'object' || typeof userData.settings !== 'object' ||
typeof data.scopes !== 'string' || typeof userData.rules !== 'string' ||
typeof data.ubiquitousBlacklist !== 'string' || typeof userData.hostsFiles !== 'object' ) {
typeof data.ubiquitousWhitelist !== 'string' ) { return null;
alert('File content is not valid backed up data.');
} }
return data; return userData;
}; };
var fileReaderOnLoadHandler = function() { var fileReaderOnLoadHandler = function() {
var data = validateBackup(this.result); var userData = validateBackup(this.result);
if ( !data ) { if ( !userData ) {
window.alert(uDom('[data-i18n="aboutRestoreError"]').text());
return; return;
} }
var time = new Date(data.timeStamp); var time = new Date(userData.when);
var msg = chrome.i18n var msg = uDom('[data-i18n="aboutRestoreConfirm"]').text()
.getMessage('aboutUserDataRestoreConfirm')
.replace('{{time}}', time.toLocaleString()); .replace('{{time}}', time.toLocaleString());
var proceed = window.confirm(msg); var proceed = window.confirm(msg);
if ( proceed ) { if ( proceed ) {
restoreBackup(data); messaging.tell({ what: 'restoreAllUserData', userData: userData });
} }
}; };
@ -166,28 +105,25 @@ var startRestoreFilePicker = function() {
/******************************************************************************/ /******************************************************************************/
var resetUserData = function() { var resetUserData = function() {
messaging.tell({ var proceed = window.confirm(uDom('[data-i18n="aboutResetConfirm"]').text());
what: 'gotoExtensionURL', if ( proceed ) {
url: 'setup.html' messaging.tell({ what: 'resetAllUserData' });
}); }
}; };
/******************************************************************************/ /******************************************************************************/
messaging.start('about.js');
/******************************************************************************/
(function() { (function() {
uDom('#aboutVersion').html(chrome.runtime.getManifest().version);
var renderStats = function(details) { var renderStats = function(details) {
var template = chrome.i18n.getMessage('aboutStorageUsed'); uDom('#aboutVersion').html(details.version);
var percent = 0; var template = uDom('[data-i18n="aboutStorageUsed"]').text();
if ( details.storageQuota ) { var storageUsed = '?';
percent = (details.storageUsed / details.storageQuota * 100).toFixed(1); if ( typeof details.storageUsed === 'number' ) {
storageUsed = details.storageUsed.toLocaleString();
} }
uDom('#aboutStorageUsed').html(template.replace('{{storageUsed}}', percent)); uDom('#aboutStorageUsed').html(template.replace('{{storageUsed}}', storageUsed));
}; };
messaging.start('about.js');
messaging.ask({ what: 'getSomeStats' }, renderStats); messaging.ask({ what: 'getSomeStats' }, renderStats);
})(); })();

@ -1,224 +0,0 @@
/*******************************************************************************
µMatrix - a Chromium browser extension to black/white list requests.
Copyright (C) 2013 Raymond Hill
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/uMatrix
*/
/* global chrome, µMatrix */
/******************************************************************************/
// Asset update manager
µMatrix.assetUpdater = (function() {
/******************************************************************************/
var getUpdateList = function(callback) {
var localChecksumsText = '';
var remoteChecksumsText = '';
var compareChecksums = function() {
var parseChecksumsText = function(text) {
var result = {};
var lines = text.split(/\n+/);
var i = lines.length;
var fields;
while ( i-- ) {
fields = lines[i].trim().split(/\s+/);
if ( fields.length !== 2 ) {
continue;
}
result[fields[1]] = fields[0];
}
return result;
};
if ( remoteChecksumsText === 'Error' || localChecksumsText === 'Error' ) {
remoteChecksumsText = localChecksumsText = '';
}
var localAssetChecksums = parseChecksumsText(localChecksumsText);
var remoteAssetChecksums = parseChecksumsText(remoteChecksumsText);
var toUpdate = {};
var path;
for ( path in remoteAssetChecksums ) {
if ( !remoteAssetChecksums.hasOwnProperty(path) ) {
continue;
}
if ( localAssetChecksums[path] === undefined ) {
toUpdate[path] = {
status: 'Added',
remoteChecksum: remoteAssetChecksums[path],
localChecksum: ''
};
continue;
}
if ( localAssetChecksums[path] === remoteAssetChecksums[path] ) {
toUpdate[path] = {
status: 'Unchanged',
remoteChecksum: remoteAssetChecksums[path],
localChecksum: localAssetChecksums[path]
};
continue;
}
toUpdate[path] = {
status: 'Changed',
remoteChecksum: remoteAssetChecksums[path],
localChecksum: localAssetChecksums[path]
};
}
for ( path in localAssetChecksums ) {
if ( !localAssetChecksums.hasOwnProperty(path) ) {
continue;
}
if ( remoteAssetChecksums[path] === undefined ) {
toUpdate[path] = {
status: 'Removed',
remoteChecksum: '',
localChecksum: localAssetChecksums[path]
};
}
}
callback({ 'list': toUpdate });
};
var validateChecksums = function(details) {
if ( details.error || details.content === '' ) {
return 'Error';
}
if ( /^(?:[0-9a-f]{32}\s+\S+(\s+|$))+/.test(details.content) ) {
return details.content;
}
return 'Error';
};
var onLocalChecksumsLoaded = function(details) {
localChecksumsText = validateChecksums(details);
if ( remoteChecksumsText !== '' ) {
compareChecksums();
}
};
var onRemoteChecksumsLoaded = function(details) {
remoteChecksumsText = validateChecksums(details);
if ( localChecksumsText !== '' ) {
compareChecksums();
}
};
µMatrix.assets.getRemote('assets/checksums.txt', onRemoteChecksumsLoaded);
µMatrix.assets.get('assets/checksums.txt', onLocalChecksumsLoaded);
};
/******************************************************************************/
// If `list` is null, it will be fetched internally.
var update = function(list, callback) {
var assetChangedCount = 0;
var assetProcessedCount;
var updatedAssetChecksums = [];
var onCompleted = function() {
var details = {
what: 'allLocalAssetsUpdated',
changedCount: assetChangedCount
};
callback(details);
µMatrix.messaging.announce(details);
};
var doCountdown = function() {
assetProcessedCount -= 1;
if ( assetProcessedCount > 0 ) {
return;
}
µMatrix.assets.put(
'assets/checksums.txt',
updatedAssetChecksums.join('\n'),
onCompleted
);
chrome.storage.local.set({ 'assetsUpdateTimestamp': Date.now() });
};
var assetUpdated = function(details) {
var path = details.path;
var entry = list[path];
if ( details.error ) {
updatedAssetChecksums.push(entry.localChecksum + ' ' + path);
} else {
updatedAssetChecksums.push(entry.remoteChecksum + ' ' + path);
assetChangedCount += 1;
}
doCountdown();
};
var processList = function() {
assetProcessedCount = Object.keys(list).length;
if ( assetProcessedCount === 0 ) {
onCompleted();
return;
}
var entry;
var details = { path: '', md5: '' };
for ( var path in list ) {
if ( list.hasOwnProperty(path) === false ) {
continue;
}
entry = list[path];
if ( entry.status === 'Added' || entry.status === 'Changed' ) {
details.path = path;
details.md5 = entry.remoteChecksum;
µMatrix.assets.update(details, assetUpdated);
continue;
}
if ( entry.status === 'Unchanged' ) {
updatedAssetChecksums.push(entry.localChecksum + ' ' + path);
}
doCountdown();
}
};
var listLoaded = function(details) {
list = details.list;
processList();
};
if ( list ) {
processList();
} else {
getUpdateList(listLoaded);
}
};
/******************************************************************************/
// Export API
return {
'getList': getUpdateList,
'update': update
};
/******************************************************************************/
})();
/******************************************************************************/

@ -27,6 +27,13 @@ var µMatrix = (function() {
/******************************************************************************/ /******************************************************************************/
var oneSecond = 1000;
var oneMinute = 60 * oneSecond;
var oneHour = 60 * oneMinute;
var oneDay = 24 * oneHour;
/******************************************************************************/
var defaultUserAgentStrings = [ var defaultUserAgentStrings = [
'# http://www.useragentstring.com/pages/Chrome/', '# http://www.useragentstring.com/pages/Chrome/',
'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36', 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36',
@ -40,6 +47,7 @@ var getDefaultUserAgentStrings = function() {
return defaultUserAgentStrings.join('\n'); return defaultUserAgentStrings.join('\n');
}; };
/******************************************************************************/
return { return {
manifest: chrome.runtime.getManifest(), manifest: chrome.runtime.getManifest(),
@ -73,7 +81,9 @@ return {
}, },
clearBrowserCacheCycle: 0, clearBrowserCacheCycle: 0,
updateAssetsEvery: 5 * 24 * 60 * 60 * 1000, updateAssetsEvery: 11 * oneDay + 1 * oneHour + 1 * oneMinute + 1 * oneSecond,
firstUpdateAfter: 11 * oneMinute,
nextUpdateAfter: 11 * oneHour,
projectServerRoot: 'https://raw.githubusercontent.com/gorhill/umatrix/master/', projectServerRoot: 'https://raw.githubusercontent.com/gorhill/umatrix/master/',
// permanent hosts files // permanent hosts files

@ -162,23 +162,23 @@ var renderBlacklists = function() {
hasCachedContent = false; hasCachedContent = false;
// Visually split the filter lists in two groups: built-in and external // Visually split the filter lists in two groups: built-in and external
var html = []; var htmlBuiltin = [];
var htmlExternal = [];
var hostsPaths = Object.keys(details.available); var hostsPaths = Object.keys(details.available);
var hostsEntry; var hostsPath, hostsEntry;
for ( i = 0; i < hostsPaths.length; i++ ) { for ( var i = 0; i < hostsPaths.length; i++ ) {
hostsPath = hostsPaths[i];
hostsEntry = details.available[hostsPath];
if ( !hostsEntry.external ) {
html.push(htmlFromLeaf(hostsPath, hostsEntry));
}
}
for ( i = 0; i < hostsPaths.length; i++ ) {
hostsPath = hostsPaths[i]; hostsPath = hostsPaths[i];
hostsEntry = details.available[hostsPath]; hostsEntry = details.available[hostsPath];
if ( hostsEntry.external ) { if ( hostsEntry.external ) {
html.push(htmlFromLeaf(hostsPath, hostsEntry)); htmlExternal.push(htmlFromLeaf(hostsPath, hostsEntry));
} else {
htmlBuiltin.push(htmlFromLeaf(hostsPath, hostsEntry));
}
} }
if ( htmlExternal.length !== 0 ) {
htmlBuiltin.push('<li>&nbsp;');
} }
var html = htmlBuiltin.concat(htmlExternal);
uDom('#listsOfBlockedHostsPrompt').text( uDom('#listsOfBlockedHostsPrompt').text(
chrome.i18n.getMessage('hostsFilesStats') chrome.i18n.getMessage('hostsFilesStats')

@ -231,12 +231,8 @@ function renderRequestRow(row, request) {
a.css('display', 'none'); a.css('display', 'none');
} }
// reason of why block, if available
$(cells[3]).text('\u00a0');
$(cells[3]).removeAttr('data-tip');
// request URL // request URL
$(cells[4]).text(request.url); $(cells[3]).text(request.url);
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/

@ -630,14 +630,45 @@ var onMessage = function(request, sender, callback) {
(function() { (function() {
var onMessage = function(request, sender, callback) { var µm = µMatrix;
var µm = µMatrix;
/******************************************************************************/
var restoreUserData = function(userData) {
var countdown = 3;
var onCountdown = function() {
countdown -= 1;
if ( countdown === 0 ) {
µm.XAL.restart();
}
};
var onAllRemoved = function() {
// Be sure to adjust `countdown` if adding/removing anything below
µm.XAL.keyvalSetMany(userData.settings, onCountdown);
µm.XAL.keyvalSetOne('userMatrix', userData.rules, onCountdown);
µm.XAL.keyvalSetOne('liveHostsFiles', userData.hostsFiles, onCountdown);
};
// If we are going to restore all, might as well wipe out clean local
// storage
µm.XAL.keyvalRemoveAll(onAllRemoved);
};
/******************************************************************************/
var resetUserData = function() {
var onAllRemoved = function() {
µm.XAL.restart();
};
µm.XAL.keyvalRemoveAll(onAllRemoved);
};
/******************************************************************************/
var onMessage = function(request, sender, callback) {
// Async // Async
switch ( request.what ) { switch ( request.what ) {
case 'readUserSettings':
return chrome.storage.local.get(µm.userSettings, callback);
default: default:
break; break;
} }
@ -646,13 +677,33 @@ var onMessage = function(request, sender, callback) {
var response; var response;
switch ( request.what ) { switch ( request.what ) {
case 'getAllUserData':
response = {
app: 'µMatrix',
version: µm.manifest.version,
when: Date.now(),
settings: µm.userSettings,
rules: µm.pMatrix.toString(),
hostsFiles: µm.liveHostsFiles
};
break;
case 'getSomeStats': case 'getSomeStats':
response = { response = {
version: µm.manifest.version,
storageQuota: µm.storageQuota, storageQuota: µm.storageQuota,
storageUsed: µm.storageUsed storageUsed: µm.storageUsed
}; };
break; break;
case 'restoreAllUserData':
restoreUserData(request.userData);
break;
case 'resetAllUserData':
resetUserData();
break;
default: default:
return µm.messaging.defaultHandler(request, sender, callback); return µm.messaging.defaultHandler(request, sender, callback);
} }
@ -662,6 +713,8 @@ var onMessage = function(request, sender, callback) {
µMatrix.messaging.listen('about.js', onMessage); µMatrix.messaging.listen('about.js', onMessage);
/******************************************************************************/
})(); })();
/******************************************************************************/ /******************************************************************************/

@ -166,7 +166,7 @@ function defaultHandler(request, sender, callback) {
break; break;
case 'reloadHostsFiles': case 'reloadHostsFiles':
µm.reloadHostsFiles(request.switches); µm.reloadHostsFiles(request.switches, request.update);
break; break;
case 'userSettings': case 'userSettings':

@ -20,6 +20,7 @@
*/ */
/* global chrome, µMatrix */ /* global chrome, µMatrix */
/* jshint bitwise: false */
/******************************************************************************* /*******************************************************************************
@ -156,7 +157,6 @@ var LogEntry = function() {
this.type = ''; this.type = '';
this.when = 0; this.when = 0;
this.block = false; this.block = false;
this.reason = '';
}; };
var logEntryJunkyard = []; var logEntryJunkyard = [];
@ -300,7 +300,7 @@ PageRequestStats.prototype.typeFromRequestKey = typeFromRequestKey;
/******************************************************************************/ /******************************************************************************/
PageRequestStats.prototype.createEntryIfNotExists = function(url, type, block) { PageRequestStats.prototype.createEntryIfNotExists = function(url, type) {
var reqKey = makeRequestKey(url, type); var reqKey = makeRequestKey(url, type);
if ( this.requests[reqKey] ) { if ( this.requests[reqKey] ) {
return false; return false;
@ -347,7 +347,7 @@ PageRequestStats.prototype.resizeLogBuffer = function(size) {
/******************************************************************************/ /******************************************************************************/
PageRequestStats.prototype.logRequest = function(url, type, block, reason) { PageRequestStats.prototype.logRequest = function(url, type, block) {
var buffer = this.ringBuffer; var buffer = this.ringBuffer;
var len = buffer.length; var len = buffer.length;
if ( !len ) { if ( !len ) {
@ -362,7 +362,6 @@ PageRequestStats.prototype.logRequest = function(url, type, block, reason) {
logEntry.type = type; logEntry.type = type;
logEntry.when = Date.now(); logEntry.when = Date.now();
logEntry.block = block; logEntry.block = block;
logEntry.reason = reason;
this.ringBufferPointer = ((pointer + 1) % len) | 0; this.ringBufferPointer = ((pointer + 1) % len) | 0;
}; };
@ -495,10 +494,7 @@ PageStore.prototype.dispose = function() {
/******************************************************************************/ /******************************************************************************/
// rhill 2014-03-11: If `block` !== false, then block.toString() may return PageStore.prototype.recordRequest = function(type, url, block) {
// user legible information about the reason for the block.
PageStore.prototype.recordRequest = function(type, url, block, reason) {
// TODO: this makes no sense, I forgot why I put this here. // TODO: this makes no sense, I forgot why I put this here.
if ( !this ) { if ( !this ) {
// console.error('HTTP Switchboard> PageStore.recordRequest(): no pageStats'); // console.error('HTTP Switchboard> PageStore.recordRequest(): no pageStats');
@ -523,7 +519,7 @@ PageStore.prototype.recordRequest = function(type, url, block, reason) {
this.perLoadAllowedRequestCount++; this.perLoadAllowedRequestCount++;
} }
this.requests.logRequest(url, type, block, reason); this.requests.logRequest(url, type, block);
if ( !this.requests.createEntryIfNotExists(url, type, block) ) { if ( !this.requests.createEntryIfNotExists(url, type, block) ) {
return; return;
@ -544,7 +540,7 @@ PageStore.prototype.recordRequest = function(type, url, block, reason) {
// rhill 2014-03-12: disregard blocking operations which do not originate // rhill 2014-03-12: disregard blocking operations which do not originate
// from matrix evaluation, or else this can cause a useless reload of the // from matrix evaluation, or else this can cause a useless reload of the
// page if something important was blocked through ABP filtering. // page if something important was blocked through ABP filtering.
if ( block !== false && reason === undefined ) { if ( block !== false ) {
this.state[type + '|' + hostname] = true; this.state[type + '|' + hostname] = true;
} }

@ -24,8 +24,9 @@
/******************************************************************************/ /******************************************************************************/
µMatrix.getBytesInUse = function() { µMatrix.getBytesInUse = function() {
var µm = this;
var getBytesInUseHandler = function(bytesInUse) { var getBytesInUseHandler = function(bytesInUse) {
µMatrix.storageUsed = bytesInUse; µm.storageUsed = bytesInUse;
}; };
chrome.storage.local.getBytesInUse(null, getBytesInUseHandler); chrome.storage.local.getBytesInUse(null, getBytesInUseHandler);
}; };
@ -33,14 +34,21 @@
/******************************************************************************/ /******************************************************************************/
µMatrix.saveUserSettings = function() { µMatrix.saveUserSettings = function() {
chrome.storage.local.set(this.userSettings, function() { chrome.storage.local.set(
µMatrix.getBytesInUse(); this.userSettings,
}); this.getBytesInUse.bind(this)
);
}; };
/******************************************************************************/ /******************************************************************************/
µMatrix.loadUserSettings = function() { µMatrix.loadUserSettings = function(callback) {
var µm = this;
if ( typeof callback !== 'function' ) {
callback = this.noopFunc;
}
var settingsLoaded = function(store) { var settingsLoaded = function(store) {
// console.log('storage.js > loaded user settings'); // console.log('storage.js > loaded user settings');
@ -51,19 +59,13 @@
} else if ( store.smartAutoReload === false ) { } else if ( store.smartAutoReload === false ) {
store.smartAutoReload = 'none'; store.smartAutoReload = 'none';
} }
// https://github.com/gorhill/httpswitchboard/issues/250
if ( typeof store.autoCreateSiteScope === 'boolean' ) {
store.autoCreateScope = store.autoCreateSiteScope ? 'site' : '';
delete store.autoCreateSiteScope;
}
// https://github.com/gorhill/httpswitchboard/issues/299
// No longer needed.
delete store.subframeFgColor;
µMatrix.userSettings = store; µm.userSettings = store;
// https://github.com/gorhill/httpswitchboard/issues/344 // https://github.com/gorhill/httpswitchboard/issues/344
µMatrix.userAgentSpoofer.shuffle(); µm.userAgentSpoofer.shuffle();
callback(µm.userSettings);
}; };
chrome.storage.local.get(this.userSettings, settingsLoaded); chrome.storage.local.get(this.userSettings, settingsLoaded);
@ -319,7 +321,7 @@
// `switches` contains the preset blacklists for which the switch must be // `switches` contains the preset blacklists for which the switch must be
// revisited. // revisited.
µMatrix.reloadHostsFiles = function(switches) { µMatrix.reloadHostsFiles = function(switches, update) {
var liveHostsFiles = this.liveHostsFiles; var liveHostsFiles = this.liveHostsFiles;
// Toggle switches // Toggle switches
@ -334,19 +336,22 @@
// Save switch states // Save switch states
chrome.storage.local.set( chrome.storage.local.set(
{ 'liveHostsFiles': liveHostsFiles }, { 'liveHostsFiles': liveHostsFiles },
this.loadHostsFiles.bind(this) this.loadUpdatableAssets.bind(this, update)
); );
}; };
/******************************************************************************/ /******************************************************************************/
µMatrix.loadPublicSuffixList = function() { µMatrix.loadPublicSuffixList = function(callback) {
if ( typeof callback !== 'function' ) {
callback = this.noopFunc;
}
var applyPublicSuffixList = function(details) { var applyPublicSuffixList = function(details) {
// TODO: Not getting proper suffix list is a bit serious, I think
// the extension should be force-restarted if it occurs..
if ( !details.error ) { if ( !details.error ) {
publicSuffixList.parse(details.content, punycode.toASCII); publicSuffixList.parse(details.content, punycode.toASCII);
} }
callback();
}; };
this.assets.get( this.assets.get(
'assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat', 'assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat',
@ -358,9 +363,14 @@
// Load updatable assets // Load updatable assets
µMatrix.loadUpdatableAssets = function() { µMatrix.loadUpdatableAssets = function(forceUpdate) {
this.loadHostsFiles(); this.assets.autoUpdate = forceUpdate === true;
this.assets.autoUpdateDelay = this.updateAssetsEvery;
if ( forceUpdate ) {
this.updater.restart();
}
this.loadPublicSuffixList(); this.loadPublicSuffixList();
this.loadHostsFiles();
}; };
/******************************************************************************/ /******************************************************************************/
@ -368,10 +378,20 @@
// Load all // Load all
µMatrix.load = function() { µMatrix.load = function() {
this.loadUserSettings(); var µm = this;
this.loadMatrix();
this.loadUpdatableAssets();
// User settings are in memory
var onUserSettingsReady = function(settings) {
// Never auto-update at boot time
µm.loadUpdatableAssets(false);
// Setup auto-updater, earlier if auto-upate is enabled, later if not
if ( settings.autoUpdate ) {
µm.updater.restart(µm.firstUpdateAfter);
}
};
this.loadUserSettings(onUserSettingsReady);
this.loadMatrix();
this.getBytesInUse(); this.getBytesInUse();
}; };

@ -288,7 +288,6 @@ var processRequest = function(µm, details) {
// Block request? // Block request?
var block = µm.mustBlock(µm.scopeFromURL(pageURL), requestHostname, requestType); var block = µm.mustBlock(µm.scopeFromURL(pageURL), requestHostname, requestType);
var reason;
// Record request. // Record request.
// https://github.com/gorhill/httpswitchboard/issues/342 // https://github.com/gorhill/httpswitchboard/issues/342
@ -296,7 +295,7 @@ var processRequest = function(µm, details) {
// processing has already been performed, and that a synthetic URL has // processing has already been performed, and that a synthetic URL has
// been constructed for logging purpose. Use this synthetic URL if // been constructed for logging purpose. Use this synthetic URL if
// it is available. // it is available.
pageStats.recordRequest(requestType, details.µmRequestURL || requestURL, block, false); pageStats.recordRequest(requestType, details.µmRequestURL || requestURL, block);
// whitelisted? // whitelisted?
if ( !block ) { if ( !block ) {
@ -883,7 +882,7 @@ chrome.webRequest.onBeforeRequest.addListener(
[ "blocking" ] [ "blocking" ]
); );
console.log('µMatrix > Beginning to intercept net requests at %s', (new Date()).toISOString()); //console.log('µMatrix > Beginning to intercept net requests at %s', (new Date()).toISOString());
chrome.webRequest.onBeforeSendHeaders.addListener( chrome.webRequest.onBeforeSendHeaders.addListener(
onBeforeSendHeadersHandler, onBeforeSendHeadersHandler,

@ -0,0 +1,105 @@
/*******************************************************************************
µMatrix - a Chromium browser extension to black/white list requests.
Copyright (C) 2014 Raymond Hill
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/uMatrix
*/
/* global µMatrix */
/******************************************************************************/
// Automatic update of non-user assets
// https://github.com/gorhill/httpswitchboard/issues/334
µMatrix.updater = (function() {
/******************************************************************************/
var µm = µMatrix;
var jobCallback = function() {
// Simpler to fire restart here, and safe given how far this will happen
// in the future.
restart();
// If auto-update is disabled, check again in a while.
if ( µm.userSettings.autoUpdate !== true ) {
return;
}
var onMetadataReady = function(metadata) {
// Check PSL
var mdEntry = metadata[µm.pslPath];
if ( mdEntry.repoObsolete ) {
µm.loadUpdatableAssets(true);
return;
}
// Check used hosts files
var hostsFiles = µm.liveHostsFiles;
for ( var path in hostsFiles ) {
if ( hostsFiles.hasOwnProperty(path) === false ) {
continue;
}
if ( hostsFiles[path].off ) {
continue;
}
if ( metadata.hasOwnProperty(path) === false ) {
continue;
}
mdEntry = metadata[path];
if ( mdEntry.cacheObsolete || mdEntry.repoObsolete ) {
µm.loadUpdatableAssets(true);
return;
}
}
// console.log('updater.js > all is up to date');
};
µm.assets.metadata(onMetadataReady);
};
// https://www.youtube.com/watch?v=cIrGQD84F1g
/******************************************************************************/
var restart = function(after) {
if ( after === undefined ) {
after = µm.nextUpdateAfter;
}
µm.asyncJobs.add(
'autoUpdateAssets',
null,
jobCallback,
after,
false
);
};
/******************************************************************************/
return {
restart: restart
};
/******************************************************************************/
})();
/******************************************************************************/

@ -483,143 +483,37 @@
"message": "Deine Daten", "message": "Deine Daten",
"description": "English: Your data" "description": "English: Your data"
}, },
"aboutUserDataBackupButton" : { "aboutBackupButton" : {
"message": "Backup in eine Datei...", "message": "Backup to file...",
"description": "English: Backup all..." "description": "English: Backup all..."
}, },
"aboutUserDataRestoreButton" : { "aboutBackupFilename" : {
"message": "Aus einer Datei wiederherstellen...", "message": "all-my-umatrix-data.txt",
"description": "English: Restore all..." "description": "all-my-umatrix-data.txt"
},
"aboutUserDataOr" : {
"message": "... oder ...",
"description": "English: ... or ..."
}, },
"aboutUserDataResetButton" : { "aboutRestoreButton" : {
"message": "Fange von ganz vorne an ...", "message": "Restore from file...",
"description": "English: Start from scratch..." "description": "English: Restore all..."
}, },
"aboutUserDataRestoreConfirm" : { "aboutRestoreConfirm" : {
"message": "Alle deine Einstellungen und Regeln werden überschrieben\nmit Daten gesichert am {{time}},\nund µMatrix wird neu starten.\n\nSollen alle existierenden Daten mit Backup-Daten überschrieben werden?", "message": "All your settings will be overwritten using data backed up on {{time}}, and µMatrix will restart.\n\nOverwrite all existing settings using backed up data?",
"description": "Message asking user to confirm restore" "description": "Message asking user to confirm restore"
}, },
"aboutExtensionDataHeader" : { "aboutRestoreError" : {
"message": "Externe Ressourcen dieser Erweiterung", "message": "The data could not be read or is invalid",
"description": "English: Extension data" "description": ""
},
"aboutAssetsUpdatePrompt" : {
"message": "Von <i>µMatrix</i> benutzte externe Ressourcen können hier upgedatet werden, ohne auf eine neue Version dieser Erweiterung warten zu müssen. Diese Ressourcen werden bezogen vom <a href=\"https://github.com/gorhill/httpswitchboard\">Github Repository dieses Projekts</a>.",
"description": "Short descriptive text of the update feature"
},
"aboutAssetsUpdateColPath" : {
"message": "Pfad",
"description": "Path column header"
},
"aboutAssetsUpdateColStatus" : {
"message": "Status",
"description": "Status column header"
},
"aboutAssetsUpdateGetListError" : {
"message": "Ein Fehler ist aufgetreten. Ist <b>XHR</b> blockiert für <b>raw2.github.com</b>?",
"description": "Successful outcome of clicking 'update' button"
},
"aboutAssetsUpdateStatusAdded" : {
"message": "Hinzufügen",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusChanged" : {
"message": "Neue Version verfügbar",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusUnchanged" : {
"message": "Up-to-date",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusRemoved" : {
"message": "Entfernen",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateButton" : {
"message": "Update",
"description": "Update button"
},
"aboutAssetsUpdatingButton" : {
"message": "Updating...",
"description": "Updating..."
},
"setupPagePrompt" : {
"message": "<p><b>µMatrix</b> ist hochgradig konfigurierbar: Die Einstellungen können fast beliebig gesetzt werden zwischen den beiden Extremen &ldquo;alles blockieren&rdquo; und &ldquo;nichts blockieren&rdquo;. <p>Je höher die Sicherheit, desto höher die Wahrscheinlichkeit, dass Webseiten &ldquo;nicht funktionieren&rdquo;, d.h. sie werden nicht gerendert und/oder verhalten sich nicht wie gewünscht. Daher bedeutet höhere Sicherheit auch mehr notwendige Interventionen durch den Benutzer, damit vertrauenswürdige Webseiten wieder &ldquo;funktionieren&rdquo;. <p>Hier kannst du ein Profil wählen, das am besten zu dem passt, wie du gedenkst, <b>µMatrix</b> zu benutzen. Bitte berücksichtige, dass diese Profile lediglich einen Startpunkt repräsentieren, den du später beliebig an deine Vorstellungen anpassen kannst .",
"description": "Appears at the top of the setup page"
},
"setupBlockAllAllowExceptionally" : {
"message": "Blockiere alles / erlaube ausnahmsweise",
"description": "English: Block all / allow exceptionally"
},
"setupAllowAllBlockExceptionally" : {
"message": "Erlaube alles / blockiere ausnahmsweise",
"description": "English: Allow all / block exceptionally"
},
"setupAdBlocker" : {
"message": "Benutzen als Werbeblocker",
"description": "English: Ad blocker-like"
},
"setupNoScript" : {
"message": "Verhalten wie NoScript",
"description": "English: NoScript-like"
},
"setupRequestPolicy" : {
"message": "Verhalten wie RequestPolicy",
"description": "English: RequestPolicy-like"
},
"setupBlockNothingReportAll" : {
"message": "Blockiere nichts / melde alles",
"description": "English: Block nothing / report everything"
},
"setupSecurity" : {
"message": "Sicherheit:",
"description": "English: Security:"
},
"setupBreakage" : {
"message": "Bruchgefahr:",
"description": "English: Breakage:"
},
"setupVeryHigh" : {
"message": "sehr hoch",
"description": "English: very high"
},
"setupHigh" : {
"message": "hoch",
"description": "English: high"
},
"setupMediumHigh" : {
"message": "mittel - hoch",
"description": "English: medium high"
},
"setupMedium" : {
"message": "mittel",
"description": "English: medium"
},
"setupMediumLow" : {
"message": "mittel - niedrig",
"description": "English: medium low"
},
"setupLow" : {
"message": "niedrig",
"description": "English: low"
}, },
"setupVeryLow" : { "aboutOr" : {
"message": "sehr niedrig", "message": "... or ...",
"description": "English: very low" "description": "English: ... or ..."
}, },
"setupNone" : { "aboutResetButton" : {
"message": "gar nicht", "message": "Reset to default settings",
"description": "English: none" "description": "English: Reset to default settings"
}, },
"setupRestoreConfirm" : { "aboutResetConfirm" : {
"message": "Alle deine Einstellungen und Regeln werden überschrieben\nund µMatrix wird neu starten.\n\nAlle existierenden Daten überschreiben?", "message": "Caution! this will also remove all your custom settings. Are you sure you want to proceed?",
"description": "English: All your settings and rules will be overwritten\nand µMatrix will restart.\n\nOverwrite all existing data?" "description": "Message asking user to confirm reset"
}, },

@ -460,12 +460,12 @@
"aboutChangelog" : { "aboutChangelog" : {
"message": "<a href='https://github.com/gorhill/httpswitchboard/wiki/Change-log'>Change log</a>", "message": "<a href='https://github.com/gorhill/uMatrix/releases'>Change log</a>",
"description": "English: <a href='https://github.com/gorhill/httpswitchboard/wiki/Change-log'>Change log</a>" "description": "English: <a href='https://github.com/gorhill/uMatrix/releases'>Change log</a>"
}, },
"aboutStorageUsed" : { "aboutStorageUsed" : {
"message": "Storage used: {{storageUsed}}%", "message": "Storage used: {{storageUsed}} bytes",
"description": "English: Storage used: {{storageUsed}}%" "description": "English: Storage used: {{storageUsed}} bytes"
}, },
"aboutDoc" : { "aboutDoc" : {
"message": "<a href='https://github.com/gorhill/httpswitchboard/wiki'>Documentation</a>", "message": "<a href='https://github.com/gorhill/httpswitchboard/wiki'>Documentation</a>",
@ -476,154 +476,48 @@
"description": "English: <a href='https://github.com/gorhill/httpswitchboard/wiki/Permissions'>Permissions</a>" "description": "English: <a href='https://github.com/gorhill/httpswitchboard/wiki/Permissions'>Permissions</a>"
}, },
"aboutCode" : { "aboutCode" : {
"message": "<a href='https://github.com/gorhill/httpswitchboard'>Source code (GPLv3)</a>", "message": "<a href='https://github.com/gorhill/uMatrix'>Source code (GPLv3)</a>",
"description": "English: <a href='https://github.com/gorhill/httpswitchboard'>Source code (GPLv3)</a>" "description": "English: <a href='https://github.com/gorhill/uMatrix'>Source code (GPLv3)</a>"
}, },
"aboutCredits" : { "aboutCredits" : {
"message": "<a href='https://github.com/gorhill/httpswitchboard/wiki/Credits'>Credits</a>", "message": "<a href='https://github.com/gorhill/uMatrix/wiki/Credits'>Credits</a>",
"description": "English: <a href='https://github.com/gorhill/httpswitchboard/wiki/Credits'>Credits</a>" "description": "English: <a href='https://github.com/gorhill/uMatrix/wiki/Credits'>Credits</a>"
}, },
"aboutUserDataHeader" : { "aboutUserDataHeader" : {
"message": "Your data", "message": "Your data",
"description": "English: Your data" "description": "English: Your data"
}, },
"aboutUserDataBackupButton" : { "aboutBackupButton" : {
"message": "Backup to file...", "message": "Backup to file...",
"description": "English: Backup all..." "description": "English: Backup all..."
}, },
"aboutUserDataRestoreButton" : { "aboutBackupFilename" : {
"message": "all-my-umatrix-data.txt",
"description": "all-my-umatrix-data.txt"
},
"aboutRestoreButton" : {
"message": "Restore from file...", "message": "Restore from file...",
"description": "English: Restore all..." "description": "English: Restore all..."
}, },
"aboutUserDataOr" : { "aboutRestoreConfirm" : {
"message": "... or ...", "message": "All your settings will be overwritten using data backed up on {{time}}, and µMatrix will restart.\n\nOverwrite all existing settings using backed up data?",
"description": "English: ... or ..."
},
"aboutUserDataResetButton" : {
"message": "Start from scratch...",
"description": "English: Start from scratch..."
},
"aboutUserDataRestoreConfirm" : {
"message": "All your settings and rules will be overwritten\nusing data backed up on {{time}},\nand µMatrix will restart.\n\nOverwrite all existing data using backed up data?",
"description": "Message asking user to confirm restore" "description": "Message asking user to confirm restore"
}, },
"aboutExtensionDataHeader" : { "aboutRestoreError" : {
"message": "Extension data", "message": "The data could not be read or is invalid",
"description": "English: Extension data" "description": ""
},
"aboutAssetsUpdatePrompt" : {
"message": "<i>µMatrix</i> assets can be updated here without having to wait for the next release of the extension. These assets are pulled from the <a href=\"https://github.com/gorhill/httpswitchboard\">project's Github repository</a>.",
"description": "Short descriptive text of the update feature"
},
"aboutAssetsUpdateColPath" : {
"message": "Path",
"description": "Path column header"
},
"aboutAssetsUpdateColStatus" : {
"message": "Status",
"description": "Status column header"
},
"aboutAssetsUpdateGetListError" : {
"message": "An error occurred. Is <b>XHR</b> blocked for <b>raw2.github.com</b>?",
"description": "Successful outcome of clicking 'update' button"
},
"aboutAssetsUpdateStatusAdded" : {
"message": "To add",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusChanged" : {
"message": "New version available",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusUnchanged" : {
"message": "Up to date",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusRemoved" : {
"message": "To remove",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateButton" : {
"message": "Update",
"description": "Update button"
},
"aboutAssetsUpdatingButton" : {
"message": "Updating...",
"description": "Updating..."
},
"setupPagePrompt" : {
"message": "<p><b>µMatrix</b> is highly configurable: it can be set anywhere between &ldquo;block everything&rdquo; and &ldquo;block nothing&rdquo;. <p>The higher the security, the more likely web pages will be &ldquo;broken&rdquo;, i.e. will not render and/or behave as intended. Thus, higher security also means more intervention required from the user in order to &ldquo;unbreak&rdquo; those web pages which a user trust. <p>Here you can pick a profile which best matches how you plan to use <b>µMatrix</b>. Consider these a starting point, as you can customize at will afterward.",
"description": "Appears at the top of the setup page"
},
"setupBlockAllAllowExceptionally" : {
"message": "Block all / allow exceptionally",
"description": "English: Block all / allow exceptionally"
},
"setupAllowAllBlockExceptionally" : {
"message": "Allow all / block exceptionally",
"description": "English: Allow all / block exceptionally"
},
"setupAdBlocker" : {
"message": "Ad blocker-like",
"description": "English: Ad blocker-like"
},
"setupNoScript" : {
"message": "NoScript-like",
"description": "English: NoScript-like"
},
"setupRequestPolicy" : {
"message": "RequestPolicy-like",
"description": "English: RequestPolicy-like"
},
"setupBlockNothingReportAll" : {
"message": "Block nothing / report everything",
"description": "English: Block nothing / report everything"
},
"setupSecurity" : {
"message": "Security:",
"description": "English: Security:"
},
"setupBreakage" : {
"message": "Breakage:",
"description": "English: Breakage:"
},
"setupVeryHigh" : {
"message": "very high",
"description": "English: very high"
},
"setupHigh" : {
"message": "high",
"description": "English: high"
},
"setupMediumHigh" : {
"message": "medium high",
"description": "English: medium high"
},
"setupMedium" : {
"message": "medium",
"description": "English: medium"
},
"setupMediumLow" : {
"message": "medium low",
"description": "English: medium low"
},
"setupLow" : {
"message": "low",
"description": "English: low"
}, },
"setupVeryLow" : { "aboutOr" : {
"message": "very low", "message": "... or ...",
"description": "English: very low" "description": "English: ... or ..."
}, },
"setupNone" : { "aboutResetButton" : {
"message": "none", "message": "Reset to default settings",
"description": "English: none" "description": "English: Reset to default settings"
}, },
"setupRestoreConfirm" : { "aboutResetConfirm" : {
"message": "All your settings and rules will be overwritten\nand µMatrix will restart.\n\nOverwrite all existing data?", "message": "Caution! this will also remove all your custom settings. Are you sure you want to proceed?",
"description": "English: All your settings and rules will be overwritten\nand µMatrix will restart.\n\nOverwrite all existing data?" "description": "Message asking user to confirm reset"
}, },

@ -483,143 +483,37 @@
"message": "Vos réglages", "message": "Vos réglages",
"description": "English: Your data" "description": "English: Your data"
}, },
"aboutUserDataBackupButton" : { "aboutBackupButton" : {
"message": "Exporter vers un fichier", "message": "Backup to file...",
"description": "English: Backup to file..." "description": "English: Backup all..."
}, },
"aboutUserDataRestoreButton" : { "aboutBackupFilename" : {
"message": "Importer depuis un fichier", "message": "all-my-umatrix-data.txt",
"description": "English: Restore from file..." "description": "all-my-umatrix-data.txt"
}, },
"aboutUserDataOr" : { "aboutRestoreButton" : {
"message": "Ou alors vous pouvez...", "message": "Restore from file...",
"description": "English: ... or ..." "description": "English: Restore all..."
},
"aboutUserDataResetButton" : {
"message": "Repartir à zéro",
"description": "English: Start from scratch..."
}, },
"aboutUserDataRestoreConfirm" : { "aboutRestoreConfirm" : {
"message": "Vos paramètres et vos règles seront remplacés\npar les données sauvegardées le {{time}},\n puis µMatrix redémarrera.\n\nProcéder à l'importation ?", "message": "All your settings will be overwritten using data backed up on {{time}}, and µMatrix will restart.\n\nOverwrite all existing settings using backed up data?",
"description": "Message asking user to confirm restore" "description": "Message asking user to confirm restore"
}, },
"aboutExtensionDataHeader" : { "aboutRestoreError" : {
"message": "Données de l'extension", "message": "The data could not be read or is invalid",
"description": "English: Extension data" "description": ""
},
"aboutAssetsUpdatePrompt" : {
"message": "Les éléments dynamiques, comprenant entre autres listes d'hôtes à bloquer et recettes prédéfinies, peuvent être mis à jour ici sans avoir à attendre la prochaine version de µMatrix. Le processus s'effectue à partir de la <a href=\"https://github.com/gorhill/httpswitchboard\">page du projet sur Github</a>.",
"description": "Short descriptive text of the update feature"
},
"aboutAssetsUpdateColPath" : {
"message": "Élément dynamique",
"description": "Path column header"
},
"aboutAssetsUpdateColStatus" : {
"message": "État",
"description": "Status column header"
},
"aboutAssetsUpdateGetListError" : {
"message": "Une erreur est survenue. Veuillez vous assurer que les requêtes de type <b>XHR</b> ne soient pas bloquées pour <b>raw2.github.com</b>",
"description": "Successful outcome of clicking 'update' button"
},
"aboutAssetsUpdateStatusAdded" : {
"message": "À ajouter",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusChanged" : {
"message": "Nouvelle version disponible",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusUnchanged" : {
"message": "À jour",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusRemoved" : {
"message": "À supprimer",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateButton" : {
"message": "Mettre à jour",
"description": "Update button"
},
"aboutAssetsUpdatingButton" : {
"message": "Mise à jour en cours...",
"description": "Updating..."
},
"setupPagePrompt" : {
"message": "<p><b>µMatrix</b> est hautement personnalisable : il peut être paramétré pour faire du &ldquo;Blocage total&rdquo; comme du &ldquo;Blocage inactif&rdquo;. <p>Plus les pages Web sont sécurisées, plus elles risquent d'être &ldquo;compromises&rdquo;, c'est-à-dire qu'elles n'auront pas un rendu/comportement attendu. Ainsi, une sécurité forte implique plus d'interventions de la part de l'utilisateur pour &ldquo;faire remarcher&rdquo; les pages Web jugées fiables par l'utilisateur. <p>Ici, vous pouvez choisir un profil correspondant le mieux à votre intention d'utiliser <b>µMatrix</b>. Pensez cela comme un point de départ, paramétrable à volonté par la suite !",
"description": "Appears at the top of the setup page"
},
"setupBlockAllAllowExceptionally" : {
"message": "Blocage total / Permissions exceptionnelles",
"description": "English: Block all / allow exceptionally"
},
"setupAllowAllBlockExceptionally" : {
"message": "Permission totale / Blocage exceptionnel",
"description": "English: Allow all / block exceptionally"
},
"setupAdBlocker" : {
"message": "Façon Adblock",
"description": "English: Ad blocker-like"
},
"setupNoScript" : {
"message": "Façon NoScript",
"description": "English: NoScript-like"
},
"setupRequestPolicy" : {
"message": "Façon RequestPolicy",
"description": "English: RequestPolicy-like"
},
"setupBlockNothingReportAll" : {
"message": "Blocage inactif / Tout rapporter",
"description": "English: Block nothing / report everything"
},
"setupSecurity" : {
"message": "Sécurité :",
"description": "English: Security:"
},
"setupBreakage" : {
"message": "Compromission :",
"description": "English: Breakage:"
},
"setupVeryHigh" : {
"message": "Très élevée",
"description": "English: very high"
},
"setupHigh" : {
"message": "Élevée",
"description": "English: high"
},
"setupMediumHigh" : {
"message": "Assez élevée",
"description": "English: medium high"
},
"setupMedium" : {
"message": "Moyenne",
"description": "English: medium"
},
"setupMediumLow" : {
"message": "Assez faible",
"description": "English: medium low"
},
"setupLow" : {
"message": "Faible",
"description": "English: low"
}, },
"setupVeryLow" : { "aboutOr" : {
"message": "Très faible", "message": "... or ...",
"description": "English: very low" "description": "English: ... or ..."
}, },
"setupNone" : { "aboutResetButton" : {
"message": "Inexistante", "message": "Reset to default settings",
"description": "English: none" "description": "English: Reset to default settings"
}, },
"setupRestoreConfirm" : { "aboutResetConfirm" : {
"message": "Tous vos paramètres et toutes vos règles seront remplacés\net µMatrix va redémarrer.\n\nRemplacer les données existantes ?", "message": "Caution! this will also remove all your custom settings. Are you sure you want to proceed?",
"description": "English: All your settings and rules will be overwritten\nand µMatrix will restart.\n\nOverwrite all existing data?" "description": "Message asking user to confirm reset"
}, },

@ -483,143 +483,37 @@
"message": "Ваши настройки", "message": "Ваши настройки",
"description": "English: Your data" "description": "English: Your data"
}, },
"aboutUserDataBackupButton" : { "aboutBackupButton" : {
"message": "Сохранить в файл...", "message": "Backup to file...",
"description": "English: Backup all..." "description": "English: Backup all..."
}, },
"aboutUserDataRestoreButton" : { "aboutBackupFilename" : {
"message": "Восстановить из файла...", "message": "all-my-umatrix-data.txt",
"description": "English: Restore all..." "description": "all-my-umatrix-data.txt"
},
"aboutUserDataOr" : {
"message": "... или ...",
"description": "English: ... or ..."
}, },
"aboutUserDataResetButton" : { "aboutRestoreButton" : {
"message": "Запустить настройку с нуля...", "message": "Restore from file...",
"description": "English: Start from scratch..." "description": "English: Restore all..."
}, },
"aboutUserDataRestoreConfirm" : { "aboutRestoreConfirm" : {
"message": "Все ваши настройки и правила будет перезаписаны\nданными от {{time}},\nи µMatrix перезапустится.\n\nПерезаписать все существующие данные резервной копией?", "message": "All your settings will be overwritten using data backed up on {{time}}, and µMatrix will restart.\n\nOverwrite all existing settings using backed up data?",
"description": "Message asking user to confirm restore" "description": "Message asking user to confirm restore"
}, },
"aboutExtensionDataHeader" : { "aboutRestoreError" : {
"message": "Данные расширения", "message": "The data could not be read or is invalid",
"description": "English: Extension data" "description": ""
},
"aboutAssetsUpdatePrompt" : {
"message": "<i>µMatrix</i> подписки могут быть обновлены здесь вручную, если не хотите ждать новой версии расширения. Они загружаются из <a href=\"https://github.com/gorhill/httpswitchboard\">Github хранилища</a>.",
"description": "Short descriptive text of the update feature"
},
"aboutAssetsUpdateColPath" : {
"message": "Путь",
"description": "Path column header"
},
"aboutAssetsUpdateColStatus" : {
"message": "Состояние",
"description": "Status column header"
},
"aboutAssetsUpdateGetListError" : {
"message": "Произошла ошибка. <b>XHR</b> заблокирован для <b>raw2.github.com</b>?",
"description": "Successful outcome of clicking 'update' button"
},
"aboutAssetsUpdateStatusAdded" : {
"message": "Добавить",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusChanged" : {
"message": "Доступно обновление",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusUnchanged" : {
"message": "Обновлений не найдено",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusRemoved" : {
"message": "Для удаления",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateButton" : {
"message": "Обновить",
"description": "Update button"
},
"aboutAssetsUpdatingButton" : {
"message": "Обновление...",
"description": "Updating..."
},
"setupPagePrompt" : {
"message": "<p><b>µMatrix</b> можно гибко настроить: в любом месте можно уставновить &ldquo;блокирование всего&rdquo; и &ldquo;ничего не блокировать&rdquo;. <p>Чем выше безопасность, тем больше вероятность &ldquo;поломки&rdquo; сайтов, это означает, что сайт будет загружаться не полностью или вести себя не так, как задумавал создатель. Поэтому скорее всего потребуется вмешательство пользователя, чтобы &ldquo;починить&rdquo; эти страницы, которым пользователь доверяет, разрешив в матрице данные необходимые для нормальной работы сайта. <p>Здесь вы можете выбрать готовый профиль, как будет работать <b>µMatrix</b>. Можно считать это начальной настройкой т.к. дальше их можно дополнять для конкретных сайтов отдельно.",
"description": "Appears at the top of the setup page"
},
"setupBlockAllAllowExceptionally" : {
"message": "Блокировать все / разрешать исключения",
"description": "English: Block all / allow exceptionally"
},
"setupAllowAllBlockExceptionally" : {
"message": "Разрешить все / блокировать исключения",
"description": "English: Allow all / block exceptionally"
},
"setupAdBlocker" : {
"message": "Как блокировщик рекламы",
"description": "English: Ad blocker-like"
},
"setupNoScript" : {
"message": "Как блокировщик скриптов",
"description": "English: NoScript-like"
},
"setupRequestPolicy" : {
"message": "Как политика запросов",
"description": "English: RequestPolicy-like"
},
"setupBlockNothingReportAll" : {
"message": "Ничего не блокировать / докладывать обо всем",
"description": "English: Block nothing / report everything"
},
"setupSecurity" : {
"message": "Безопасность:",
"description": "English: Security:"
},
"setupBreakage" : {
"message": "Вероятность неправильного отображения сайта::",
"description": "English: Breakage:"
},
"setupVeryHigh" : {
"message": "очень высокая",
"description": "English: very high"
},
"setupHigh" : {
"message": "высокая",
"description": "English: high"
},
"setupMediumHigh" : {
"message": "выше среднего",
"description": "English: medium high"
},
"setupMedium" : {
"message": "средняя",
"description": "English: medium"
},
"setupMediumLow" : {
"message": "ниже среднего",
"description": "English: medium low"
},
"setupLow" : {
"message": "низкая",
"description": "English: low"
}, },
"setupVeryLow" : { "aboutOr" : {
"message": "очень низкая", "message": "... or ...",
"description": "English: very low" "description": "English: ... or ..."
}, },
"setupNone" : { "aboutResetButton" : {
"message": "ни влияет", "message": "Reset to default settings",
"description": "English: none" "description": "English: Reset to default settings"
}, },
"setupRestoreConfirm" : { "aboutResetConfirm" : {
"message": "Все ваши правила и настройки будут перезаписаны\nи µMatrix перезапустится.\n\nПерезаписать существующие настройки?", "message": "Caution! this will also remove all your custom settings. Are you sure you want to proceed?",
"description": "English: All your settings and rules will be overwritten\nand µMatrix will restart.\n\nOverwrite all existing data?" "description": "Message asking user to confirm reset"
}, },

@ -483,143 +483,37 @@
"message": "您的数据", "message": "您的数据",
"description": "English: Your data" "description": "English: Your data"
}, },
"aboutUserDataBackupButton" : { "aboutBackupButton" : {
"message": "备份到文件...", "message": "Backup to file...",
"description": "English: Backup all..." "description": "English: Backup all..."
}, },
"aboutUserDataRestoreButton" : { "aboutBackupFilename" : {
"message": "从文件恢复...", "message": "all-my-umatrix-data.txt",
"description": "English: Restore all..." "description": "all-my-umatrix-data.txt"
},
"aboutUserDataOr" : {
"message": "... 或者 ...",
"description": "English: ... or ..."
}, },
"aboutUserDataResetButton" : { "aboutRestoreButton" : {
"message": "从头来过……", "message": "Restore from file...",
"description": "English: Start from scratch..." "description": "English: Restore all..."
}, },
"aboutUserDataRestoreConfirm" : { "aboutRestoreConfirm" : {
"message": "所有您的设置和规则将被覆盖,\n使用备份于{{time}}时的数据,\n随后µMatrix将会重启。\n\n是否要使用备份数据覆盖所有现存数据", "message": "All your settings will be overwritten using data backed up on {{time}}, and µMatrix will restart.\n\nOverwrite all existing settings using backed up data?",
"description": "Message asking user to confirm restore" "description": "Message asking user to confirm restore"
}, },
"aboutExtensionDataHeader" : { "aboutRestoreError" : {
"message": "扩展数据", "message": "The data could not be read or is invalid",
"description": "English: Extension data" "description": ""
},
"aboutAssetsUpdatePrompt" : {
"message": "<i>µMatrix</i>使用的资源可以在这里进行升级,而不必等到扩展的下一个发行版。这些资源是拉取自<a href=\"https://github.com/gorhill/httpswitchboard\">本项目的Github代码托管库</a>。",
"description": "Short descriptive text of the update feature"
},
"aboutAssetsUpdateColPath" : {
"message": "路径",
"description": "Path column header"
},
"aboutAssetsUpdateColStatus" : {
"message": "状态",
"description": "Status column header"
},
"aboutAssetsUpdateGetListError" : {
"message": "有一个错误发生。<b>raw2.github.com</b>的<b>XHR</b>是否被屏蔽?",
"description": "Successful outcome of clicking 'update' button"
},
"aboutAssetsUpdateStatusAdded" : {
"message": "将被添加",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusChanged" : {
"message": "有新版本",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusUnchanged" : {
"message": "已是最新",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateStatusRemoved" : {
"message": "将被移除",
"description": "Displayed in the status column for each entry"
},
"aboutAssetsUpdateButton" : {
"message": "马上更新",
"description": "Update button"
},
"aboutAssetsUpdatingButton" : {
"message": "正在更新...",
"description": "Updating..."
},
"setupPagePrompt" : {
"message": "<p><b>µMatrix</b>是高度可配置的:它可以被设置为“屏蔽所有”和“完全不屏蔽”间的任何状态。<p>安全性越高,网页破损的可能性也就越高,即不能如设想的一样渲染或运作。因此,更高的安全性也意味着需要更多来自用户的介入,来“修复”那些用户信任的网页。<p>这里您可以选择一个最适合您使用<b>µMatrix</b>计划的设定档。您只需把这当作一个起点,因为您之后仍可随意自行定制。",
"description": "Appears at the top of the setup page"
},
"setupBlockAllAllowExceptionally" : {
"message": "屏蔽所有 / 允许例外",
"description": "English: Block all / allow exceptionally"
},
"setupAllowAllBlockExceptionally" : {
"message": "允许所有 / 屏蔽例外",
"description": "English: Allow all / block exceptionally"
},
"setupAdBlocker" : {
"message": "类似Adblock Plus",
"description": "English: Ad blocker-like"
},
"setupNoScript" : {
"message": "类似NoScript",
"description": "English: NoScript-like"
},
"setupRequestPolicy" : {
"message": "类似RequestPolicy",
"description": "English: RequestPolicy-like"
},
"setupBlockNothingReportAll" : {
"message": "完全不屏蔽 / 报告所有",
"description": "English: Block nothing / report everything"
},
"setupSecurity" : {
"message": "安全性:",
"description": "English: Security:"
},
"setupBreakage" : {
"message": "不兼容性:",
"description": "English: Breakage:"
},
"setupVeryHigh" : {
"message": "非常高",
"description": "English: very high"
},
"setupHigh" : {
"message": "高",
"description": "English: high"
},
"setupMediumHigh" : {
"message": "中高",
"description": "English: medium high"
},
"setupMedium" : {
"message": "中等",
"description": "English: medium"
},
"setupMediumLow" : {
"message": "中低",
"description": "English: medium low"
},
"setupLow" : {
"message": "低",
"description": "English: low"
}, },
"setupVeryLow" : { "aboutOr" : {
"message": "非常低", "message": "... or ...",
"description": "English: very low" "description": "English: ... or ..."
}, },
"setupNone" : { "aboutResetButton" : {
"message": "", "message": "Reset to default settings",
"description": "English: none" "description": "English: Reset to default settings"
}, },
"setupRestoreConfirm" : { "aboutResetConfirm" : {
"message": "所有您的设置和规则将被覆盖,\n然后µMatrix将会重启。\n\n是否要覆盖所有现存数据", "message": "Caution! this will also remove all your custom settings. Are you sure you want to proceed?",
"description": "English: All your settings and rules will be overwritten\nand µMatrix will restart.\n\nOverwrite all existing data?" "description": "Message asking user to confirm reset"
}, },

Loading…
Cancel
Save