summaryrefslogtreecommitdiffstats
path: root/modules-available/baseconfig/inc
diff options
context:
space:
mode:
Diffstat (limited to 'modules-available/baseconfig/inc')
-rw-r--r--modules-available/baseconfig/inc/baseconfig.inc.php151
-rw-r--r--modules-available/baseconfig/inc/baseconfigutil.inc.php14
-rw-r--r--modules-available/baseconfig/inc/configholder.inc.php134
-rw-r--r--modules-available/baseconfig/inc/validator.inc.php20
4 files changed, 302 insertions, 17 deletions
diff --git a/modules-available/baseconfig/inc/baseconfig.inc.php b/modules-available/baseconfig/inc/baseconfig.inc.php
new file mode 100644
index 00000000..36622dce
--- /dev/null
+++ b/modules-available/baseconfig/inc/baseconfig.inc.php
@@ -0,0 +1,151 @@
+<?php
+
+class BaseConfig
+{
+
+ private static $modulesDone = [];
+
+ /**
+ * @var array key-value-pairs of override vars, can be accessed by hooks
+ */
+ private static $overrides = [];
+
+ /**
+ * Fill the ConfigHolder with values from various hooks, while taking
+ * into account UUID and IP-address of the client making the current
+ * HTTP request.
+ */
+ public static function prepareFromRequest()
+ {
+ $ip = $_SERVER['REMOTE_ADDR'] ?? null;
+ if ($ip === null)
+ ErrorHandler::traceError('No REMOTE_ADDR given in $_SERVER');
+ if (substr($ip, 0, 7) === '::ffff:') {
+ $ip = substr($ip, 7);
+ }
+ $uuid = Request::any('uuid', null, 'string');
+ if ($uuid !== null && strlen($uuid) !== 36) {
+ $uuid = null;
+ }
+ // Handle any hooks by other modules first
+ // other modules should generally only populate $configVars
+ foreach (glob('modules/*/baseconfig/getconfig.inc.php') as $file) {
+ preg_match('#^modules/([^/]+)/#', $file, $out);
+ ConfigHolder::setContext($out[1]);
+ self::handleModule($out[1], $ip, $uuid, false);
+ }
+ self::commonBase();
+ }
+
+ /**
+ * Fill the ConfigHolder with data from various hooks that supply
+ * static overrides for config variables. The overrides can be used
+ * to make the hooks behave in certain ways, by setting specific values like
+ * 'locationid'
+ * @param array $overrides key value pairs of overrides
+ */
+ public static function prepareWithOverrides(array $overrides): void
+ {
+ self::$overrides = $overrides;
+ $ip = $uuid = null;
+ if (self::hasOverride('ip')) {
+ $ip = self::getOverride('ip');
+ }
+ if (self::hasOverride('uuid')) {
+ $uuid = self::getOverride('uuid');
+ }
+ // Handle only static hooks that don't dynamically generate output
+ foreach (glob('modules/*/baseconfig/hook.json') as $file) {
+ preg_match('#^modules/([^/]+)/#', $file, $out);
+ ConfigHolder::setContext($out[1]);
+ self::handleModule($out[1], $ip, $uuid, true);
+ }
+ self::commonBase();
+ }
+
+ /**
+ * Just fill the ConfigHolder with the defaults from all the json files
+ * that define config variables.
+ */
+ public static function prepareDefaults()
+ {
+ $defaults = BaseConfigUtil::getVariables();
+ self::addDefaults($defaults);
+ }
+
+ private static function commonBase()
+ {
+ $defaults = BaseConfigUtil::getVariables();
+
+ // Dump global config from DB
+ ConfigHolder::setContext('<global>', function($id) {
+ return [
+ 'name' => Dictionary::translate('source-global'),
+ 'locationid' => 0,
+ ];
+ });
+ $res = Database::simpleQuery('SELECT setting, value, displayvalue FROM setting_global');
+ foreach ($res as $row) {
+ if (!isset($defaults[$row['setting']]))
+ continue; // Setting is not defined in any <module>/baseconfig/settings.json
+ ConfigHolder::add($row['setting'], $row, -1);
+ }
+
+ // Fallback to default values from json files
+ self::addDefaults($defaults);
+
+ }
+
+ private static function addDefaults($defaults)
+ {
+ ConfigHolder::setContext('<default>', function($id) {
+ return [
+ 'name' => Dictionary::translate('source-default'),
+ 'locationid' => 0,
+ ];
+ });
+ foreach ($defaults as $setting => $value) {
+ ConfigHolder::add($setting, $value['defaultvalue'], -1000);
+ }
+ }
+
+ private static function handleModule(string $name, ?string $ip, ?string $uuid, bool $needJsonHook): void
+ {
+ // Pass ip and uuid instead of global to make them read only
+ if (isset(self::$modulesDone[$name]))
+ return;
+ self::$modulesDone[$name] = true;
+ // Module has getconfig hook
+ $file = 'modules/' . $name . '/baseconfig/getconfig.inc.php';
+ if (!is_file($file))
+ return;
+ // We want only static hooks that have a json config (currently used for displaying inheritance tree)
+ if ($needJsonHook && !is_file('modules/' . $name . '/baseconfig/hook.json'))
+ return;
+ // Properly registered and can be activated
+ $mod = Module::get($name);
+ if ($mod === false)
+ return;
+ if (!$mod->activate(1, false))
+ return;
+ // Process dependencies first
+ foreach ($mod->getDependencies() as $dep) {
+ self::handleModule($dep, $ip, $uuid, $needJsonHook);
+ }
+ ConfigHolder::setContext($name);
+ (function (string $file, ?string $ip, ?string $uuid) {
+ include_once($file);
+ })($file, $ip, $uuid);
+ }
+
+ public static function hasOverride($key): bool
+ {
+ return array_key_exists($key, self::$overrides);
+ }
+
+ public static function getOverride($key)
+ {
+ return self::$overrides[$key];
+ }
+
+} \ No newline at end of file
diff --git a/modules-available/baseconfig/inc/baseconfigutil.inc.php b/modules-available/baseconfig/inc/baseconfigutil.inc.php
index a48eb93b..4d1ef8c1 100644
--- a/modules-available/baseconfig/inc/baseconfigutil.inc.php
+++ b/modules-available/baseconfig/inc/baseconfigutil.inc.php
@@ -16,7 +16,7 @@ class BaseConfigUtil
* @param \Module $module optional, only consider given module, not all enabled modules
* @return array all known config variables
*/
- public static function getVariables($module = false)
+ public static function getVariables($module = false): array
{
$settings = array();
if ($module === false) {
@@ -39,16 +39,13 @@ class BaseConfigUtil
/**
* Get configuration categories for given module, or all modules if false is passed.
- *
- * @param \Module $module
- * @return array
*/
- public static function getCategories($module = false)
+ public static function getCategories(Module $module = null): array
{
$categories = array();
- if ($module === false) {
+ if ($module === null) {
$module = '*';
- } elseif (is_object($module)) {
+ } else {
$module = $module->getIdentifier();
}
foreach (glob("modules/{$module}/baseconfig/categories.json", GLOB_NOSORT) as $file) {
@@ -70,7 +67,8 @@ class BaseConfigUtil
* @param array $vars list of vars as obtained from BaseConfigUtil::getVariables()
* @param array $values key-value-pairs of variable assignments to work with
*/
- public static function markShadowedVars(&$vars, $values) {
+ public static function markShadowedVars(array &$vars, array $values): void
+ {
foreach ($vars as $key => &$var) {
if (!isset($var['shadows']))
continue;
diff --git a/modules-available/baseconfig/inc/configholder.inc.php b/modules-available/baseconfig/inc/configholder.inc.php
new file mode 100644
index 00000000..75b43460
--- /dev/null
+++ b/modules-available/baseconfig/inc/configholder.inc.php
@@ -0,0 +1,134 @@
+<?php
+
+class ConfigHolder
+{
+ private static $config = [];
+
+ private static $context = '';
+
+ private static $postHooks = [];
+
+ public static function setContext($id, $resolver = false)
+ {
+ $tmp = ['id' => $id, 'resolver' => $resolver];
+ self::$context =& $tmp;
+ }
+
+ /**
+ * @param string $key config variable name
+ * @param false|string|array $value false to unset, string value, or array with keys value and displayvalue
+ * @param int $prio priority of this value, in case the same key gets set multiple times
+ */
+ public static function add(string $key, $value, int $prio = 0): void
+ {
+ if (!isset(self::$config[$key])) {
+ self::$config[$key] = [];
+ }
+ $new = [
+ 'prio' => $prio,
+ 'context' => &self::$context,
+ ];
+ if (is_array($value)) {
+ $new['value'] = $value['value'];
+ $new['displayvalue'] = $value['displayvalue'];
+ } else {
+ $new['value'] = $value;
+ }
+ if (empty(self::$config[$key]) || self::$config[$key][0]['prio'] > $prio) {
+ // Existing is higher, append new one
+ array_push(self::$config[$key], $new);
+ } else {
+ // New one has highest prio or matches existing, put in front
+ array_unshift(self::$config[$key], $new);
+ }
+ }
+
+ public static function get(string $key): ?string
+ {
+ if (!isset(self::$config[$key]))
+ return null;
+ return self::$config[$key][0]['value'];
+ }
+
+ public static function addPostHook(callable $func): void
+ {
+ self::$postHooks[] = array('context' => &self::$context, 'function' => $func);
+ }
+
+ public static function applyPostHooks(): void
+ {
+ foreach (self::$postHooks as $hook) {
+ $newContext = $hook['context'];
+ $newContext['post'] = true;
+ self::$context =& $newContext;
+ $hook['function']();
+ }
+ self::$postHooks = [];
+ }
+
+ public static function getRecursiveConfig(bool $prettyPrint = true): array
+ {
+ $ret = [];
+ foreach (self::$config as $key => $list) {
+ $last = false;
+ foreach ($list as $entry) {
+ if ($last !== false && $last['context']['id'] === '<global>'
+ && $entry['context']['id'] === '<default>' && $last['value'] === $entry['value'])
+ continue;
+ $cb =& $entry['context']['resolver'];
+ $valueKey = 'value';
+ if ($prettyPrint && is_callable($cb)) {
+ $data = $cb($entry['context']['id']);
+ $name = $data['name'];
+ if (isset($data['locationid']) && isset($entry['displayvalue'])
+ && User::hasPermission('.baseconfig.view', $data['locationid'])) {
+ $valueKey = 'displayvalue';
+ }
+ } else {
+ $name = $entry['context']['id'];
+ }
+ $ret[$key][] = ['name' => $name, 'value' => $entry[$valueKey]];
+ $last = $entry;
+ }
+ }
+ return $ret;
+ }
+
+ public static function outputConfig(): void
+ {
+ foreach (self::$config as $key => $list) {
+ echo str_pad('# ' . $key . ' ', 35, '#', STR_PAD_BOTH), "\n";
+ foreach ($list as $pos => $item) {
+ $ctx = $item['context']['id'];
+ if (isset($item['context']['post'])) {
+ $ctx .= '[post-hook]';
+ }
+ $ctx .= ' :: ' . $item['prio'];
+ if ($pos != 0 || $item['value'] === false) {
+ echo '# (', $ctx, ')';
+ if ($pos == 0) {
+ echo " <disabled this setting>\n";
+ } else {
+ echo " <overridden>\n";
+ }
+ } else {
+ echo $key, "='", self::escape($item['value']), "'\n";
+ echo '# (', $ctx, ") <active>\n";
+ }
+ }
+ }
+ }
+
+ /**
+ * Escape given string so it is a valid string in sh that can be surrounded
+ * by single quotes ('). This basically turns _'_ into _'"'"'_
+ *
+ * @param string $string input
+ * @return string escaped sh string
+ */
+ private static function escape(string $string): string
+ {
+ return str_replace(["'", "\n", "\r"], ["'\"'\"'", ' ', ' '], $string);
+ }
+
+}
diff --git a/modules-available/baseconfig/inc/validator.inc.php b/modules-available/baseconfig/inc/validator.inc.php
index 2dfeed7c..be71c3df 100644
--- a/modules-available/baseconfig/inc/validator.inc.php
+++ b/modules-available/baseconfig/inc/validator.inc.php
@@ -32,11 +32,12 @@ class Validator
case 'multilist':
return self::validateMultiList($data[1], $displayValue);
case 'multiinput':
- return self::validateMultiInput($data[1], $displayValue);
+ return self::validateMultiInput($data[1] ?? [], $displayValue);
+ case 'suggestions':
+ return true;
default:
- Util::traceError('Unknown validation method: ' . $data[0]);
+ ErrorHandler::traceError('Unknown validation method: ' . $data[0]);
}
- return false; // make code inspector happy - doesn't know traceError doesn't return
}
@@ -44,10 +45,10 @@ class Validator
* Validate linux password. If already in $6$ hash form,
* the unchanged value will be returned.
* if empty, an empty string will also be returned.
- * Otherwise it it assumed that the value is a plain text
+ * Otherwise, it is assumed that the value is a plain text
* password that is supposed to be hashed.
*/
- private static function linuxPassword(&$displayValue)
+ private static function linuxPassword($displayValue)
{
if (empty($displayValue))
return '';
@@ -62,7 +63,7 @@ class Validator
* @param string $displayValue network path
* @return string cleaned up path
*/
- private static function networkShare(&$displayValue)
+ private static function networkShare(string &$displayValue): string
{
$displayValue = trim($displayValue);
if (substr($displayValue, 0, 2) === '\\\\')
@@ -75,18 +76,19 @@ class Validator
/**
* Validate value against list.
+ *
* @param string $list The list as a string of items, separated by "|"
* @param string $displayValue The value to validate
* @return boolean|string The value, if in list, false otherwise
*/
- private static function validateList($list, &$displayValue)
+ private static function validateList(string $list, string $displayValue)
{
$list = explode('|', $list);
if (in_array($displayValue, $list))
return $displayValue;
return false;
}
- private static function validateMultiList($list, &$displayValue)
+ private static function validateMultiList(string $list, array &$displayValue): string
{
$allowedValues = explode('|', $list);
$values = [];
@@ -99,7 +101,7 @@ class Validator
return $displayValue;
}
- private static function validateMultiInput($list, &$displayValue)
+ private static function validateMultiInput($list, $displayValue)
{
return $displayValue;
}