From a4fb878b082389830f4c9e9829e917a5a11ea7f3 Mon Sep 17 00:00:00 2001 From: gorhill Date: Sun, 4 Dec 2016 10:30:55 -0500 Subject: [PATCH] fix https://github.com/gorhill/uBlock/issues/2084 for uMatrix --- src/_locales/en/messages.json | 4 +- src/css/dashboard-common.css | 9 +-- src/js/i18n.js | 120 +++++++++++++++++++++++++++++++++- 3 files changed, 124 insertions(+), 9 deletions(-) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index e956e23..63de061 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -360,7 +360,7 @@ "description": "Second part of 'Clear browser cache every [n] minutes'" }, "privacyClearCacheHelp" : { - "message": "

Some web sites are really bent on tracking you, so much that they will use not-so-nice tricks to work around whatever measures you take in order to not be tracked.

A few of these tricks rely[1, 2] on the browser cache, which content is often long lasting since rarely will users take the time to regularly clear their browser cache.

There is little inconvenience to clear the browser cache regularly (likelihood is that you won't notice when it happens), and the benefit is to prevent these obnoxious trackers from invading your privacy.

Check this option to have uMatrix do it for you, at the interval you wish.

[1] “Preventing Web Tracking via the Browser Cache”
[2] “Cookieless cookies”

", + "message": "

Some web sites are really bent on tracking you, so much that they will use not-so-nice tricks to work around whatever measures you take in order to not be tracked.

A few of these tricks rely[1, 2] on the browser cache, which content is often long lasting since rarely will users take the time to regularly clear their browser cache.

There is little inconvenience to clear the browser cache regularly (likelihood is that you won't notice when it happens), and the benefit is to prevent these obnoxious trackers from invading your privacy.

Check this option to have uMatrix do it for you, at the interval you wish.

[1] “Preventing Web Tracking via the Browser Cache”\n[2] “Cookieless cookies”

", "description": "" }, "privacyProcessRefererPrompt" : { @@ -368,7 +368,7 @@ "description": "" }, "privacyProcessRefererHelp" : { - "message": "

From Wikipedia:

HTTP referer is an HTTP header field that identifies the address of the webpage that linked to the resource being requested. ... Because referer information can violate privacy, some web browsers allow the user to disable the sending of referer information.

If this setting is checked, uMatrix will spoof the HTTP referrer information if the domain name of the HTTP referrer is third-party to the domain name of net request.", + "message": "From Wikipedia:

HTTP referer is an HTTP header field that identifies the address of the webpage that linked to the resource being requested. ... Because referer information can violate privacy, some web browsers allow the user to disable the sending of referer information.
If this setting is checked, uMatrix will spoof the HTTP referrer information if the domain name of the HTTP referrer is third-party to the domain name of net request.", "description": "" }, "privacyNoMixedContentPrompt" : { diff --git a/src/css/dashboard-common.css b/src/css/dashboard-common.css index 77837c5..d78e52e 100644 --- a/src/css/dashboard-common.css +++ b/src/css/dashboard-common.css @@ -56,12 +56,13 @@ button { opacity: 1.0; } .whatisthis-expandable { + background-color: #F8F8F8; + border: 1px dotted #aaa; + display: none; + font-size: smaller; margin: 0.5em 0 1em 1.25em; padding: 0.5em; - font-size: smaller; - display: none; - border: 1px dotted #aaa; - background-color: #F8F8F8; + white-space: pre-line; } .whatisthis-expandable > p { margin-top: 1em; diff --git a/src/js/i18n.js b/src/js/i18n.js index 81f793b..e7d1647 100644 --- a/src/js/i18n.js +++ b/src/js/i18n.js @@ -32,11 +32,125 @@ /******************************************************************************/ +// https://github.com/gorhill/uBlock/issues/2084 +// Anything else than , , , , , , and will +// be rendered as plain text. +// For , only the type attribute is allowed. +// For , only href attribute must be present, and it MUST starts with +// `https://`, and includes no single- or double-quotes. +// No HTML entities are allowed, there is code to handle existing HTML +// entities already present in translation files until they are all gone. + +var reSafeTags = /^([\s\S]*?)<(b|blockquote|code|em|i|span|sup)>(.+?)<\/\2>([\s\S]*)$/, + reSafeInput = /^([\s\S]*?)<(input type="[^"]+")>(.*?)([\s\S]*)$/, + reInput = /^input type=(['"])([a-z]+)\1$/, + reSafeLink = /^([\s\S]*?)<(a href=['"]https?:\/\/[^'" <>]+['"])>(.+?)<\/a>([\s\S]*)$/, + reLink = /^a href=(['"])(https?:\/\/[^'"]+)\1$/; + +var safeTextToTagNode = function(text) { + var matches, node; + if ( text.lastIndexOf('a ', 0) === 0 ) { + matches = reLink.exec(text); + if ( matches === null ) { return null; } + node = document.createElement('a'); + node.setAttribute('href', matches[2]); + return node; + } + if ( text.lastIndexOf('input ', 0) === 0 ) { + matches = reInput.exec(text); + if ( matches === null ) { return null; } + node = document.createElement('input'); + node.setAttribute('type', matches[2]); + return node; + } + // Firefox extension validator warns if using a variable as argument for + // document.createElement(). + switch ( text ) { + case 'b': + return document.createElement('b'); + case 'blockquote': + return document.createElement('blockquote'); + case 'code': + return document.createElement('code'); + case 'em': + return document.createElement('em'); + case 'i': + return document.createElement('i'); + case 'span': + return document.createElement('span'); + case 'sup': + return document.createElement('sup'); + default: + break; + } +}; + +var safeTextToTextNode = function(text) { + // TODO: remove once no more HTML entities in translation files. + if ( text.indexOf('&') !== -1 ) { + text = text.replace(/“/g, '“') + .replace(/”/g, '”') + .replace(/‘/g, '‘') + .replace(/’/g, '’'); + } + return document.createTextNode(text); +}; + +var safeTextToDOM = function(text, parent) { + if ( text === '' ) { return; } + // Fast path (most common). + if ( text.indexOf('<') === -1 ) { + return parent.appendChild(safeTextToTextNode(text)); + } + // Slow path. + // `

` no longer allowed. Code below can be remove once all

's are + // gone from translation files. + text = text.replace(/^

|<\/p>/g, '') + .replace(/

/g, '\n\n'); + // Parse allowed HTML tags. + var matches, + matches1 = reSafeTags.exec(text), + matches2 = reSafeLink.exec(text); + if ( matches1 !== null && matches2 !== null ) { + matches = matches1.index < matches2.index ? matches1 : matches2; + } else if ( matches1 !== null ) { + matches = matches1; + } else if ( matches2 !== null ) { + matches = matches2; + } else { + matches = reSafeInput.exec(text); + } + if ( matches === null ) { + parent.appendChild(safeTextToTextNode(text)); + return; + } + safeTextToDOM(matches[1], parent); + var node = safeTextToTagNode(matches[2]) || parent; + safeTextToDOM(matches[3], node); + parent.appendChild(node); + safeTextToDOM(matches[4], parent); +}; + +/******************************************************************************/ + // Helper to deal with the i18n'ing of HTML files. vAPI.i18n.render = function(context) { - uDom('[data-i18n]', context).forEach(function(elem) { - elem.html(vAPI.i18n(elem.attr('data-i18n'))); - }); + var docu = document, + root = context || docu, + elems, n, i, elem, text; + + elems = root.querySelectorAll('[data-i18n]'); + n = elems.length; + for ( i = 0; i < n; i++ ) { + elem = elems[i]; + text = vAPI.i18n(elem.getAttribute('data-i18n')); + if ( !text ) { continue; } + // TODO: remove once it's all replaced with + if ( text.indexOf('{') !== -1 ) { + text = text.replace(/\{\{input:([^}]+)\}\}/g, ''); + } + safeTextToDOM(text, elem); + } uDom('[title]', context).forEach(function(elem) { var title = vAPI.i18n(elem.attr('title'));