Revive formerly removed <noscript> tag spoofing code

Also:
- a new per-scope switch has been added to control <noscript> spoofing on
  a per site basis
- a global setting to be used as the default state of the <noscript>
  spoofing switch
- Privacy pane has been merged into Setting pane
pull/2/head
gorhill 7 years ago
parent b5d94c708d
commit 9d43f929bc
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2

@ -119,6 +119,10 @@
"message": "Referrer spoofing",
"description": "A menu entry in the matrix popup"
},
"matrixSwitchNoscriptSpoof" : {
"message": "<code><noscript></code> tags spoofing",
"description": "A menu entry in the matrix popup"
},
"matrixRevertAllEntry" : {
"message": "Revert all temporary changes",
"description": "A menu entry in the matrix popup"
@ -338,6 +342,10 @@
"message": "Collapse placeholder of blocked elements",
"description": "English: Collapse placeholder of blocked elements"
},
"settingsNoscriptTagsSpoofed" : {
"message": "Spoof <code><noscript></code> tags when 1st-party scripts are blocked",
"description": "This appears in the Settings pane in the dashboard"
},
"settingsCloudStorageEnabled" : {
"message": "Enable cloud storage support",
"description": ""

@ -113,3 +113,6 @@ button.custom[disabled] {
opacity: 0.6;
pointer-events: none;
}
code {
font-size: 90%;
}

@ -82,7 +82,6 @@ iframe {
<div id="dashboard-nav-widgets">
<span>uMatrix</span>
<a class="tabButton" id="settings" href="#settings" data-dashboard-panel-url="settings.html" data-i18n="settingsPageName"></a>
<a class="tabButton" id="privacy" href="#privacy" data-dashboard-panel-url="privacy.html" data-i18n="privacyPageName"></a>
<a class="tabButton" id="user-rules" href="#user-rules" data-dashboard-panel-url="user-rules.html" data-i18n="userRulesPageName"></a>
<a class="tabButton" id="hosts-files" href="#hosts-files" data-dashboard-panel-url="hosts-files.html" data-i18n="ubiquitousRulesPageName"></a>
<a class="tabButton" id="about" href="#about" data-dashboard-panel-url="about.html" data-i18n="aboutPageName"></a>

@ -493,6 +493,31 @@ var nodeListsAddedHandler = function(nodeLists) {
/******************************************************************************/
/******************************************************************************/
// Executed only once.
(function() {
var noscripts = document.querySelectorAll('noscript');
if ( noscripts.length === 0 ) { return; }
var renderNoscriptTags = function(response) {
if ( response !== true ) { return; }
var parent, span;
for ( var noscript of noscripts ) {
parent = noscript.parentNode;
if ( parent === null ) { continue; }
span = document.createElement('span');
span.innerHTML = noscript.textContent;
parent.replaceChild(span, noscript);
}
};
localMessager.send({ what: 'mustRenderNoscriptTags?' }, renderNoscriptTags);
})();
/******************************************************************************/
/******************************************************************************/
localMessager.send({ what: 'shutdown?' }, function(response) {
if ( response === true ) {
vAPI.shutdown.exec();

@ -90,7 +90,8 @@ var switchBitOffsets = new Map([
[ 'matrix-off', 0 ],
[ 'https-strict', 2 ],
/* 4 is now unused, formerly assigned to UA spoofing */
[ 'referrer-spoof', 6 ]
[ 'referrer-spoof', 6 ],
[ 'noscript-spoof', 8 ]
]);
var switchStateToNameMap = new Map([

@ -63,7 +63,14 @@ function onMessage(request, sender, callback) {
break;
case 'getUserSettings':
response = µm.userSettings;
response = {
userSettings: µm.userSettings,
matrixSwitches: {
'https-strict': µm.pMatrix.evaluateSwitch('https-strict', '*') === 1,
'referrer-spoof': µm.pMatrix.evaluateSwitch('referrer-spoof', '*') === 1,
'noscript-spoof': µm.pMatrix.evaluateSwitch('noscript-spoof', '*') === 1
}
};
break;
case 'gotoExtensionURL':
@ -86,6 +93,13 @@ function onMessage(request, sender, callback) {
µm.reloadHostsFiles();
break;
case 'setMatrixSwitch':
µm.tMatrix.setSwitch(request.switchName, '*', request.state);
if ( µm.pMatrix.setSwitch(request.switchName, '*', request.state) ) {
µm.saveMatrix();
}
break;
case 'userSettings':
if ( request.hasOwnProperty('value') === false ) {
request.value = undefined;
@ -519,6 +533,7 @@ var onMessage = function(request, sender, callback) {
}
var tabId = sender && sender.tab ? sender.tab.id || 0 : 0;
var tabContext = µm.tabContextManager.lookup(tabId);
// Sync
var response;
@ -536,8 +551,15 @@ var onMessage = function(request, sender, callback) {
response = evaluateURLs(tabId, request.requests);
break;
case 'mustRenderNoscriptTags?':
if ( tabContext !== null ) {
response =
µm.tMatrix.mustBlock(tabContext.rootHostname, tabContext.rootHostname, 'script') &&
µm.tMatrix.evaluateSwitchZ('noscript-spoof', tabContext.rootHostname);
}
break;
case 'shutdown?':
var tabContext = µm.tabContextManager.lookup(tabId);
if ( tabContext !== null ) {
response = µm.tMatrix.evaluateSwitchZ('matrix-off', tabContext.rootHostname);
}
@ -619,85 +641,6 @@ vAPI.messaging.listen('cloud-ui.js', onMessage);
/******************************************************************************/
/******************************************************************************/
// settings.js
(function() {
var onMessage = function(request, sender, callback) {
var µm = µMatrix;
// Async
switch ( request.what ) {
default:
break;
}
// Sync
var response;
switch ( request.what ) {
default:
return vAPI.messaging.UNHANDLED;
}
callback(response);
};
vAPI.messaging.listen('settings.js', onMessage);
})();
/******************************************************************************/
/******************************************************************************/
// privacy.js
(function() {
var onMessage = function(request, sender, callback) {
var µm = µMatrix;
// Async
switch ( request.what ) {
default:
break;
}
// Sync
var response;
switch ( request.what ) {
case 'getPrivacySettings':
response = {
userSettings: µm.userSettings,
matrixSwitches: {
'https-strict': µm.pMatrix.evaluateSwitch('https-strict', '*') === 1,
'referrer-spoof': µm.pMatrix.evaluateSwitch('referrer-spoof', '*') === 1
}
};
break;
case 'setMatrixSwitch':
µm.tMatrix.setSwitch(request.switchName, '*', request.state);
if ( µm.pMatrix.setSwitch(request.switchName, '*', request.state) ) {
µm.saveMatrix();
}
break;
default:
return vAPI.messaging.UNHANDLED;
}
callback(response);
};
vAPI.messaging.listen('privacy.js', onMessage);
})();
/******************************************************************************/
/******************************************************************************/
// user-rules.js
(function() {

@ -1,142 +0,0 @@
/*******************************************************************************
uMatrix - a Chromium browser extension to black/white list requests.
Copyright (C) 2014-2017 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 vAPI, uDom */
'use strict';
/******************************************************************************/
(function() {
/******************************************************************************/
var messager = vAPI.messaging.channel('privacy.js');
var cachedPrivacySettings = {};
/******************************************************************************/
function changeUserSettings(name, value) {
messager.send({
what: 'userSettings',
name: name,
value: value
});
}
/******************************************************************************/
function changeMatrixSwitch(name, state) {
messager.send({
what: 'setMatrixSwitch',
switchName: name,
state: state
});
}
/******************************************************************************/
function onChangeValueHandler(uelem, setting, min, max) {
var oldVal = cachedPrivacySettings.userSettings[setting];
var newVal = Math.round(parseFloat(uelem.val()));
if ( typeof newVal !== 'number' ) {
newVal = oldVal;
} else {
newVal = Math.max(newVal, min);
newVal = Math.min(newVal, max);
}
uelem.val(newVal);
if ( newVal !== oldVal ) {
changeUserSettings(setting, newVal);
}
}
/******************************************************************************/
function prepareToDie() {
onChangeValueHandler(uDom('#delete-unused-session-cookies-after'), 'deleteUnusedSessionCookiesAfter', 15, 1440);
onChangeValueHandler(uDom('#clear-browser-cache-after'), 'clearBrowserCacheAfter', 15, 1440);
}
/******************************************************************************/
var installEventHandlers = function() {
uDom('[data-setting-bool]').on('change', function(){
var settingName = this.getAttribute('data-setting-bool');
if ( typeof settingName === 'string' && settingName !== '' ) {
changeUserSettings(settingName, this.checked);
}
});
uDom('[data-matrix-switch]').on('change', function(){
var switchName = this.getAttribute('data-matrix-switch');
if ( typeof switchName === 'string' && switchName !== '' ) {
changeMatrixSwitch(switchName, this.checked);
}
});
uDom('#delete-unused-session-cookies-after').on('change', function(){
onChangeValueHandler(uDom(this), 'deleteUnusedSessionCookiesAfter', 15, 1440);
});
uDom('#clear-browser-cache-after').on('change', function(){
onChangeValueHandler(uDom(this), 'clearBrowserCacheAfter', 15, 1440);
});
// https://github.com/gorhill/httpswitchboard/issues/197
uDom(window).on('beforeunload', prepareToDie);
};
/******************************************************************************/
uDom.onLoad(function() {
var onSettingsReceived = function(privacySettings) {
// Cache copy
cachedPrivacySettings = privacySettings;
var userSettings = privacySettings.userSettings;
var matrixSwitches = privacySettings.matrixSwitches;
uDom('[data-setting-bool]').forEach(function(elem){
var settingName = elem.attr('data-setting-bool');
if ( typeof settingName === 'string' && settingName !== '' ) {
elem.prop('checked', userSettings[settingName] === true);
}
});
uDom('[data-matrix-switch]').forEach(function(elem){
var switchName = elem.attr('data-matrix-switch');
if ( typeof switchName === 'string' && switchName !== '' ) {
elem.prop('checked', matrixSwitches[switchName] === true);
}
});
uDom('#delete-unused-session-cookies-after').val(userSettings.deleteUnusedSessionCookiesAfter);
uDom('#clear-browser-cache-after').val(userSettings.clearBrowserCacheAfter);
installEventHandlers();
};
messager.send({ what: 'getPrivacySettings' }, onSettingsReceived);
});
/******************************************************************************/
})();

@ -1,7 +1,7 @@
/*******************************************************************************
µMatrix - a Chromium browser extension to black/white list requests.
Copyright (C) 2014 Raymond Hill
uMatrix - a Chromium browser extension to black/white list requests.
Copyright (C) 2014-2017 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
@ -22,17 +22,17 @@
/* global vAPI, uDom */
/* jshint multistr: true */
'use strict';
/******************************************************************************/
(function() {
'use strict';
/******************************************************************************/
var messager = vAPI.messaging.channel('settings.js');
var cachedUserSettings = {};
var cachedSettings = {};
/******************************************************************************/
@ -46,18 +46,41 @@ function changeUserSettings(name, value) {
/******************************************************************************/
function changeMatrixSwitch(name, state) {
messager.send({
what: 'setMatrixSwitch',
switchName: name,
state: state
});
}
/******************************************************************************/
function onChangeValueHandler(uelem, setting, min, max) {
var oldVal = cachedSettings.userSettings[setting];
var newVal = Math.round(parseFloat(uelem.val()));
if ( typeof newVal !== 'number' ) {
newVal = oldVal;
} else {
newVal = Math.max(newVal, min);
newVal = Math.min(newVal, max);
}
uelem.val(newVal);
if ( newVal !== oldVal ) {
changeUserSettings(setting, newVal);
}
}
/******************************************************************************/
function prepareToDie() {
onChangeValueHandler(uDom('#delete-unused-session-cookies-after'), 'deleteUnusedSessionCookiesAfter', 15, 1440);
onChangeValueHandler(uDom('#clear-browser-cache-after'), 'clearBrowserCacheAfter', 15, 1440);
}
/******************************************************************************/
var installEventHandlers = function() {
// `data-range` allows to add/remove bool properties without
// changing code.
uDom('input[data-range="bool"]').on('change', function() {
changeUserSettings(this.id, this.checked);
});
uDom('input[name="displayTextSize"]').on('change', function(){
changeUserSettings('displayTextSize', this.value);
});
@ -66,6 +89,27 @@ var installEventHandlers = function() {
changeUserSettings('popupScopeLevel', this.value);
});
uDom('[data-setting-bool]').on('change', function(){
var settingName = this.getAttribute('data-setting-bool');
if ( typeof settingName === 'string' && settingName !== '' ) {
changeUserSettings(settingName, this.checked);
}
});
uDom('[data-matrix-switch]').on('change', function(){
var switchName = this.getAttribute('data-matrix-switch');
if ( typeof switchName === 'string' && switchName !== '' ) {
changeMatrixSwitch(switchName, this.checked);
}
});
uDom('#delete-unused-session-cookies-after').on('change', function(){
onChangeValueHandler(uDom(this), 'deleteUnusedSessionCookiesAfter', 15, 1440);
});
uDom('#clear-browser-cache-after').on('change', function(){
onChangeValueHandler(uDom(this), 'clearBrowserCacheAfter', 15, 1440);
});
// https://github.com/gorhill/httpswitchboard/issues/197
uDom(window).on('beforeunload', prepareToDie);
};
@ -73,14 +117,25 @@ var installEventHandlers = function() {
/******************************************************************************/
uDom.onLoad(function() {
var onUserSettingsReceived = function(userSettings) {
var onSettingsReceived = function(settings) {
// Cache copy
cachedUserSettings = userSettings;
cachedSettings = settings;
var userSettings = settings.userSettings;
var matrixSwitches = settings.matrixSwitches;
// `data-range` allows to add/remove bool properties without
// changing code.
uDom('input[data-range="bool"]').forEach(function(elem) {
elem.prop('checked', userSettings[elem.attr('id')] === true);
uDom('[data-setting-bool]').forEach(function(elem){
var settingName = elem.attr('data-setting-bool');
if ( typeof settingName === 'string' && settingName !== '' ) {
elem.prop('checked', userSettings[settingName] === true);
}
});
uDom('[data-matrix-switch]').forEach(function(elem){
var switchName = elem.attr('data-matrix-switch');
if ( typeof switchName === 'string' && switchName !== '' ) {
elem.prop('checked', matrixSwitches[switchName] === true);
}
});
uDom('input[name="displayTextSize"]').forEach(function(elem) {
@ -89,9 +144,12 @@ uDom.onLoad(function() {
uDom.nodeFromId('popupScopeLevel').value = userSettings.popupScopeLevel;
uDom('#delete-unused-session-cookies-after').val(userSettings.deleteUnusedSessionCookiesAfter);
uDom('#clear-browser-cache-after').val(userSettings.clearBrowserCacheAfter);
installEventHandlers();
};
messager.send({ what: 'getUserSettings' }, onUserSettingsReceived);
messager.send({ what: 'getUserSettings' }, onSettingsReceived);
});
/******************************************************************************/

@ -31,6 +31,7 @@
<ul id="mtxSwitches">
<li id="mtxSwitch_referrer-spoof" class="dropdown-menu-entry" data-i18n="matrixSwitchReferrerSpoof">
<li id="mtxSwitch_https-strict" class="dropdown-menu-entry" data-i18n="matrixSwitchNoMixedContent">
<li id="mtxSwitch_noscript-spoof" class="dropdown-menu-entry" data-i18n="matrixSwitchNoscriptSpoof">
</ul>
</div>
<div class="dropdown-menu-capture"></div>

@ -1,88 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>uMatrix — Privacy</title>
<link rel="stylesheet" type="text/css" href="css/common.css">
<link rel="stylesheet" type="text/css" href="css/dashboard-common.css">
<style>
div > p:first-child {
margin-top: 0;
}
div > p:last-child {
margin-bottom: 0;
}
ul {
padding: 0;
list-style-type: none;
}
ul > li {
margin: 0.5em 0;
}
.dim {
font-weight: 100;
color: #888;
}
</style>
</head>
<body>
<ul>
<li>
<input id="delete-blacklisted-cookies" type="checkbox" data-setting-bool="deleteCookies"><label data-i18n="privacyDeleteBlockedCookiesPrompt" for="delete-blacklisted-cookies"></label>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyDeleteBlockedCookiesHelp"></div>
<li>
<input id="delete-unused-session-cookies" type="checkbox" data-setting-bool="deleteUnusedSessionCookies"><label data-i18n="privacyDeleteNonBlockedSessionCookiesPrompt1" for="delete-unused-session-cookies"></label>
<input id="delete-unused-session-cookies-after" type="text" value="60" size="3"><span data-i18n="privacyDeleteNonBlockedSessionCookiesPrompt2"></span>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyDeleteNonBlockedSessionCookiesHelp"></div>
<!--
Delete non-blocked session cookies x minutes after the last time they have been used.
Allow generically blocked cookies but deleted them x minutes after they have been first created.
A "generically blocked" cookie is a cookie which inherits its block status in
the matrix from the `cookie` cell or the `all` cell in the top row of the
matrix.
When a cookie inherits its block status from a cell in the top row of the
matrix (the "header" row), this means it is not specifically distrusted, but
rather that the default stance is to distrust cookies in general.
However some sites do require cookies to minimally work properly. This options
allow to "unbreak" these sites by allowing not specifically distrusted cookies
to travel back and forth between you and the server, but to limit the lifetime
of these cookies so that they cannot be used to track you.
-->
<li>
<input id="delete-blacklisted-localstorage" type="checkbox" data-setting-bool="deleteLocalStorage"><label data-i18n="privacyDeleteBlockedLocalStoragePrompt" for="delete-blacklisted-localstorage"></label>
<li>
<input id="clear-browser-cache" type="checkbox" data-setting-bool="clearBrowserCache"><label data-i18n="privacyClearCachePrompt1" for="clear-browser-cache"></label>
<input id="clear-browser-cache-after" type="text" value="60" size="3"> <label data-i18n="privacyClearCachePrompt2" for="clear-browser-cache-after"></label>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyClearCacheHelp"></div>
<li>
<input id="process-referer" type="checkbox" data-matrix-switch="referrer-spoof"><label data-i18n="privacyProcessRefererPrompt" for="process-referer"></label>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyProcessRefererHelp"></div>
<li>
<input id="no-mixed-content" type="checkbox" data-matrix-switch="https-strict"><label data-i18n="privacyNoMixedContentPrompt" for="no-mixed-content"></label>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyNoMixedContentHelp"></div>
<li>
<input id="process-hyperlink-auditing" type="checkbox" data-setting-bool="processHyperlinkAuditing"><label data-i18n="privacyProcessHyperlinkAuditingPrompt" for="process-hyperlink-auditing"></label>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyProcessHyperlinkAuditingHelp"></div>
</ul>
<script src="js/vapi-common.js"></script>
<script src="js/vapi-client.js"></script>
<script src="js/udom.js"></script>
<script src="js/i18n.js"></script>
<script src="js/dashboard-common.js"></script>
<script src="js/privacy.js"></script>
</body>
</html>

@ -17,7 +17,7 @@ ul {
list-style-type: none;
}
ul > li {
margin: 0 0 0 1em;
margin: 0.2em 0 0.2em 1em;
}
ul > li.separator {
margin: 0.5em 0;
@ -34,13 +34,16 @@ ul > li.separator {
<h2 data-i18n="settingsMatrixConvenienceHeader"></h2>
<ul>
<li>
<input id="iconBadgeEnabled" type="checkbox" data-range="bool">
<input id="iconBadgeEnabled" type="checkbox" data-setting-bool="iconBadgeEnabled">
<label data-i18n="settingsIconBadgeEnabled" for="iconBadgeEnabled"></label>
<li>
<input id="collapseBlocked" type="checkbox" data-range="bool">
<input id="collapseBlocked" type="checkbox" data-setting-bool="collapseBlocked">
<label data-i18n="settingsCollapseBlocked" for="collapseBlocked"></label>
<li>
<input id="cloudStorageEnabled" type="checkbox" data-range="bool">
<input id="noscriptTagsSpoofed" type="checkbox" data-matrix-switch="noscript-spoof">
<label data-i18n="settingsNoscriptTagsSpoofed" for="noscriptTagsSpoofed"></label>
<li>
<input id="cloudStorageEnabled" type="checkbox" data-setting-bool="cloudStorageEnabled">
<label data-i18n="settingsCloudStorageEnabled" for="cloudStorageEnabled"></label>
</ul>
<h2 data-i18n="settingsMatrixDisplayHeader"></h2>
@ -53,9 +56,58 @@ ul > li.separator {
<label data-i18n="settingsDefaultScopeLevel"></label> <select id="popupScopeLevel"><option data-i18n="settingsDefaultScopeLevel2" value="site"><option data-i18n="settingsDefaultScopeLevel1" value="domain"><option data-i18n="settingsDefaultScopeLevel0" value="*"></select>
<li class="separator">
<li>
<input id="colorBlindFriendly" type="checkbox" data-range="bool">
<input id="colorBlindFriendly" type="checkbox" data-setting-bool="colorBlindFriendly">
<label data-i18n="settingsMatrixDisplayColorBlind" for="colorBlindFriendly"></label>
</ul>
<h2 data-i18n="privacyPageName"></h2>
<ul>
<li>
<input id="delete-blacklisted-cookies" type="checkbox" data-setting-bool="deleteCookies"><label data-i18n="privacyDeleteBlockedCookiesPrompt" for="delete-blacklisted-cookies"></label>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyDeleteBlockedCookiesHelp"></div>
<li>
<input id="delete-unused-session-cookies" type="checkbox" data-setting-bool="deleteUnusedSessionCookies"><label data-i18n="privacyDeleteNonBlockedSessionCookiesPrompt1" for="delete-unused-session-cookies"></label>
<input id="delete-unused-session-cookies-after" type="text" value="60" size="3"><span data-i18n="privacyDeleteNonBlockedSessionCookiesPrompt2"></span>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyDeleteNonBlockedSessionCookiesHelp"></div>
<!--
Delete non-blocked session cookies x minutes after the last time they have been used.
Allow generically blocked cookies but deleted them x minutes after they have been first created.
A "generically blocked" cookie is a cookie which inherits its block status in
the matrix from the `cookie` cell or the `all` cell in the top row of the
matrix.
When a cookie inherits its block status from a cell in the top row of the
matrix (the "header" row), this means it is not specifically distrusted, but
rather that the default stance is to distrust cookies in general.
However some sites do require cookies to minimally work properly. This options
allow to "unbreak" these sites by allowing not specifically distrusted cookies
to travel back and forth between you and the server, but to limit the lifetime
of these cookies so that they cannot be used to track you.
-->
<li>
<input id="delete-blacklisted-localstorage" type="checkbox" data-setting-bool="deleteLocalStorage"><label data-i18n="privacyDeleteBlockedLocalStoragePrompt" for="delete-blacklisted-localstorage"></label>
<li>
<input id="clear-browser-cache" type="checkbox" data-setting-bool="clearBrowserCache"><label data-i18n="privacyClearCachePrompt1" for="clear-browser-cache"></label>
<input id="clear-browser-cache-after" type="text" value="60" size="3"> <label data-i18n="privacyClearCachePrompt2" for="clear-browser-cache-after"></label>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyClearCacheHelp"></div>
<li>
<input id="process-referer" type="checkbox" data-matrix-switch="referrer-spoof"><label data-i18n="privacyProcessRefererPrompt" for="process-referer"></label>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyProcessRefererHelp"></div>
<li>
<input id="no-mixed-content" type="checkbox" data-matrix-switch="https-strict"><label data-i18n="privacyNoMixedContentPrompt" for="no-mixed-content"></label>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyNoMixedContentHelp"></div>
<li>
<input id="process-hyperlink-auditing" type="checkbox" data-setting-bool="processHyperlinkAuditing"><label data-i18n="privacyProcessHyperlinkAuditingPrompt" for="process-hyperlink-auditing"></label>
<span class="whatisthis"></span>
<div class="whatisthis-expandable para" data-i18n="privacyProcessHyperlinkAuditingHelp"></div>
</ul>
<script src="js/vapi-common.js"></script>
<script src="js/vapi-client.js"></script>

Loading…
Cancel
Save