Raymond Hill
7 years ago
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
19 changed files with 1076 additions and 420 deletions
-
22src/_locales/en/messages.json
-
1src/background.html
-
2src/css/dashboard-common.css
-
40src/css/hosts-files.css
-
102src/css/popup.css
-
1src/css/user-rules.css
-
25src/hosts-files.html
-
28src/js/assets.js
-
10src/js/background.js
-
190src/js/hosts-files.js
-
77src/js/messaging.js
-
143src/js/popup.js
-
217src/js/recipe-manager.js
-
1src/js/start.js
-
465src/js/storage.js
-
6src/js/usersettings.js
-
31src/js/utils.js
-
56src/popup.html
-
3tools/make-assets.sh
@ -0,0 +1,217 @@ |
|||
/******************************************************************************* |
|||
|
|||
uMatrix - a Chromium browser extension to black/white list requests. |
|||
Copyright (C) 2018 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 punycode */ |
|||
|
|||
'use strict'; |
|||
|
|||
/******************************************************************************/ |
|||
|
|||
µMatrix.recipeManager = (function() { |
|||
let rawRecipes = []; |
|||
let recipeIdGenerator = 1; |
|||
let recipeBook = new Map(); |
|||
let reValidRecipeFile = /^! uMatrix: Ruleset recipes [0-9.]+\n/; |
|||
let reNoUnicode = /^[\x00-\x7F]$/; |
|||
|
|||
var authorFromHeader = function(header) { |
|||
let match = /^! +maintainer: +([^\n]+)/im.exec(header); |
|||
return match !== null ? match[1].trim() : ''; |
|||
}; |
|||
|
|||
var conditionMatch = function(condition, srcHostname, desHostnames) { |
|||
let i = condition.indexOf(' '); |
|||
if ( i === -1 ) { return false; } |
|||
let hn = condition.slice(0, i).trim(); |
|||
if ( hn !== '*' && srcHostname.endsWith(hn) === false ) { |
|||
return false; |
|||
} |
|||
hn = condition.slice(i + 1).trim(); |
|||
if ( hn === '*' ) { return true; } |
|||
for ( let desHostname of desHostnames ) { |
|||
if ( desHostname.endsWith(hn) ) { return true; } |
|||
} |
|||
return false; |
|||
}; |
|||
|
|||
var toASCII = function(rule) { |
|||
if ( reNoUnicode.test(rule) ) { return rule; } |
|||
let parts = rule.split(/\s+/); |
|||
for ( let i = 0; i < parts.length; i++ ) { |
|||
parts[i] = punycode.toASCII(parts[i]); |
|||
} |
|||
return parts.join(' '); |
|||
}; |
|||
|
|||
var compareLength = function(a, b) { |
|||
return b.length - a.length; |
|||
}; |
|||
|
|||
var getTokens = function(s) { |
|||
let tokens = s.match(/[a-z0-9]+/gi); |
|||
if ( tokens === null ) { return []; } |
|||
return tokens; |
|||
}; |
|||
|
|||
var addRecipe = function(recipe) { |
|||
let tokens = getTokens(recipe.condition); |
|||
tokens.sort(compareLength); |
|||
let token = tokens[0]; |
|||
let recipes = recipeBook.get(token); |
|||
if ( recipes === undefined ) { |
|||
recipeBook.set(token, recipes = []); |
|||
} |
|||
recipes.push(recipe); |
|||
}; |
|||
|
|||
var fromString = function(raw) { |
|||
var recipeName, |
|||
recipeCondition, |
|||
recipeRuleset; |
|||
let rawHeader = raw.slice(0, 1024); |
|||
if ( reValidRecipeFile.test(rawHeader) === false ) { return; } |
|||
let maintainer = authorFromHeader(rawHeader); |
|||
let lineIter = new µMatrix.LineIterator(raw); |
|||
for (;;) { |
|||
let line = lineIter.next().trim(); |
|||
if ( line.length === 0 ) { |
|||
if ( |
|||
recipeName !== undefined && |
|||
recipeCondition !== undefined && |
|||
recipeRuleset.length !== 0 |
|||
) { |
|||
addRecipe({ |
|||
id: recipeIdGenerator++, |
|||
name: recipeName, |
|||
maintainer: maintainer, |
|||
condition: recipeCondition, |
|||
ruleset: recipeRuleset |
|||
}); |
|||
} |
|||
recipeName = undefined; |
|||
} |
|||
if ( lineIter.eot() && recipeName === undefined ) { break; } |
|||
if ( line.length === 0 ) { continue; } |
|||
let c = line.charCodeAt(0); |
|||
if ( c === 0x23 /* '#' */ || c === 0x21 /* '!' */ ) { continue; } |
|||
if ( recipeName === undefined ) { |
|||
recipeName = line; |
|||
recipeCondition = undefined; |
|||
continue; |
|||
} |
|||
if ( recipeCondition === undefined ) { |
|||
recipeCondition = toASCII(line); |
|||
recipeRuleset = ''; |
|||
continue; |
|||
} |
|||
if ( recipeRuleset.length !== 0 ) { |
|||
recipeRuleset += '\n'; |
|||
} |
|||
recipeRuleset += toASCII(line); |
|||
} |
|||
}; |
|||
|
|||
var fromPendingStrings = function() { |
|||
if ( rawRecipes.length === 0 ) { return; } |
|||
for ( var raw of rawRecipes ) { |
|||
fromString(raw); |
|||
} |
|||
rawRecipes = []; |
|||
}; |
|||
|
|||
return { |
|||
apply: function(details) { |
|||
let µm = µMatrix; |
|||
let tMatrix = µm.tMatrix; |
|||
let pMatrix = µm.pMatrix; |
|||
let mustPersist = false; |
|||
for ( let rule of details.ruleset.split('\n') ) { |
|||
let parts = rule.split(/\s+/); |
|||
let action = tMatrix.evaluateCellZXY(parts[0], parts[1], parts[2]); |
|||
if ( action === 1 ) { |
|||
tMatrix.whitelistCell(parts[0], parts[1], parts[2]); |
|||
} |
|||
if ( details.commit !== true ) { continue; } |
|||
action = pMatrix.evaluateCellZXY(parts[0], parts[1], parts[2]); |
|||
if ( action === 1 ) { |
|||
pMatrix.whitelistCell(parts[0], parts[1], parts[2]); |
|||
mustPersist = true; |
|||
} |
|||
} |
|||
if ( mustPersist ) { |
|||
µm.saveMatrix(); |
|||
} |
|||
}, |
|||
fetch: function(srcHostname, desHostnames, callback) { |
|||
fromPendingStrings(); |
|||
let out = []; |
|||
let fetched = new Set(); |
|||
let tokens = getTokens(srcHostname + ' ' + desHostnames.join(' ')); |
|||
for ( let token of tokens ) { |
|||
let recipes = recipeBook.get(token); |
|||
if ( recipes === undefined ) { continue; } |
|||
for ( let recipe of recipes ) { |
|||
if ( fetched.has(recipe.id) ) { continue; } |
|||
if ( |
|||
conditionMatch( |
|||
recipe.condition, |
|||
srcHostname, |
|||
desHostnames |
|||
) |
|||
) { |
|||
out.push(recipe); |
|||
fetched.add(recipe.id); |
|||
} |
|||
} |
|||
} |
|||
callback(out); |
|||
}, |
|||
commitStatuses: function(details) { |
|||
let matrix = µMatrix.pMatrix; |
|||
for ( let recipe of details.recipes ) { |
|||
let ruleIter = new µMatrix.LineIterator(recipe.ruleset); |
|||
while ( ruleIter.eot() === false ) { |
|||
let parts = ruleIter.next().split(/\s+/); |
|||
if ( |
|||
matrix.evaluateCellZXY( |
|||
details.scope, |
|||
parts[1], |
|||
parts[2] |
|||
) === 1 |
|||
) { |
|||
recipe.mustCommit = true; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
return details; |
|||
}, |
|||
fromString: function(raw) { |
|||
rawRecipes.push(raw); |
|||
}, |
|||
reset: function() { |
|||
rawRecipes.length = 0; |
|||
recipeBook.clear(); |
|||
} |
|||
}; |
|||
})(); |
|||
|
|||
/******************************************************************************/ |
Write
Preview
Loading…
Cancel
Save
Reference in new issue