mirror of https://github.com/gorhill/uBlock.git
Add support for admin-managed hidden settings
Related discussion: - https://github.com/uBlockOrigin/uBlock-issues/issues/1437#issuecomment-754127066
This commit is contained in:
parent
d254c7c304
commit
c1130ec843
|
@ -7,13 +7,37 @@
|
|||
"description": "All entries present will overwrite local settings.",
|
||||
"type": "string"
|
||||
},
|
||||
"extraTrustedSiteDirectives": {
|
||||
"title": "A list of trusted-site directives",
|
||||
"description": "Trusted-site directives to always add at launch time.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
"toSet": {
|
||||
"title": "Settings to overwrite at launch time",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hiddenSettings": {
|
||||
"title": "A list of [name,value] pairs to populate hidden settings",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"title": "A [name,value] pair",
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"trustedSiteDirectives": {
|
||||
"title": "A list of trusted-site directives",
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"toAdd": {
|
||||
"title": "Settings to add at launch time",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"trustedSiteDirectives": {
|
||||
"title": "A list of trusted-site directives",
|
||||
"description": "Trusted-site directives to always add at launch time.",
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1429,9 +1429,10 @@ vAPI.adminStorage = (( ) => {
|
|||
bin = await webext.storage.managed.get(key);
|
||||
} catch(ex) {
|
||||
}
|
||||
if ( bin instanceof Object ) {
|
||||
if ( typeof key === 'string' && bin instanceof Object ) {
|
||||
return bin[key];
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -91,6 +91,9 @@
|
|||
text-decoration: underline var(--sf-warning-ink);
|
||||
text-underline-position: under;
|
||||
}
|
||||
.cm-s-default .cm-readonly {
|
||||
color: var(--sf-readonly-ink);
|
||||
}
|
||||
|
||||
/* Rules */
|
||||
.cm-s-default .cm-allowrule {
|
||||
|
|
|
@ -192,6 +192,7 @@
|
|||
--sf-error-surface: #ff000016;
|
||||
--sf-keyword-ink: var(--purple-60);
|
||||
--sf-notice-ink: var(--light-gray-60);
|
||||
--sf-readonly-ink: var(--light-gray-80);
|
||||
--sf-tag-ink: #117700;
|
||||
--sf-value-ink: var(--orange-80);
|
||||
--sf-variable-ink: var(--default-ink);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
/******************************************************************************/
|
||||
|
||||
let defaultSettings = new Map();
|
||||
let adminSettings = new Map();
|
||||
let beforeHash = '';
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -45,18 +46,22 @@ CodeMirror.defineMode('raw-settings', function() {
|
|||
const match = stream.match(/\S+/);
|
||||
if ( match !== null && defaultSettings.has(match[0]) ) {
|
||||
lastSetting = match[0];
|
||||
return 'keyword';
|
||||
return adminSettings.has(match[0])
|
||||
? 'readonly keyword'
|
||||
: 'keyword';
|
||||
}
|
||||
stream.skipToEnd();
|
||||
return 'line-cm-error';
|
||||
}
|
||||
stream.eatSpace();
|
||||
const match = stream.match(/.*$/);
|
||||
if (
|
||||
match !== null &&
|
||||
match[0].trim() !== defaultSettings.get(lastSetting)
|
||||
) {
|
||||
return 'line-cm-strong';
|
||||
if ( match !== null ) {
|
||||
if ( match[0].trim() !== defaultSettings.get(lastSetting) ) {
|
||||
return 'line-cm-strong';
|
||||
}
|
||||
if ( adminSettings.has(lastSetting) ) {
|
||||
return 'readonly';
|
||||
}
|
||||
}
|
||||
stream.skipToEnd();
|
||||
return null;
|
||||
|
@ -146,21 +151,34 @@ const renderAdvancedSettings = async function(first) {
|
|||
what: 'readHiddenSettings',
|
||||
});
|
||||
defaultSettings = new Map(arrayFromObject(details.default));
|
||||
adminSettings = new Map(arrayFromObject(details.admin));
|
||||
beforeHash = hashFromAdvancedSettings(details.current);
|
||||
const pretty = [];
|
||||
const roLines = [];
|
||||
const entries = arrayFromObject(details.current);
|
||||
let max = 0;
|
||||
for ( const [ k ] of entries ) {
|
||||
if ( k.length > max ) { max = k.length; }
|
||||
}
|
||||
for ( const [ k, v ] of entries ) {
|
||||
for ( let i = 0; i < entries.length; i++ ) {
|
||||
const [ k, v ] = entries[i];
|
||||
pretty.push(' '.repeat(max - k.length) + `${k} ${v}`);
|
||||
if ( adminSettings.has(k) ) {
|
||||
roLines.push(i);
|
||||
}
|
||||
}
|
||||
pretty.push('');
|
||||
cmEditor.setValue(pretty.join('\n'));
|
||||
if ( first ) {
|
||||
cmEditor.clearHistory();
|
||||
}
|
||||
for ( const line of roLines ) {
|
||||
cmEditor.markText(
|
||||
{ line, ch: 0 },
|
||||
{ line: line + 1, ch: 0 },
|
||||
{ readOnly: true }
|
||||
);
|
||||
}
|
||||
advancedSettingsChanged();
|
||||
cmEditor.focus();
|
||||
};
|
||||
|
|
|
@ -108,6 +108,7 @@ const µBlock = (( ) => { // jshint ignore:line
|
|||
},
|
||||
|
||||
hiddenSettingsDefault: hiddenSettingsDefault,
|
||||
hiddenSettingsAdmin: {},
|
||||
hiddenSettings: Object.assign({}, hiddenSettingsDefault),
|
||||
|
||||
// Features detection.
|
||||
|
|
|
@ -1258,8 +1258,9 @@ const onMessage = function(request, sender, callback) {
|
|||
|
||||
case 'readHiddenSettings':
|
||||
response = {
|
||||
current: µb.hiddenSettings,
|
||||
default: µb.hiddenSettingsDefault,
|
||||
'default': µb.hiddenSettingsDefault,
|
||||
'admin': µb.hiddenSettingsAdmin,
|
||||
'current': µb.hiddenSettings,
|
||||
};
|
||||
break;
|
||||
|
||||
|
|
|
@ -143,10 +143,10 @@ const onNetWhitelistReady = function(netWhitelistRaw, adminExtra) {
|
|||
}
|
||||
// Append admin-controlled trusted-site directives
|
||||
if (
|
||||
Array.isArray(adminExtra.trustedSites) &&
|
||||
adminExtra.trustedSites.length !== 0
|
||||
adminExtra instanceof Object &&
|
||||
Array.isArray(adminExtra.trustedSiteDirectives)
|
||||
) {
|
||||
for ( const directive of adminExtra.trustedSites ) {
|
||||
for ( const directive of adminExtra.trustedSiteDirectives ) {
|
||||
µb.netWhitelistDefault.push(directive);
|
||||
netWhitelistRaw.push(directive);
|
||||
}
|
||||
|
@ -296,9 +296,7 @@ try {
|
|||
);
|
||||
log.info(`Backend storage for cache will be ${cacheBackend}`);
|
||||
|
||||
const adminExtra = {};
|
||||
adminExtra.trustedSites =
|
||||
await vAPI.adminStorage.get('extraTrustedSiteDirectives') || [];
|
||||
const adminExtra = await vAPI.adminStorage.get('toAdd');
|
||||
log.info(`Extra admin settings ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
|
||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/1365
|
||||
|
|
|
@ -89,29 +89,51 @@
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.loadHiddenSettings = async function() {
|
||||
const bin = await vAPI.storage.get('hiddenSettings');
|
||||
if ( bin instanceof Object === false ) { return; }
|
||||
// Admin hidden settings have precedence over user hidden settings.
|
||||
|
||||
const hs = bin.hiddenSettings;
|
||||
if ( hs instanceof Object ) {
|
||||
const hsDefault = this.hiddenSettingsDefault;
|
||||
for ( const key in hsDefault ) {
|
||||
if (
|
||||
hsDefault.hasOwnProperty(key) &&
|
||||
hs.hasOwnProperty(key) &&
|
||||
typeof hs[key] === typeof hsDefault[key]
|
||||
) {
|
||||
this.hiddenSettings[key] = hs[key];
|
||||
}
|
||||
}
|
||||
if ( typeof this.hiddenSettings.suspendTabsUntilReady === 'boolean' ) {
|
||||
this.hiddenSettings.suspendTabsUntilReady =
|
||||
this.hiddenSettings.suspendTabsUntilReady
|
||||
? 'yes'
|
||||
: 'unset';
|
||||
µBlock.loadHiddenSettings = async function() {
|
||||
const hsDefault = this.hiddenSettingsDefault;
|
||||
const hsAdmin = this.hiddenSettingsAdmin;
|
||||
const hsUser = this.hiddenSettings;
|
||||
|
||||
const results = await Promise.all([
|
||||
vAPI.adminStorage.get('toSet'),
|
||||
vAPI.storage.get('hiddenSettings'),
|
||||
]);
|
||||
|
||||
if (
|
||||
results[0] instanceof Object &&
|
||||
Array.isArray(results[0].hiddenSettings)
|
||||
) {
|
||||
for ( const entry of results[0].hiddenSettings ) {
|
||||
if ( entry.length < 1 ) { continue; }
|
||||
const name = entry[0];
|
||||
if ( hsDefault.hasOwnProperty(name) === false ) { continue; }
|
||||
const value = entry.length < 2
|
||||
? hsDefault[name]
|
||||
: this.hiddenSettingValueFromString(name, entry[1]);
|
||||
if ( value === undefined ) { continue; }
|
||||
hsDefault[name] = hsAdmin[name] = hsUser[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
const hs = results[1] instanceof Object && results[1].hiddenSettings || {};
|
||||
if ( Object.keys(hsAdmin).length === 0 && Object.keys(hs).length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( const key in hsDefault ) {
|
||||
if ( hsDefault.hasOwnProperty(key) === false ) { continue; }
|
||||
if ( hsAdmin.hasOwnProperty(name) ) { continue; }
|
||||
if ( typeof hs[key] !== typeof hsDefault[key] ) { continue; }
|
||||
this.hiddenSettings[key] = hs[key];
|
||||
}
|
||||
if ( typeof this.hiddenSettings.suspendTabsUntilReady === 'boolean' ) {
|
||||
this.hiddenSettings.suspendTabsUntilReady =
|
||||
this.hiddenSettings.suspendTabsUntilReady
|
||||
? 'yes'
|
||||
: 'unset';
|
||||
}
|
||||
this.fireDOMEvent('hiddenSettingsChanged');
|
||||
};
|
||||
|
||||
|
@ -162,31 +184,47 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
if ( matches === null || matches.length !== 3 ) { continue; }
|
||||
const name = matches[1];
|
||||
if ( out.hasOwnProperty(name) === false ) { continue; }
|
||||
const value = matches[2];
|
||||
switch ( typeof out[name] ) {
|
||||
case 'boolean':
|
||||
if ( value === 'true' ) {
|
||||
out[name] = true;
|
||||
} else if ( value === 'false' ) {
|
||||
out[name] = false;
|
||||
}
|
||||
break;
|
||||
case 'string':
|
||||
out[name] = value.trim();
|
||||
break;
|
||||
case 'number':
|
||||
out[name] = parseInt(value, 10);
|
||||
if ( isNaN(out[name]) ) {
|
||||
out[name] = this.hiddenSettingsDefault[name];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if ( this.hiddenSettingsAdmin.hasOwnProperty(name) ) { continue; }
|
||||
const value = this.hiddenSettingValueFromString(name, matches[2]);
|
||||
if ( value !== undefined ) {
|
||||
out[name] = value;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
µBlock.hiddenSettingValueFromString = function(name, value) {
|
||||
if ( typeof name !== 'string' || typeof value !== 'string' ) { return; }
|
||||
const hsDefault = this.hiddenSettingsDefault;
|
||||
if ( hsDefault.hasOwnProperty(name) === false ) { return; }
|
||||
let r;
|
||||
switch ( typeof hsDefault[name] ) {
|
||||
case 'boolean':
|
||||
if ( value === 'true' ) {
|
||||
r = true;
|
||||
} else if ( value === 'false' ) {
|
||||
r = false;
|
||||
}
|
||||
break;
|
||||
case 'string':
|
||||
r = value.trim();
|
||||
break;
|
||||
case 'number':
|
||||
if ( value.startsWith('0b') ) {
|
||||
r = parseInt(value.slice(2), 2);
|
||||
} else if ( value.startsWith('0x') ) {
|
||||
r = parseInt(value.slice(2), 16);
|
||||
} else {
|
||||
r = parseInt(value, 10);
|
||||
}
|
||||
if ( isNaN(r) ) { r = undefined; }
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
};
|
||||
|
||||
µBlock.stringFromHiddenSettings = function() {
|
||||
const out = [];
|
||||
for ( const key of Object.keys(this.hiddenSettings).sort() ) {
|
||||
|
@ -1222,9 +1260,17 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
// values are left to the user's choice.
|
||||
|
||||
µBlock.restoreAdminSettings = async function() {
|
||||
let toSet = {};
|
||||
let data;
|
||||
try {
|
||||
const json = await vAPI.adminStorage.get('adminSettings');
|
||||
const store = await vAPI.adminStorage.get([
|
||||
'adminSettings',
|
||||
'toSet',
|
||||
]) || {};
|
||||
if ( store.toSet instanceof Object ) {
|
||||
toSet = store.toSet;
|
||||
}
|
||||
const json = store.adminSettings;
|
||||
if ( typeof json === 'string' && json !== '' ) {
|
||||
data = JSON.parse(json);
|
||||
} else if ( json instanceof Object ) {
|
||||
|
@ -1234,7 +1280,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
console.error(ex);
|
||||
}
|
||||
|
||||
if ( data instanceof Object === false ) { return; }
|
||||
if ( data instanceof Object === false ) { data = {}; }
|
||||
|
||||
const bin = {};
|
||||
let binNotEmpty = false;
|
||||
|
@ -1269,7 +1315,11 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
|||
binNotEmpty = true;
|
||||
}
|
||||
|
||||
if ( Array.isArray(data.whitelist) ) {
|
||||
if ( Array.isArray(toSet.trustedSiteDirectives) ) {
|
||||
µBlock.netWhitelistDefault = toSet.trustedSiteDirectives.slice();
|
||||
bin.netWhitelist = toSet.trustedSiteDirectives.slice();
|
||||
binNotEmpty = true;
|
||||
} else if ( Array.isArray(data.whitelist) ) {
|
||||
bin.netWhitelist = data.whitelist;
|
||||
binNotEmpty = true;
|
||||
} else if ( typeof data.netWhitelist === 'string' ) {
|
||||
|
|
Loading…
Reference in New Issue