2021-01-19 16:37:12 +00:00
|
|
|
'use strict';
|
2021-02-03 18:31:42 -05:00
|
|
|
|
2020-11-23 13:24:19 -05:00
|
|
|
const defs = require('./plugin_defs');
|
2012-05-28 18:39:32 -07:00
|
|
|
|
2020-10-04 18:26:05 -04:00
|
|
|
const disabledHookReasons = {
|
|
|
|
hooks: {
|
|
|
|
indexCustomInlineScripts: 'The hook makes it impossible to use a Content Security Policy ' +
|
|
|
|
'that prohibits inline code. Permitting inline code makes XSS vulnerabilities more likely',
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2021-01-19 16:37:12 +00:00
|
|
|
const loadFn = (path, hookName) => {
|
2020-11-23 13:24:19 -05:00
|
|
|
let functionName;
|
|
|
|
const parts = path.split(':');
|
2012-05-28 18:39:32 -07:00
|
|
|
|
|
|
|
// on windows: C:\foo\bar:xyz
|
2021-01-19 16:37:12 +00:00
|
|
|
if (parts[0].length === 1) {
|
|
|
|
if (parts.length === 3) {
|
2012-05-28 18:39:32 -07:00
|
|
|
functionName = parts.pop();
|
|
|
|
}
|
2020-11-23 13:24:19 -05:00
|
|
|
path = parts.join(':');
|
2012-05-28 18:39:32 -07:00
|
|
|
} else {
|
|
|
|
path = parts[0];
|
|
|
|
functionName = parts[1];
|
|
|
|
}
|
|
|
|
|
2020-11-23 13:24:19 -05:00
|
|
|
let fn = require(path);
|
2012-05-28 18:39:32 -07:00
|
|
|
functionName = functionName ? functionName : hookName;
|
|
|
|
|
2021-02-03 18:31:42 -05:00
|
|
|
for (const name of functionName.split('.')) {
|
2012-05-28 18:39:32 -07:00
|
|
|
fn = fn[name];
|
2021-02-03 18:31:42 -05:00
|
|
|
}
|
2012-05-28 18:39:32 -07:00
|
|
|
return fn;
|
2021-01-19 16:37:12 +00:00
|
|
|
};
|
2012-05-28 18:39:32 -07:00
|
|
|
|
2021-02-03 18:31:42 -05:00
|
|
|
const extractHooks = (parts, hookSetName, normalizer) => {
|
2020-11-23 13:24:19 -05:00
|
|
|
const hooks = {};
|
2021-02-03 18:31:42 -05:00
|
|
|
for (const part of parts) {
|
|
|
|
for (const [hookName, regHookFnName] of Object.entries(part[hookSetName] || {})) {
|
|
|
|
/* On the server side, you can't just
|
2012-05-28 18:39:32 -07:00
|
|
|
* require("pluginname/whatever") if the plugin is installed as
|
|
|
|
* a dependency of another plugin! Bah, pesky little details of
|
|
|
|
* npm... */
|
2021-02-03 18:31:42 -05:00
|
|
|
const hookFnName = normalizer ? normalizer(part, regHookFnName, hookName) : regHookFnName;
|
2012-05-28 18:39:32 -07:00
|
|
|
|
2021-02-03 18:31:42 -05:00
|
|
|
const disabledReason = (disabledHookReasons[hookSetName] || {})[hookName];
|
|
|
|
if (disabledReason) {
|
|
|
|
console.error(`Hook ${hookSetName}/${hookName} is disabled. Reason: ${disabledReason}`);
|
|
|
|
console.error(`The hook function ${hookFnName} from plugin ${part.plugin} ` +
|
|
|
|
'will never be called, which may cause the plugin to fail');
|
|
|
|
console.error(`Please update the ${part.plugin} plugin to not use the ${hookName} hook`);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let hookFn;
|
|
|
|
try {
|
|
|
|
hookFn = loadFn(hookFnName, hookName);
|
|
|
|
if (!hookFn) throw new Error('Not a function');
|
|
|
|
} catch (exc) {
|
|
|
|
console.error(`Failed to load '${hookFnName}' for ` +
|
|
|
|
`'${part.full_name}/${hookSetName}/${hookName}': ${exc.toString()}`);
|
|
|
|
}
|
|
|
|
if (hookFn) {
|
|
|
|
if (hooks[hookName] == null) hooks[hookName] = [];
|
|
|
|
hooks[hookName].push({
|
|
|
|
hook_name: hookName,
|
|
|
|
hook_fn: hookFn,
|
|
|
|
hook_fn_name: hookFnName,
|
|
|
|
part,
|
2020-11-23 13:24:19 -05:00
|
|
|
});
|
2021-02-03 18:31:42 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-05-28 18:39:32 -07:00
|
|
|
return hooks;
|
2021-01-19 16:37:12 +00:00
|
|
|
};
|
2012-05-28 18:39:32 -07:00
|
|
|
|
|
|
|
exports.extractHooks = extractHooks;
|
2020-09-06 15:27:18 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns an array containing the names of the installed client-side plugins
|
|
|
|
*
|
|
|
|
* If no client-side plugins are installed, returns an empty array.
|
|
|
|
* Duplicate names are always discarded.
|
|
|
|
*
|
|
|
|
* A client-side plugin is a plugin that implements at least one client_hook
|
|
|
|
*
|
|
|
|
* EXAMPLE:
|
|
|
|
* No plugins: []
|
|
|
|
* Some plugins: [ 'ep_adminpads', 'ep_add_buttons', 'ep_activepads' ]
|
|
|
|
*/
|
2021-01-19 16:37:12 +00:00
|
|
|
exports.clientPluginNames = () => {
|
2021-02-03 18:31:42 -05:00
|
|
|
const clientPluginNames = defs.parts
|
|
|
|
.filter((part) => Object.prototype.hasOwnProperty.call(part, 'client_hooks'))
|
|
|
|
.map((part) => `plugin-${part.plugin}`);
|
|
|
|
return [...new Set(clientPluginNames)];
|
2020-11-23 13:24:19 -05:00
|
|
|
};
|