158 lines
4.5 KiB
JavaScript
158 lines
4.5 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
const PREF_LOGLEVEL = "browser.policies.loglevel";
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineLazyGetter(lazy, "log", () => {
|
|
let { ConsoleAPI } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/Console.sys.mjs"
|
|
);
|
|
return new ConsoleAPI({
|
|
prefix: "macOSPoliciesParser",
|
|
// tip: set maxLogLevel to "debug" and use log.debug() to create detailed
|
|
// messages during development. See LOG_LEVELS in Console.sys.mjs for details.
|
|
maxLogLevel: "error",
|
|
maxLogLevelPref: PREF_LOGLEVEL,
|
|
});
|
|
});
|
|
|
|
export var macOSPoliciesParser = {
|
|
readPolicies(reader) {
|
|
let nativePolicies = reader.readPreferences();
|
|
if (!nativePolicies) {
|
|
return null;
|
|
}
|
|
|
|
nativePolicies = this.unflatten(nativePolicies);
|
|
nativePolicies = this.removeUnknownPolicies(nativePolicies);
|
|
|
|
// Need an extra check here so we don't
|
|
// JSON.stringify if we aren't in debug mode
|
|
if (lazy.log.maxLogLevel == "debug") {
|
|
lazy.log.debug(JSON.stringify(nativePolicies, null, 2));
|
|
}
|
|
|
|
return nativePolicies;
|
|
},
|
|
|
|
removeUnknownPolicies(policies) {
|
|
let { schema } = ChromeUtils.importESModule(
|
|
"resource:///modules/policies/schema.sys.mjs"
|
|
);
|
|
|
|
for (let policyName of Object.keys(policies)) {
|
|
if (!schema.properties.hasOwnProperty(policyName)) {
|
|
lazy.log.debug(`Removing unknown policy: ${policyName}`);
|
|
delete policies[policyName];
|
|
}
|
|
}
|
|
|
|
return policies;
|
|
},
|
|
|
|
unflatten(input, delimiter = "__") {
|
|
let ret = {};
|
|
|
|
for (let key of Object.keys(input)) {
|
|
if (!key.includes(delimiter)) {
|
|
// Short-circuit for policies that are not specified in
|
|
// the flat format.
|
|
ret[key] = input[key];
|
|
continue;
|
|
}
|
|
|
|
lazy.log.debug(`Unflattening policy key "${key}".`);
|
|
|
|
let subkeys = key.split(delimiter);
|
|
|
|
// `obj`: is the intermediate step into the unflattened
|
|
// return object. For example, for an input:
|
|
//
|
|
// Foo__Bar__Baz: 5,
|
|
//
|
|
// when the subkey being iterated is Bar, then `obj` will be
|
|
// the Bar object being constructed, as represented below:
|
|
//
|
|
// ret = {
|
|
// Foo = {
|
|
// Bar = { <---- obj
|
|
// Baz: 5,
|
|
// }
|
|
// }
|
|
// }
|
|
let obj = ret;
|
|
|
|
// Iterate until the second to last subkey, as the last one
|
|
// needs special handling afterwards.
|
|
for (let i = 0; i < subkeys.length - 1; i++) {
|
|
let subkey = subkeys[i];
|
|
|
|
if (!isValidSubkey(subkey)) {
|
|
lazy.log.error(
|
|
`Error in key ${key}: can't use indexes bigger than 50.`
|
|
);
|
|
continue;
|
|
}
|
|
|
|
if (!obj[subkey]) {
|
|
// if this subkey hasn't been seen yet, create the object
|
|
// for it, which could be an array if the next subkey is
|
|
// a number.
|
|
//
|
|
// For example, in the following examples:
|
|
// A)
|
|
// Foo__Bar__0
|
|
// Foo__Bar__1
|
|
//
|
|
// B)
|
|
// Foo__Bar__Baz
|
|
// Foo__Bar__Qux
|
|
//
|
|
// If the subkey being analysed right now is Bar, then in example A
|
|
// we'll create an array to accomodate the numeric entries.
|
|
// Otherwise, if it's example B, we'll create an object to host all
|
|
// the named keys.
|
|
if (Number.isInteger(Number(subkeys[i + 1]))) {
|
|
obj[subkey] = [];
|
|
} else {
|
|
obj[subkey] = {};
|
|
}
|
|
}
|
|
|
|
obj = obj[subkey];
|
|
}
|
|
|
|
let lastSubkey = subkeys[subkeys.length - 1];
|
|
if (!isValidSubkey(lastSubkey)) {
|
|
lazy.log.error(
|
|
`Error in key ${key}: can't use indexes bigger than 50.`
|
|
);
|
|
continue;
|
|
}
|
|
|
|
// In the last subkey, we assign it the value by accessing the input
|
|
// object again with the full key. For example, in the case:
|
|
//
|
|
// input = {"Foo__Bar__Baz": 5}
|
|
//
|
|
// what we're doing in practice is:
|
|
//
|
|
// ret["Foo"]["Bar"]["Baz"] = input["Foo__Bar__Baz"];
|
|
// \_______ _______/ |
|
|
// v |
|
|
// obj last subkey
|
|
|
|
obj[lastSubkey] = input[key];
|
|
}
|
|
|
|
return ret;
|
|
},
|
|
};
|
|
|
|
function isValidSubkey(subkey) {
|
|
let valueAsNumber = Number(subkey);
|
|
return Number.isNaN(valueAsNumber) || valueAsNumber <= 50;
|
|
}
|