summaryrefslogtreecommitdiffstats
path: root/modules-available/sysconfig
diff options
context:
space:
mode:
Diffstat (limited to 'modules-available/sysconfig')
-rw-r--r--modules-available/sysconfig/addconfig.inc.php54
-rw-r--r--modules-available/sysconfig/addmodule.inc.php58
-rw-r--r--modules-available/sysconfig/addmodule_adauth.inc.php57
-rw-r--r--modules-available/sysconfig/addmodule_branding.inc.php83
-rw-r--r--modules-available/sysconfig/addmodule_custommodule.inc.php75
-rw-r--r--modules-available/sysconfig/addmodule_ldapauth.inc.php42
-rw-r--r--modules-available/sysconfig/addmodule_screensaver.inc.php80
-rw-r--r--modules-available/sysconfig/addmodule_sshconfig.inc.php39
-rw-r--r--modules-available/sysconfig/addmodule_sshkey.inc.php72
-rw-r--r--modules-available/sysconfig/api.inc.php8
-rw-r--r--modules-available/sysconfig/clientscript.js57
-rw-r--r--modules-available/sysconfig/hooks/bootup.inc.php3
-rw-r--r--modules-available/sysconfig/hooks/locations-column.inc.php57
-rw-r--r--modules-available/sysconfig/inc/configmodule.inc.php236
-rw-r--r--modules-available/sysconfig/inc/configmodule/branding.inc.php20
-rw-r--r--modules-available/sysconfig/inc/configmodule/customodule.inc.php36
-rw-r--r--modules-available/sysconfig/inc/configmodule/ldapauth.inc.php2
-rw-r--r--modules-available/sysconfig/inc/configmodule/screensaver.inc.php29
-rw-r--r--modules-available/sysconfig/inc/configmodule/sshconfig.inc.php40
-rw-r--r--modules-available/sysconfig/inc/configmodule/sshkey.inc.php55
-rw-r--r--modules-available/sysconfig/inc/configmodulebaseldap.inc.php35
-rw-r--r--modules-available/sysconfig/inc/configtgz.inc.php253
-rw-r--r--modules-available/sysconfig/inc/ldap.inc.php2
-rw-r--r--modules-available/sysconfig/inc/ppd.inc.php249
-rw-r--r--modules-available/sysconfig/inc/sysconfig.inc.php31
-rw-r--r--modules-available/sysconfig/install.inc.php66
-rw-r--r--modules-available/sysconfig/lang/de/config-module.json9
-rw-r--r--modules-available/sysconfig/lang/de/module.json20
-rw-r--r--modules-available/sysconfig/lang/de/template-tags.json47
-rw-r--r--modules-available/sysconfig/lang/en/config-module.json9
-rw-r--r--modules-available/sysconfig/lang/en/module.json20
-rw-r--r--modules-available/sysconfig/lang/en/template-tags.json43
-rw-r--r--modules-available/sysconfig/page.inc.php61
-rw-r--r--modules-available/sysconfig/templates/ad-selfsearch.html2
-rw-r--r--modules-available/sysconfig/templates/ad-start.html12
-rw-r--r--modules-available/sysconfig/templates/ad_ldap-checkconnection.html2
-rw-r--r--modules-available/sysconfig/templates/ad_ldap-checkcredentials.html3
-rw-r--r--modules-available/sysconfig/templates/ad_ldap-homedir.html1
-rw-r--r--modules-available/sysconfig/templates/branding-check.html2
-rw-r--r--modules-available/sysconfig/templates/branding-start.html2
-rw-r--r--modules-available/sysconfig/templates/cfg-start.html2
-rw-r--r--modules-available/sysconfig/templates/custom-filelist.html18
-rw-r--r--modules-available/sysconfig/templates/custom-fileselect.html36
-rw-r--r--modules-available/sysconfig/templates/ldap-finish.html1
-rw-r--r--modules-available/sysconfig/templates/ldap-start.html12
-rw-r--r--modules-available/sysconfig/templates/list-configs.html16
-rw-r--r--modules-available/sysconfig/templates/list-legend.html4
-rw-r--r--modules-available/sysconfig/templates/list-modules.html13
-rw-r--r--modules-available/sysconfig/templates/sshconfig-start.html38
-rw-r--r--modules-available/sysconfig/templates/sshkey-start.html21
50 files changed, 1245 insertions, 888 deletions
diff --git a/modules-available/sysconfig/addconfig.inc.php b/modules-available/sysconfig/addconfig.inc.php
index a22cdc46..27af31e8 100644
--- a/modules-available/sysconfig/addconfig.inc.php
+++ b/modules-available/sysconfig/addconfig.inc.php
@@ -9,21 +9,17 @@ abstract class AddConfig_Base
/**
* Holds the instance for the currently executing step
- * @var \AddConfig_Base
+ * @var AddConfig_Base
*/
- private static $instance = false;
+ private static $instance = null;
/**
* Config being edited (if any)
- * @var \ConfigTgz
+ * @var ?ConfigTgz
*/
- protected $edit = false;
+ protected $edit = null;
- /**
- *
- * @param string $step
- */
- public static function setStep($step)
+ public static function setStep(string $step)
{
if (empty($step) || !class_exists($step) || get_parent_class($step) !== 'AddConfig_Base') {
Message::addError('invalid-action', $step);
@@ -32,18 +28,12 @@ abstract class AddConfig_Base
self::$instance = new $step();
if (($editId = Request::any('edit', 0, 'int')) !== 0) {
self::$instance->edit = ConfigTgz::get($editId);
- if (self::$instance->edit === false)
- Util::traceError('Invalid config id for editing');
+ if (self::$instance->edit === null)
+ ErrorHandler::traceError('Invalid config id for editing');
Util::addRedirectParam('edit', self::$instance->edit->id());
}
}
- protected function tmError()
- {
- Message::addError('main.taskmanager-error');
- Util::redirect('?do=SysConfig');
- }
-
/**
* Called before any HTML rendering happens, so you can
* prepare stuff, validate input, and optionally redirect
@@ -73,25 +63,25 @@ abstract class AddConfig_Base
public static function preprocess()
{
- if (self::$instance === false) {
- Util::traceError('No step instance yet');
+ if (self::$instance === null) {
+ ErrorHandler::traceError('No step instance yet');
}
self::$instance->preprocessInternal();
}
public static function render()
{
- if (self::$instance === false)
- Util::traceError('No step instance yet');
- if (self::$instance->edit !== false)
+ if (self::$instance === null)
+ ErrorHandler::traceError('No step instance yet');
+ if (self::$instance->edit !== null)
Message::addInfo('replacing-config', self::$instance->edit->title());
self::$instance->renderInternal();
}
public static function ajax()
{
- if (self::$instance === false) {
- Util::traceError('No step instance yet');
+ if (self::$instance === null) {
+ ErrorHandler::traceError('No step instance yet');
}
self::$instance->ajaxInternal();
}
@@ -110,7 +100,7 @@ class AddConfig_Start extends AddConfig_Base
$mods = ConfigModule::getList();
$res = Database::simpleQuery("SELECT moduleid, title, moduletype, filepath FROM configtgz_module"
. " ORDER BY title ASC"); // Move to ConfigModule
- if ($this->edit === false) {
+ if ($this->edit === null) {
$active = array();
} else {
$active = $this->edit->getModuleIds();
@@ -122,7 +112,7 @@ class AddConfig_Start extends AddConfig_Base
$modGroups[$mod['group']] =& $mod;
}
unset($mod);
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
if (!isset($mods[$row['moduletype']])) {
$mods[$row['moduletype']] = array(
'unique' => false,
@@ -140,7 +130,7 @@ class AddConfig_Start extends AddConfig_Base
$row['active'] = in_array($row['moduleid'], $active);
$group['modules'][] = $row;
}
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
$title = $this->edit->title();
} else {
$title = Request::any('title', '', 'string');
@@ -162,7 +152,7 @@ class AddConfig_Start extends AddConfig_Base
'step' => 'AddConfig_Finish',
'groups' => array_values($modGroups),
'title' => $title,
- 'edit' => ($this->edit !== false ? $this->edit->id() : false)
+ 'edit' => $this->edit === null ? null : $this->edit->id(),
));
}
@@ -174,9 +164,9 @@ class AddConfig_Start extends AddConfig_Base
class AddConfig_Finish extends AddConfig_Base
{
/**
- * @var ConfigTgz
+ * @var ?ConfigTgz
*/
- private $config = false;
+ private $config = null;
protected function preprocessInternal()
{
@@ -186,13 +176,13 @@ class AddConfig_Finish extends AddConfig_Base
Message::addError('missing-file');
Util::redirect('?do=SysConfig&action=addconfig');
}
- if ($this->edit === false) {
+ if ($this->edit === null) {
$this->config = ConfigTgz::insert($title, $modules);
} else {
$this->edit->update($title, $modules);
$this->config = $this->edit;
}
- if ($this->config === false || $this->config->generate(true, 150) === false) {
+ if ($this->config->generate(true, 150) === false) {
Message::addError('unsuccessful-action');
Util::redirect('?do=SysConfig&action=addconfig');
}
diff --git a/modules-available/sysconfig/addmodule.inc.php b/modules-available/sysconfig/addmodule.inc.php
index 91fee45d..4564537e 100644
--- a/modules-available/sysconfig/addmodule.inc.php
+++ b/modules-available/sysconfig/addmodule.inc.php
@@ -9,34 +9,39 @@ abstract class AddModule_Base
/**
* Holds the instance for the currently executing step
- * @var \AddModule_Base
+ *
+ * @var AddModule_Base
*/
private static $instance = false;
/**
* Instance of ConfigModule we're editing. False if not editing but creating.
- * @var \ConfigModule
+ *
+ * @var ?ConfigModule
*/
- protected $edit = false;
+ protected $edit = null;
/**
*
* @param string $step name of class representing the current step
* @param int $editId (optional) overwrite for the request parameter 'edit'
*/
- public static function setStep($step, $editId = false)
+ public static function setStep(string $step, int $editId = null): void
{
if (empty($step) || !class_exists($step) || get_parent_class($step) !== 'AddModule_Base') {
Message::addError('invalid-action', $step);
Util::redirect('?do=SysConfig');
}
self::$instance = new $step();
- if ($editId = $editId ? $editId : Request::any('edit')) {
+ if ($editId === null) {
+ $editId = Request::any('edit', 0, 'int');
+ }
+ if ($editId !== 0) {
self::$instance->edit = ConfigModule::get($editId);
- if (self::$instance->edit === false)
- Util::traceError('Invalid module id for editing');
+ if (self::$instance->edit === null)
+ ErrorHandler::traceError('Invalid module id for editing');
if ($step !== 'AddModule_Assign' && !preg_match('/^' . self::$instance->edit->moduleType() . '_/', $step))
- Util::traceError('Module to edit is of different type!');
+ ErrorHandler::traceError('Module to edit is of different type!');
Util::addRedirectParam('edit', self::$instance->edit->id());
}
}
@@ -90,7 +95,7 @@ abstract class AddModule_Base
public static function preprocess()
{
if (self::$instance === false) {
- Util::traceError('No step instance yet');
+ ErrorHandler::traceError('No step instance yet');
}
self::$instance->preprocessInternal();
}
@@ -98,9 +103,9 @@ abstract class AddModule_Base
public static function render()
{
if (self::$instance === false) {
- Util::traceError('No step instance yet');
+ ErrorHandler::traceError('No step instance yet');
}
- if (get_class(self::$instance) !== 'AddModule_Assign' && self::$instance->edit !== false) {
+ if (get_class(self::$instance) !== 'AddModule_Assign' && self::$instance->edit !== null) {
Message::addInfo('replacing-module', self::$instance->edit->title());
}
self::$instance->renderInternal();
@@ -109,7 +114,7 @@ abstract class AddModule_Base
public static function ajax()
{
if (self::$instance === false) {
- Util::traceError('No step instance yet');
+ ErrorHandler::traceError('No step instance yet');
}
self::$instance->ajaxInternal();
}
@@ -155,7 +160,7 @@ class AddModule_Assign extends AddModule_Base
if (ConfigModule::getList()[$moduleType]['unique']) {
$moduleIds = [];
- foreach (ConfigModule::getAll($moduleType) as $module) {
+ foreach (ConfigModule::getAll($moduleType) ?? [] as $module) {
$moduleIds[] = $module->id();
}
@@ -209,41 +214,26 @@ class AddModule_Assign extends AddModule_Base
* Helper functions to set/get a batch of vars from/to post variables or a module
*/
-/**
- *
- * @param \ConfigModule $module
- * @param array $array
- * @param array $keys
- */
-function moduleToArray($module, &$array, $keys)
+function moduleToArray(ConfigModule $module, array &$array, array $keys): void
{
foreach ($keys as $key) {
$array[$key] = $module->getData($key);
}
}
-/**
- *
- * @param \ConfigModule $module
- * @param array $array
- * @param array $keys
- */
-function arrayToModule($module, $array, $keys)
+function arrayToModule(ConfigModule $module, array $array, array $keys): void
{
foreach ($keys as $key) {
$module->setData($key, $array[$key]);
}
}
-/**
- *
- * @param array $array
- * @param array $keys
- */
-function postToArray(&$array, $keys, $ignoreMissing = false)
+
+function postToArray(array &$array, array $keys, $ignoreMissing = false): void
{
foreach ($keys as $key) {
$val = Request::post($key, '--not-in-post');
- if ($ignoreMissing && $val === '--not-in-post') continue;
+ if ($ignoreMissing && $val === '--not-in-post')
+ continue;
$array[$key] = $val;
}
}
diff --git a/modules-available/sysconfig/addmodule_adauth.inc.php b/modules-available/sysconfig/addmodule_adauth.inc.php
index 583844d0..42187171 100644
--- a/modules-available/sysconfig/addmodule_adauth.inc.php
+++ b/modules-available/sysconfig/addmodule_adauth.inc.php
@@ -13,15 +13,12 @@ class AdAuth_Start extends AddModule_Base
protected function renderInternal()
{
- $ADAUTH_COMMON_FIELDS = array('title', 'server', 'searchbase', 'binddn', 'bindpw', 'home', 'homeattr', 'ssl', 'fixnumeric', 'genuid', 'certificate', 'mapping', 'nohomewarn');
+ $ADAUTH_COMMON_FIELDS = array('title', 'server', 'searchbase', 'binddn', 'bindpw', 'home', 'homeattr', 'ssl', 'genuid', 'certificate', 'mapping', 'nohomewarn');
$data = array();
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
moduleToArray($this->edit, $data, $ADAUTH_COMMON_FIELDS);
$data['title'] = $this->edit->title();
$data['edit'] = $this->edit->id();
- if (!isset($data['fixnumeric']) || $data['fixnumeric'] === false) {
- $data['fixnumeric'] = 's';
- }
} else {
$data['ssl'] = true;
}
@@ -38,7 +35,7 @@ class AdAuth_Start extends AddModule_Base
}
$data['step'] = 'AdAuth_CheckConnection';
$data['map_empty'] = true;
- $data['mapping'] = ConfigModuleBaseLdap::getMapping(isset($data['mapping']) ? $data['mapping'] : false, $data['map_empty']);
+ $data['mapping'] = ConfigModuleBaseLdap::getMapping($data['mapping'] ?? null, $data['map_empty']);
Render::addDialog(Dictionary::translateFile('config-module', 'adAuth_title'), false, 'ad-start', $data);
}
@@ -92,13 +89,12 @@ class AdAuth_CheckConnection extends AddModule_Base
));
if (!isset($this->scanTask['id'])) {
AddModule_Base::setStep('AdAuth_Start'); // Continues with AdAuth_Start for render()
- return;
}
}
protected function renderInternal()
{
- $mapping = Request::post('mapping', false, 'array');
+ $mapping = Request::post('mapping', null, 'array');
$data = array(
'edit' => Request::post('edit'),
'title' => Request::post('title'),
@@ -108,7 +104,6 @@ class AdAuth_CheckConnection extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl'),
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'certificate' => Request::post('certificate', ''),
'taskid' => $this->scanTask['id'],
@@ -135,7 +130,7 @@ class AdAuth_SelfSearch extends AddModule_Base
protected function preprocessInternal()
{
- $server = $binddn = $port = null;
+ $server = $binddn = null;
$searchbase = Request::post('searchbase', '');
$bindpw = Request::post('bindpw');
$ssl = Request::post('ssl', 'off') === 'on';
@@ -144,14 +139,8 @@ class AdAuth_SelfSearch extends AddModule_Base
AddModule_Base::setStep('AdAuth_Start'); // Continues with AdAuth_Start for render()
return;
}
- foreach (['server', 'binddn', 'port'] as $var) {
- $$var = Request::post($var, null);
- if (empty($$var)) {
- Message::addError('main.parameter-empty', $var);
- AddModule_Base::setStep('AdAuth_Start'); // Continues with AdAuth_Start for render()
- return;
- }
- }
+ $server = Request::post('server', Request::REQUIRED, 'string');
+ $binddn = Request::post('binddn', Request::REQUIRED, 'string');
$this->originalBindDn = '';
// Fix bindDN if short name given
//
@@ -199,7 +188,7 @@ class AdAuth_SelfSearch extends AddModule_Base
protected function renderInternal()
{
- $mapping = Request::post('mapping', false, 'array');
+ $mapping = Request::post('mapping', null, 'array');
$data = array(
'edit' => Request::post('edit'),
'title' => Request::post('title'),
@@ -210,7 +199,6 @@ class AdAuth_SelfSearch extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
@@ -288,13 +276,12 @@ class AdAuth_HomeAttrCheck extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
'originalbinddn' => Request::post('originalbinddn'),
'tryHomeAttr' => true,
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
'prev' => 'AdAuth_Start',
'next' => 'AdAuth_CheckCredentials'
))
@@ -361,12 +348,11 @@ class AdAuth_CheckCredentials extends AddModule_Base
'home' => Request::post('home'),
'homeattr' => Request::post('homeattr'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
'originalbinddn' => Request::post('originalbinddn'),
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
'prev' => 'AdAuth_Start',
'next' => 'AdAuth_HomeDir'
))
@@ -426,16 +412,15 @@ class AdAuth_HomeDir extends AddModule_Base
'home' => Request::post('home'),
'homeattr' => Request::post('homeattr'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
'originalbinddn' => Request::post('originalbinddn'),
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
'prev' => 'AdAuth_Start',
'next' => 'AdAuth_Finish'
);
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
foreach (self::getAttributes() as $key) {
if ($this->edit->getData($key)) {
$data[$key . '_c'] = 'checked="checked"';
@@ -456,13 +441,13 @@ class AdAuth_HomeDir extends AddModule_Base
foreach (range('D', 'Z') as $l) {
$data['drives'][] = array(
'drive' => $l . ':',
- 'selected' => (strtoupper($letter{0}) === $l) ? 'selected="selected"' : ''
+ 'selected' => (strtoupper($letter[0]) === $l) ? 'selected="selected"' : ''
);
}
Render::addDialog(Dictionary::translateFile('config-module', 'adAuth_title'), false, 'ad_ldap-homedir', $data);
}
- public static function getAttributes()
+ public static function getAttributes(): array
{
return array('shareRemapMode', 'shareRemapCreate', 'shareDocuments', 'shareDownloads', 'shareDesktop',
'shareMedia', 'shareOther', 'shareHomeDrive', 'shareDomain', 'credentialPassthrough');
@@ -480,12 +465,13 @@ class AdAuth_Finish extends AddModule_Base
$title = Request::post('title');
if (empty($title))
$title = 'AD: ' . Request::post('server');
- if ($this->edit === false)
+ if ($this->edit === null) {
$module = ConfigModule::getInstance('AdAuth');
- else
+ } else {
$module = $this->edit;
+ }
$ssl = Request::post('ssl', 'off') === 'on';
- foreach (['searchbase', 'binddn', 'server', 'bindpw', 'home', 'nohomewarn', 'homeattr', 'certificate', 'fixnumeric', 'genuid',
+ foreach (['searchbase', 'binddn', 'server', 'bindpw', 'home', 'nohomewarn', 'homeattr', 'certificate', 'genuid',
'ldapAttrMountOpts', 'shareHomeMountOpts'] as $key) {
$module->setData($key, Request::post($key, '', 'string'));
}
@@ -507,7 +493,7 @@ class AdAuth_Finish extends AddModule_Base
} else {
$module->setData('fingerprint', '');
}
- if ($this->edit !== false)
+ if ($this->edit !== null)
$ret = $module->update($title);
else
$ret = $module->insert($title);
@@ -515,7 +501,7 @@ class AdAuth_Finish extends AddModule_Base
Message::addError('main.value-invalid', 'any', 'any');
$tgz = false;
} else {
- $tgz = $module->generate($this->edit === false);
+ $tgz = $module->generate($this->edit === null);
}
if ($tgz === false) {
AddModule_Base::setStep('AdAuth_Start'); // Continues with AdAuth_Start for render()
@@ -525,9 +511,8 @@ class AdAuth_Finish extends AddModule_Base
'tm-config' => $tgz,
);
- if ($this->edit === false) {
+ if ($this->edit === null) {
AddModule_Base::setStep('AddModule_Assign', $module->id());
- return;
}
}
diff --git a/modules-available/sysconfig/addmodule_branding.inc.php b/modules-available/sysconfig/addmodule_branding.inc.php
index d941a7a7..54b2ad57 100644
--- a/modules-available/sysconfig/addmodule_branding.inc.php
+++ b/modules-available/sysconfig/addmodule_branding.inc.php
@@ -11,7 +11,7 @@ class Branding_Start extends AddModule_Base
{
Render::addDialog(Dictionary::translateFile('config-module', 'branding_title'), false, 'branding-start', array(
'step' => 'Branding_ProcessFile',
- 'edit' => $this->edit ? $this->edit->id() : false
+ 'edit' => $this->edit == null ? null : $this->edit->id(),
));
}
@@ -22,7 +22,6 @@ class Branding_ProcessFile extends AddModule_Base
private $task;
private $svgFile;
- private $tarFile;
protected function preprocessInternal()
{
@@ -48,14 +47,16 @@ class Branding_ProcessFile extends AddModule_Base
if (strpos($url, '://') === false)
$url = "http://$url";
$title = false;
- if (!$this->downloadSvg($this->svgFile, $url, $title))
+ if (!Branding_ProcessFile::downloadSvg($this->svgFile, $url, $title)) {
+ @unlink($this->svgFile);
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
+ }
Session::set('logo_name', $title);
}
chmod($this->svgFile, 0644);
- $this->tarFile = '/tmp/bwlp-' . time() . '-' . mt_rand() . '.tgz';
+ $tarFile = '/tmp/bwlp-' . time() . '-' . mt_rand() . '.tgz';
$this->task = Taskmanager::submit('BrandingGenerator', array(
- 'tarFile' => $this->tarFile,
+ 'tarFile' => $tarFile,
'svgFile' => $this->svgFile
));
$this->task = Taskmanager::waitComplete($this->task, 5000);
@@ -64,8 +65,7 @@ class Branding_ProcessFile extends AddModule_Base
Taskmanager::addErrorMessage($this->task);
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
- Session::set('logo_tgz', $this->tarFile);
- Session::save();
+ Session::set('logo_tgz', $tarFile);
}
protected function renderInternal()
@@ -75,13 +75,13 @@ class Branding_ProcessFile extends AddModule_Base
$png = base64_encode(file_get_contents($this->task['data']['pngFile']));
if (filesize($this->svgFile) < 1000000)
$svg = base64_encode(file_get_contents($this->svgFile));
- Render::addDialog(Dictionary::translate('config-module', 'branding_title'), false, 'branding-check', array(
+ Render::addDialog(Dictionary::translateFile('config-module', 'branding_title'), false, 'branding-check', array(
'png' => $png,
'svg' => $svg,
- 'error' => $this->task['data']['error'],
+ 'error' => $this->task['data']['error'] ?? $this->task['statusCode'],
'step' => 'Branding_Finish',
- 'edit' => $this->edit ? $this->edit->id() : false,
- 'title' => $this->edit ? $this->edit->title() : false
+ 'edit' => $this->edit === null ? null : $this->edit->id(),
+ 'title' => $this->edit === null ? null : $this->edit->title(),
)
);
@unlink($this->svgFile);
@@ -96,39 +96,56 @@ class Branding_ProcessFile extends AddModule_Base
* @return boolean true of download succeeded, false on download error (also returns true if downloaded file doesn't
* seem to be svg!)
*/
- private function downloadSvg($svgName, $url, &$title)
+ private static function downloadSvg(string $svgName, string $url, &$title): bool
{
$title = false;
- // [wikipedia] Did someone paste a link to a thumbnail of the svg? Let's fix that...
- if (preg_match('#^(.*)/thumb/(.*\.svg)/.*\.svg#', $url, $out)) {
- $url = $out[1] . '/' . $out[2];
- }
for ($i = 0; $i < 5; ++$i) {
+ // [wikipedia] Did someone paste a link to a thumbnail of the svg? Let's fix that...
+ if (preg_match('#^(.*)/thumb/(.*\.svg)/.*\.svg#', $url, $out)) {
+ $url = $out[1] . '/' . $out[2];
+ }
$code = 400;
if (!Download::toFile($svgName, $url, 3, $code) || $code < 200 || $code > 299) {
Message::addError('remote-timeout', $url, $code);
return false;
}
- $content = FileUtil::readFile($svgName, 25000);
+ $content = FileUtil::readFile($svgName, 250000);
// Is svg file?
if (strpos($content, '<svg') !== false)
return true; // Found an svg tag - don't try to find links to the actual image
// [wikipedia] Try to be nice and detect links that might give a hint where the svg can be found
- if (preg_match_all('#href="([^"]*upload.wikimedia.org/[^"]*/[^"]*/[^"]*\.svg|[^"]+/[^"]+:[^"]+\.svg[^"]*)"#', $content, $out, PREG_PATTERN_ORDER)) {
+ $out1 = $out2 = $out3 = null;
+ if (preg_match_all('#href="([^"]*upload.wikimedia.org/[^"]*/[^"]*/[^"]*\.svg)"#', $content, $out1, PREG_PATTERN_ORDER)
+ || preg_match_all('#src="([^"]*upload.wikimedia.org/[^"]*/thumb/[^"]*\.svg/[^"]+\.svg[^"]*)"#', $content, $out2, PREG_PATTERN_ORDER)
+ || preg_match_all('#href="([^"]+/[^"]+:[^"]+\.svg)"#', $content, $out3, PREG_PATTERN_ORDER)) {
if ($title === false && preg_match('#<title>([^<]*)</title>#i', $content, $tout)) {
$title = trim(preg_replace('/\W*Wikipedia.*/', '', $tout[1]));
}
$new = false;
- foreach ($out[1] as $res) {
+ $out = [];
+ if (isset($out1[1])) {
+ $out += $out1[1];
+ }
+ if (isset($out2[1])) {
+ $out += $out2[1];
+ }
+ if (isset($out3[1])) {
+ $out += $out3[1];
+ }
+ foreach ($out as $res) {
+ error_log("Match '$res'");
+ if (!preg_match('/hochschule|univers|logo|siegel/i', $res))
+ continue;
if (strpos($res, 'action=edit') !== false)
continue;
- $new = $this->internetCombineUrl($url, html_entity_decode($res, ENT_COMPAT, 'UTF-8'));
+ $new = Branding_ProcessFile::internetCombineUrl($url, html_entity_decode($res, ENT_COMPAT, 'UTF-8'));
if ($new !== $url)
break;
}
if ($new === $url || $new === false)
break;
+ error_log("New: '$new'");
$url = $new;
continue;
}
@@ -145,7 +162,7 @@ class Branding_ProcessFile extends AddModule_Base
* @param string $relative relative url that will be converted to an absolute url
* @return string combined absolute url
*/
- private function internetCombineUrl($absolute, $relative)
+ private static function internetCombineUrl(string $absolute, string $relative): string
{
$p = parse_url($relative);
if (!empty($p["scheme"]))
@@ -154,8 +171,8 @@ class Branding_ProcessFile extends AddModule_Base
$parsed = parse_url($absolute);
$path = dirname($parsed['path']);
- if ($relative{0} === '/') {
- if ($relative{1} === '/')
+ if ($relative[0] === '/') {
+ if ($relative[1] === '/')
return "{$parsed['scheme']}:$relative";
$cparts = array_filter(explode("/", $relative));
} else {
@@ -197,9 +214,9 @@ class Branding_Finish extends AddModule_Base
protected function preprocessInternal()
{
$title = Request::post('title');
- if ($title === false || empty($title))
+ if (empty($title))
$title = Session::get('logo_name');
- if ($title === false || empty($title)) {
+ if (empty($title)) {
Message::addError('missing-title'); // TODO: Ask for title again instead of starting over
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
@@ -208,30 +225,26 @@ class Branding_Finish extends AddModule_Base
Message::addError('main.error-read', $tgz);
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
- if ($this->edit === false)
+ if ($this->edit === null) {
$module = ConfigModule::getInstance('Branding');
- else
+ } else {
$module = $this->edit;
- if ($module === false) {
- Message::addError('main.error-read', 'branding.inc.php');
- Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
}
$module->setData('tmpFile', $tgz);
- if ($this->edit !== false)
+ if ($this->edit !== null)
$ret = $module->update($title);
else
$ret = $module->insert($title);
if (!$ret)
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
- elseif ($module->generate($this->edit === false, NULL, 200) === false)
+ elseif ($module->generate($this->edit === null, NULL, 200) === false)
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
Session::set('logo_tgz', false);
Session::set('logo_name', false);
- Session::save();
// Yay
- if ($this->edit !== false)
+ if ($this->edit !== null) {
Message::addSuccess('module-edited');
- else {
+ } else {
Message::addSuccess('module-added');
AddModule_Base::setStep('AddModule_Assign', $module->id());
return;
diff --git a/modules-available/sysconfig/addmodule_custommodule.inc.php b/modules-available/sysconfig/addmodule_custommodule.inc.php
index 86b98206..3afdad0a 100644
--- a/modules-available/sysconfig/addmodule_custommodule.inc.php
+++ b/modules-available/sysconfig/addmodule_custommodule.inc.php
@@ -14,7 +14,7 @@ class CustomModule_Start extends AddModule_Base
Session::set('mod_temp', false);
Render::addDialog(Dictionary::translateFile('config-module', 'custom_title'), false, 'custom-upload', array(
'step' => 'CustomModule_ProcessUpload',
- 'edit' => $this->edit ? $this->edit->id() : false
+ 'edit' => $this->edit === null ? null : $this->edit->id(),
));
}
@@ -55,8 +55,9 @@ class CustomModule_ProcessUpload extends AddModule_Base
protected function renderInternal()
{
- $status = Taskmanager::waitComplete($this->taskId);
+ $status = Taskmanager::waitComplete($this->taskId, 7500);
Taskmanager::release($this->taskId);
+ $userGroupWarn = false;
$tempfile = Session::get('mod_temp');
if (!isset($status['statusCode'])) {
unlink($tempfile);
@@ -66,47 +67,29 @@ class CustomModule_ProcessUpload extends AddModule_Base
unlink($tempfile);
$this->taskError($status);
}
- // Sort files for better display
- $dirs = array();
- foreach ($status['data']['entries'] as $file) {
- if ($file['isdir']) continue;
- $dirs[dirname($file['name'])][] = $file;
- }
- ksort($dirs);
- $list = array();
- foreach ($dirs as $dir => $files) {
- $list[] = array(
- 'name' => $dir,
- 'isdir' => true
- );
- sort($files);
- foreach ($files as $file) {
- $file['size'] = Util::readableFileSize($file['size']);
- $list[] = $file;
- }
- }
- if ($this->edit !== false)
+ $list = SysConfig::archiveContentsFromTask($status, $userGroupWarn);
+
+ if ($this->edit !== null) {
$title = $this->edit->title();
- elseif (isset($_FILES['modulefile']['name']))
+ } else if (isset($_FILES['modulefile']['name'])) {
$title = basename($_FILES['modulefile']['name']);
- else
+ } else {
$title = '';
- Render::addDialog(Dictionary::translate('config-module', 'custom_title'), false, 'custom-fileselect', array(
+ }
+ Render::addDialog(Dictionary::translateFile('config-module', 'custom_title'), false, 'custom-fileselect', array(
'step' => 'CustomModule_CompressModule',
'files' => $list,
- 'edit' => $this->edit ? $this->edit->id() : false,
- 'title' => $title
+ 'edit' => $this->edit === null ? null : $this->edit->id(),
+ 'title' => $title,
+ 'userGroupWarn' => $userGroupWarn,
));
- Session::save();
}
}
class CustomModule_CompressModule extends AddModule_Base
{
-
- private $taskId = false;
-
+
protected function preprocessInternal()
{
$title = Request::post('title');
@@ -116,14 +99,15 @@ class CustomModule_CompressModule extends AddModule_Base
Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start');
}
// Recompress using task manager
- $this->taskId = 'tgzmod' . mt_rand() . '-' . microtime(true);
+ $taskId = 'tgzmod' . mt_rand() . '-' . microtime(true);
$destFile = tempnam(sys_get_temp_dir(), 'bwlp-') . '.tgz';
Taskmanager::submit('RecompressArchive', array(
- 'id' => $this->taskId,
- 'inputFiles' => array($tempfile),
- 'outputFile' => $destFile
+ 'id' => $taskId,
+ 'inputFiles' => [$tempfile => false],
+ 'outputFile' => $destFile,
+ 'forceRoot' => Request::post('force-owner', 0, 'int') !== 0,
), true);
- $status = Taskmanager::waitComplete($this->taskId, 5000);
+ $status = Taskmanager::waitComplete($taskId, 10000);
unlink($tempfile);
if (!isset($status['statusCode'])) {
$this->tmError();
@@ -132,29 +116,26 @@ class CustomModule_CompressModule extends AddModule_Base
$this->taskError($status);
}
// Seems ok, create entry
- if ($this->edit === false)
+ if ($this->edit === null) {
$module = ConfigModule::getInstance('CustomModule');
- else
+ } else {
$module = $this->edit;
- if ($module === false) {
- Message::addError('main.error-read', 'custommodule.inc.php');
- Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start');
}
$module->setData('tmpFile', $destFile);
- if ($this->edit !== false)
+ if ($this->edit !== null) {
$ret = $module->update($title);
- else
+ } else {
$ret = $module->insert($title);
+ }
if (!$ret)
Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start');
- elseif (!$module->generate($this->edit === false, NULL, 200))
+ elseif (!$module->generate($this->edit === null, NULL, 200))
Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start');
Session::set('mod_temp', false);
- Session::save();
// Yay
- if ($this->edit !== false)
+ if ($this->edit !== null) {
Message::addSuccess('module-edited');
- else {
+ } else {
Message::addSuccess('module-added');
AddModule_Base::setStep('AddModule_Assign', $module->id());
return;
diff --git a/modules-available/sysconfig/addmodule_ldapauth.inc.php b/modules-available/sysconfig/addmodule_ldapauth.inc.php
index 98f98c6d..6a385d9c 100644
--- a/modules-available/sysconfig/addmodule_ldapauth.inc.php
+++ b/modules-available/sysconfig/addmodule_ldapauth.inc.php
@@ -9,15 +9,12 @@ class LdapAuth_Start extends AddModule_Base
protected function renderInternal()
{
- $LDAPAUTH_COMMON_FIELDS = array('title', 'server', 'searchbase', 'binddn', 'bindpw', 'home', 'homeattr', 'ssl', 'fixnumeric', 'genuid', 'certificate', 'mapping', 'nohomewarn');
+ $LDAPAUTH_COMMON_FIELDS = array('title', 'server', 'searchbase', 'binddn', 'bindpw', 'home', 'homeattr', 'ssl', 'genuid', 'certificate', 'mapping', 'nohomewarn');
$data = array();
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
moduleToArray($this->edit, $data, $LDAPAUTH_COMMON_FIELDS);
$data['title'] = $this->edit->title();
$data['edit'] = $this->edit->id();
- if (!isset($data['fixnumeric']) || $data['fixnumeric'] === false) {
- $data['fixnumeric'] = 's';
- }
} else {
$data['ssl'] = true;
}
@@ -30,7 +27,7 @@ class LdapAuth_Start extends AddModule_Base
}
$data['step'] = 'LdapAuth_CheckConnection';
$data['map_empty'] = true;
- $data['mapping'] = ConfigModuleBaseLdap::getMapping(isset($data['mapping']) ? $data['mapping'] : false, $data['map_empty']);
+ $data['mapping'] = ConfigModuleBaseLdap::getMapping($data['mapping'] ?? null, $data['map_empty']);
Render::addDialog(Dictionary::translateFile('config-module', 'ldapAuth_title'), false, 'ldap-start', $data);
}
@@ -67,7 +64,6 @@ class LdapAuth_CheckConnection extends AddModule_Base
));
if (!isset($this->scanTask['id'])) {
AddModule_Base::setStep('LdapAuth_Start'); // Continues with LdapAuth_Start for render()
- return;
}
}
@@ -82,11 +78,10 @@ class LdapAuth_CheckConnection extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl'),
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'certificate' => Request::post('certificate', ''),
'taskid' => $this->scanTask['id'],
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
);
$data['prev'] = 'LdapAuth_Start';
$data['next'] = 'LdapAuth_CheckCredentials';
@@ -154,11 +149,10 @@ class LdapAuth_CheckCredentials extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
'prev' => 'LdapAuth_Start',
'next' => 'LdapAuth_HomeDir',
))
@@ -195,16 +189,15 @@ class LdapAuth_HomeDir extends AddModule_Base
'bindpw' => Request::post('bindpw'),
'home' => Request::post('home'),
'ssl' => Request::post('ssl') === 'on',
- 'fixnumeric' => Request::post('fixnumeric'),
'genuid' => Request::post('genuid'),
'fingerprint' => Request::post('fingerprint'),
'certificate' => Request::post('certificate', ''),
'originalbinddn' => Request::post('originalbinddn'),
- 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', false, 'array')),
+ 'mapping' => ConfigModuleBaseLdap::getMapping(Request::post('mapping', null, 'array')),
'prev' => 'LdapAuth_Start',
'next' => 'LdapAuth_Finish',
);
- if ($this->edit !== false) {
+ if ($this->edit !== null) {
foreach (self::getAttributes() as $key) {
if ($this->edit->getData($key)) {
$data[$key . '_c'] = 'checked="checked"';
@@ -225,13 +218,13 @@ class LdapAuth_HomeDir extends AddModule_Base
foreach (range('D', 'Z') as $l) {
$data['drives'][] = array(
'drive' => $l . ':',
- 'selected' => (strtoupper($letter{0}) === $l) ? 'selected="selected"' : ''
+ 'selected' => (strtoupper($letter[0]) === $l) ? 'selected="selected"' : ''
);
}
Render::addDialog(Dictionary::translateFile('config-module', 'ldapAuth_title'), false, 'ad_ldap-homedir', $data);
}
- public static function getAttributes()
+ public static function getAttributes(): array
{
return array('shareRemapMode', 'shareRemapCreate', 'shareDocuments', 'shareDownloads', 'shareDesktop',
'shareMedia', 'shareOther', 'shareHomeDrive', 'shareDomain', 'credentialPassthrough');
@@ -249,12 +242,13 @@ class LdapAuth_Finish extends AddModule_Base
$title = Request::post('title');
if (empty($title))
$title = 'LDAP: ' . Request::post('server');
- if ($this->edit === false)
+ if ($this->edit === null) {
$module = ConfigModule::getInstance('LdapAuth');
- else
+ } else {
$module = $this->edit;
+ }
$ssl = Request::post('ssl', 'off') === 'on';
- foreach (['searchbase', 'binddn', 'server', 'bindpw', 'home', 'nohomewarn', 'certificate', 'fixnumeric', 'genuid',
+ foreach (['searchbase', 'binddn', 'server', 'bindpw', 'home', 'nohomewarn', 'certificate', 'genuid',
'ldapAttrMountOpts', 'shareHomeMountOpts'] as $key) {
$module->setData($key, Request::post($key, '', 'string'));
}
@@ -276,15 +270,16 @@ class LdapAuth_Finish extends AddModule_Base
} else {
$module->setData('fingerprint', '');
}
- if ($this->edit !== false)
+ if ($this->edit !== null) {
$ret = $module->update($title);
- else
+ } else {
$ret = $module->insert($title);
+ }
if (!$ret) {
Message::addError('main.value-invalid', 'any', 'any');
$tgz = false;
} else {
- $tgz = $module->generate($this->edit === false);
+ $tgz = $module->generate($this->edit === null);
}
if ($tgz === false) {
AddModule_Base::setStep('LdapAuth_Start'); // Continues with LdapAuth_Start for render()
@@ -294,9 +289,8 @@ class LdapAuth_Finish extends AddModule_Base
'tm-config' => $tgz,
);
- if ($this->edit === false) {
+ if ($this->edit === null) {
AddModule_Base::setStep('AddModule_Assign', $module->id());
- return;
}
}
diff --git a/modules-available/sysconfig/addmodule_screensaver.inc.php b/modules-available/sysconfig/addmodule_screensaver.inc.php
index 889a94e5..7b6d0afb 100644
--- a/modules-available/sysconfig/addmodule_screensaver.inc.php
+++ b/modules-available/sysconfig/addmodule_screensaver.inc.php
@@ -6,7 +6,6 @@
class Screensaver_Start extends AddModule_Base
{
- private $hasSummernote = false;
private $session_data;
protected function preprocessInternal()
@@ -15,7 +14,7 @@ class Screensaver_Start extends AddModule_Base
if (Request::get('back', 'false', 'string') !== 'false')
/* If coming via the back button, load the session data */
$this->session_data = Session::get('data');
- elseif ($this->edit !== false) {
+ elseif ($this->edit !== null) {
$this->session_data = array(
'title' => $this->edit->title(),
'qss' => $this->edit->getData('qss'),
@@ -25,22 +24,22 @@ class Screensaver_Start extends AddModule_Base
} else {
$this->session_data = array(
'title' => '',
- 'qss' => Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenQssDefault', true),
+ 'qss' => Dictionary::translate('saver_QssDefault'),
'messages' => array(
'General' => array(
- 'shutdown' => Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenMessageDefaultShutdown', true),
- 'shutdown-locked' => Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenMessageDefaultShutdownLocked', true),
- 'idle-kill' => Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenMessageDefaultIdleKill', true),
- 'idle-kill-locked' => Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenMessageDefaultIdleKillLocked', true),
- 'no-timeout' => Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenMessageDefaultNoTimeout', true),
- 'no-timeout-locked' => Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenMessageDefaultNoTimeoutLocked', true),
+ 'shutdown' => Dictionary::translate('saver_MessageDefaultShutdown'),
+ 'shutdown-locked' => Dictionary::translate('saver_MessageDefaultShutdownLocked'),
+ 'idle-kill' => Dictionary::translate('saver_MessageDefaultIdleKill'),
+ 'idle-kill-locked' => Dictionary::translate('saver_MessageDefaultIdleKillLocked'),
+ 'no-timeout' => Dictionary::translate('saver_MessageDefaultNoTimeout'),
+ 'no-timeout-locked' => Dictionary::translate('saver_MessageDefaultNoTimeoutLocked'),
)
),
'texts' => array(
- 'text-shutdown' => Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenTextDefaultShutdown', true),
+ 'text-shutdown' => Dictionary::translate('saver_TextDefaultShutdown'),
'text-shutdown-locked' => '',
- 'text-idle-kill' => Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenTextDefaultIdleKill', true),
- 'text-idle-kill-locked' => Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenTextDefaultIdleKillLocked', true),
+ 'text-idle-kill' => Dictionary::translate('saver_TextDefaultIdleKill'),
+ 'text-idle-kill-locked' => Dictionary::translate('saver_TextDefaultIdleKillLocked'),
'text-no-timeout' => '',
'text-no-timeout-locked' => '',
),
@@ -48,18 +47,16 @@ class Screensaver_Start extends AddModule_Base
}
$this->session_data['next'] = 'idle-kill';
Session::set('data', $this->session_data);
- Session::save();
}
protected function renderInternal()
{
/* Load summernote module if available */
- $this->hasSummernote = Module::isAvailable('summernote');
-
+ Module::isAvailable('summernote');
Render::addDialog(Dictionary::translateFile('config-module', 'screensaver_title'), false, 'screensaver-start', array(
'step' => 'Screensaver_Text',
'next' => 'idle-kill',
- 'edit' => $this->edit ? $this->edit->id() : 0,
+ 'edit' => $this->edit !== null ? $this->edit->id() : 0,
'id' => 'start',
'title' => $this->session_data['title'],
'qss' => $this->session_data['qss'],
@@ -69,26 +66,23 @@ class Screensaver_Start extends AddModule_Base
class Screensaver_Text extends AddModule_Base
{
- private $hasSummernote = false;
private $session_data;
- private $id;
protected function preprocessInternal()
{
/* Load session data */
$this->session_data = Session::get('data');
- $this->id = Request::post('id', '', 'string');
+ $id = Request::post('id', '', 'string');
- if ($this->id === 'start') {
+ if ($id === 'start') {
Screensaver_Helper::processQssData($this->session_data);
- } elseif ($this->id !== '') {
- Screensaver_Helper::processScreensaverText($this->session_data, $this->id);
+ } elseif ($id !== '') {
+ Screensaver_Helper::processScreensaverText($this->session_data, $id);
}
$next = Request::post('next', $this->session_data['next'], 'string');
$this->session_data['next'] = $next;
Session::set('data', $this->session_data);
- Session::save();
if ($next === 'finish')
@@ -100,24 +94,28 @@ class Screensaver_Text extends AddModule_Base
protected function renderInternal()
{
/* Load summernote module if available */
- $this->hasSummernote = Module::isAvailable('summernote');
+ Module::isAvailable('summernote');
$next = $this->session_data['next'];
$data = array(
- 'edit' => $this->edit ? $this->edit->id() : 0,
+ 'edit' => $this->edit !== null ? $this->edit->id() : 0,
);
/* Prepare and translate labels for the frontend */
$data['id'] = $next;
/* Convert the id to a language tag (camelCase) styled string */
- $tag = explode('-', $next);
- foreach ($tag as $key => $value) {
- $tag[$key] = ucwords($value);
- }
- $tag = implode($tag);
-
- $data['title'] = Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenTitle' . $tag, true);
- $data['description'] = Dictionary::translateFileModule('sysconfig', 'template-tags', 'lang_screenDescription' . $tag, true);;
+ $tag = implode(array_map('ucwords', explode('-', $next)));
+
+ /* For translate module:
+ * Dictionary::translate('saver_TitleNoTimeout');
+ * Dictionary::translate('saver_DescriptionNoTimeout');
+ * Dictionary::translate('saver_TitleIdleKill');
+ * Dictionary::translate('saver_DescriptionIdleKill');
+ * Dictionary::translate('saver_TitleShutdown');
+ * Dictionary::translate('saver_DescriptionShutdown');
+ */
+ $data['title'] = Dictionary::translate('saver_Title' . $tag);
+ $data['description'] = Dictionary::translate('saver_Description' . $tag);
$data['msg_value'] = $this->session_data['messages']['General'][$next];
$data['msg_locked_value'] = $this->session_data['messages']['General'][$next . '-locked'];
$data['text_value'] = $this->session_data['texts']['text-' . $next];
@@ -152,14 +150,14 @@ class Screensaver_Finish extends AddModule_Base
if (empty($session_data['title'])) {
Message::addError('missing-title');
Util::redirect('?do=SysConfig');
- return;
}
/* Only create an instance, if it's a new one */
- if ($this->edit !== false)
+ if ($this->edit !== null) {
$module = $this->edit;
- else
+ } else {
$module = ConfigModule::getInstance('Screensaver');
+ }
/* Set all the data to the module instance */
$module->setData('qss', $session_data['qss']);
@@ -167,15 +165,16 @@ class Screensaver_Finish extends AddModule_Base
$module->setData('texts', $session_data['texts']);
/* Insert or update database entries */
- if ($this->edit !== false)
+ if ($this->edit !== null) {
$module->update($session_data['title']);
- else
+ } else {
$module->insert($session_data['title']);
+ }
- $task = $module->generate($this->edit === false);
+ $task = $module->generate($this->edit === null);
// Yay
- if ($task !== false && $this->edit !== false)
+ if ($task !== false && $this->edit !== null)
Message::addSuccess('module-edited');
elseif ($task !== false) {
Message::addSuccess('module-added');
@@ -194,7 +193,6 @@ class Screensaver_Helper
if (empty($session_data['title'])) {
Message::addError('missing-title');
Util::redirect('?do=SysConfig');
- return;
}
$session_data['qss'] = Request::post('qss', $session_data['qss'], 'string');
$helperMode = Request::post('helper_mode', 'false', 'string');
diff --git a/modules-available/sysconfig/addmodule_sshconfig.inc.php b/modules-available/sysconfig/addmodule_sshconfig.inc.php
index 495ba2a9..2447f9be 100644
--- a/modules-available/sysconfig/addmodule_sshconfig.inc.php
+++ b/modules-available/sysconfig/addmodule_sshconfig.inc.php
@@ -9,14 +9,18 @@ class SshConfig_Start extends AddModule_Base
protected function renderInternal()
{
- if ($this->edit !== false) {
- $data = $this->edit->getData(false) + array(
+ if ($this->edit !== null) {
+ $data = $this->edit->getData(null) + array(
'title' => $this->edit->title(),
'edit' => $this->edit->id(),
- 'apl' => $this->edit->getData('allowPasswordLogin') === 'yes'
+ 'PWD_' . strtoupper($this->edit->getData('allowPasswordLogin')) . '_selected' => 'selected',
+ 'USR_' . strtoupper($this->edit->getData('allowedUsersLogin')) . '_selected' => 'selected',
);
} else {
- $data = array();
+ $data = array(
+ 'PWD_NO_selected' => 'selected',
+ 'USR_ROOT_ONLY_selected' => 'selected',
+ );
}
Render::addDialog(Dictionary::translateFile('config-module', 'sshconfig_title'), false, 'sshconfig-start', $data + array(
'step' => 'SshConfig_Finish',
@@ -36,15 +40,17 @@ class SshConfig_Finish extends AddModule_Base
return;
}
// Seems ok, create entry
- if ($this->edit === false)
+ if ($this->edit === null) {
$module = ConfigModule::getInstance('SshConfig');
- else
+ } else {
$module = $this->edit;
+ }
if ($module === false) {
Message::addError('main.error-read', 'sshconfig.inc.php');
Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
}
- $module->setData('allowPasswordLogin', Request::post('allowPasswordLogin') === 'yes');
+ $module->setData('allowPasswordLogin', Request::post('allowPasswordLogin'));
+ $module->setData('allowedUsersLogin', Request::post('allowedUsersLogin'));
$port = Request::post('listenPort', '');
if ($port === '') {
$port = 22;
@@ -53,22 +59,21 @@ class SshConfig_Finish extends AddModule_Base
Message::addError('main.value-invalid', 'port', Request::post('listenPort'));
Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
}
- if (!$module->setData('publicKey', Request::post('publicKey'))) {
- Message::addError('main.value-invalid', 'pubkey', Request::post('publicKey'));
- Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
- }
- if ($this->edit !== false)
+ $module->setData('publicKey', false);
+ if ($this->edit !== null) {
$ret = $module->update($title);
- else
+ } else {
$ret = $module->insert($title);
- if (!$ret)
+ }
+ if (!$ret) {
Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
- elseif (!$module->generate($this->edit === false, NULL, 200))
+ } elseif (!$module->generate($this->edit === null, NULL, 200)) {
Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
+ }
// Yay
- if ($this->edit !== false)
+ if ($this->edit !== null) {
Message::addSuccess('module-edited');
- else {
+ } else {
Message::addSuccess('module-added');
AddModule_Base::setStep('AddModule_Assign', $module->id());
return;
diff --git a/modules-available/sysconfig/addmodule_sshkey.inc.php b/modules-available/sysconfig/addmodule_sshkey.inc.php
new file mode 100644
index 00000000..9f5bd1d3
--- /dev/null
+++ b/modules-available/sysconfig/addmodule_sshkey.inc.php
@@ -0,0 +1,72 @@
+<?php
+
+/*
+ * Wizard for configuring the sshd (client side).
+ */
+
+class SshKey_Start extends AddModule_Base
+{
+
+ protected function renderInternal()
+ {
+ if ($this->edit !== null) {
+ $data = $this->edit->getData(null) + array(
+ 'title' => $this->edit->title(),
+ 'edit' => $this->edit->id(),
+ );
+ } else {
+ $data = array();
+ }
+ Render::addDialog(Dictionary::translateFile('config-module', 'sshkey_title'), false, 'sshkey-start', $data + array(
+ 'step' => 'SshKey_Finish',
+ ));
+ }
+
+}
+
+class SshKey_Finish extends AddModule_Base
+{
+
+ protected function preprocessInternal()
+ {
+ $title = Request::post('title');
+ if (empty($title)) {
+ Message::addError('missing-title');
+ return;
+ }
+ // Seems ok, create entry
+ if ($this->edit === null) {
+ $module = ConfigModule::getInstance('SshKey');
+ } else {
+ $module = $this->edit;
+ }
+ if ($module === false) {
+ Message::addError('main.error-read', 'sshkey.inc.php');
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshKey_Start');
+ }
+ if (!$module->setData('publicKey', Request::post('publicKey'))) {
+ Message::addError('main.value-invalid', 'pubkey', Request::post('publicKey'));
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshKey_Start');
+ }
+ if ($this->edit !== null) {
+ $ret = $module->update($title);
+ } else {
+ $ret = $module->insert($title);
+ }
+ if (!$ret) {
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshKey_Start');
+ } elseif (!$module->generate($this->edit === null, NULL, 200)) {
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshKey_Start');
+ }
+ // Yay
+ if ($this->edit !== null) {
+ Message::addSuccess('module-edited');
+ } else {
+ Message::addSuccess('module-added');
+ AddModule_Base::setStep('AddModule_Assign', $module->id());
+ return;
+ }
+ Util::redirect('?do=SysConfig');
+ }
+
+}
diff --git a/modules-available/sysconfig/api.inc.php b/modules-available/sysconfig/api.inc.php
index 983c6dcb..e7be3029 100644
--- a/modules-available/sysconfig/api.inc.php
+++ b/modules-available/sysconfig/api.inc.php
@@ -11,9 +11,9 @@ if (substr($ip, 0, 7) === '::ffff:') {
$ip = substr($ip, 7);
}
-$uuid = Request::any('uuid', false, 'string');
-if ($uuid !== false && strlen($uuid) !== 36) {
- $uuid = false;
+$uuid = Request::any('uuid', null, 'string');
+if ($uuid !== null && strlen($uuid) !== 36) {
+ $uuid = null;
}
// What we do if we can't supply the requested config
@@ -46,7 +46,7 @@ $res = Database::simpleQuery("SELECT c.title, c.filepath, c.status, cl.locationi
$best = 1000;
$row = false;
-while ($r = $res->fetch(PDO::FETCH_ASSOC)) {
+foreach ($res as $r) {
settype($r['locationid'], 'int');
$index = array_search($r['locationid'], $locationChain);
if ($index === false || $index > $best)
diff --git a/modules-available/sysconfig/clientscript.js b/modules-available/sysconfig/clientscript.js
index cafe7b02..9dbb0745 100644
--- a/modules-available/sysconfig/clientscript.js
+++ b/modules-available/sysconfig/clientscript.js
@@ -3,9 +3,9 @@
(function() {
var boldItem = false;
- var revList = false;
+ var modToConf = false;
- var $ct = $('#conftable').find('.confrow');
+ var $ct = $('#conftable').find('.confrow .title');
$ct.click(function () {
showmod(this, 'bold');
}).mouseenter(function () {
@@ -13,7 +13,7 @@
}).mouseleave(function () {
showmod(this, 'reset');
});
- var $mt = $('#modtable').find('.modrow');
+ var $mt = $('#modtable').find('.modrow .title');
$mt.click(function () {
showconf(this, 'bold');
}).mouseenter(function () {
@@ -23,9 +23,8 @@
});
var $confirm = $('#delete-item-list');
$('.btn-del-module').click(function() {
- if (!revList) buildRevList();
var mid = $(this).val() + '';
- var list = revList[mid];
+ var list = modToConf[mid];
if (!list || !list.length) {
$confirm.append($msgs).addClass('hidden');
return;
@@ -33,7 +32,7 @@
var $msgs = $confirm.find('ul').empty();
for (var i = 0; i < list.length; ++i) {
$msgs.append($('<li>').text(
- $('.confrow[data-id="' + list[i] + '"]').text()
+ $('.confrow[data-id="' + list[i] + '"] .title').text()
));
}
$confirm.removeClass('hidden');
@@ -42,6 +41,11 @@
$confirm.addClass('hidden');
});
+ buildRevList();
+ var mods = [];
+ $('#modtable .modrow').each(function() { mods.push($(this).data('id')) });
+ mods.forEach(function(e) { if (modToConf[e] === undefined) $('.modrow[data-id=' + e + '] .icon-unused').removeClass('hidden') });
+
function showpre(e, action) {
if (boldItem && action !== 'bold') return 'reset';
if (boldItem) {
@@ -54,14 +58,14 @@
}
function buildRevList() {
- revList = {};
+ modToConf = {};
$ct.each(function () {
- var elem = $(this);
+ var elem = $(this).parent();
var cid = elem.data('id') + '';
var list = (elem.data('modlist') + '').split(',');
for (var i = 0; i < list.length; ++i) {
- if (!revList[list[i]]) revList[list[i]] = [];
- revList[list[i]].push(cid);
+ if (!modToConf[list[i]]) modToConf[list[i]] = [];
+ modToConf[list[i]].push(cid);
}
});
}
@@ -70,12 +74,11 @@
action = showpre(e, action);
if (action === 'reset') return;
var $e = $(e);
- if (!revList) buildRevList();
- var mid = $e.data('id') + '';
- var list = revList[mid];
+ var mid = $e.parent().data('id') + '';
+ var list = modToConf[mid];
if (list && list.length > 0) $ct.each(function () {
var elem = $(this);
- var cid = elem.data('id') + '';
+ var cid = elem.parent().data('id') + '';
if (list.indexOf(cid) === -1)
elem.addClass('slx-fade');
else if (action === 'bold')
@@ -91,10 +94,10 @@
action = showpre(e, action);
if (action === 'reset') return;
var $e = $(e);
- var list = ($e.data('modlist') + '').split(',');
+ var list = ($e.parent().data('modlist') + '').split(',');
$mt.each(function () {
var elem = $(this);
- if (list.indexOf(elem.data('id') + '') === -1)
+ if (list.indexOf(elem.parent().data('id') + '') === -1)
elem.addClass("slx-fade");
else if (action === 'bold')
elem.addClass("slx-bold");
@@ -113,23 +116,29 @@ var statusChecks = 0;
function checkBuildStatus() {
var mods = [];
var confs = [];
- $(".refmod.btn-primary").each(function (index) {
+ $(".modrow .btn-rebuild.btn-primary").each(function (index) {
mods.push($(this).val());
});
- $(".refconf.btn-primary").each(function (index) {
+ $(".confrow .btn-rebuild.btn-primary").each(function (index) {
confs.push($(this).val());
});
if (mods.length === 0 && confs.length === 0) return;
if (++statusChecks < 10) setTimeout(checkBuildStatus, 150 + 100 * statusChecks);
$.post('?do=SysConfig', { mods: mods.join(), confs: confs.join(), token: TOKEN, action: 'status' }, function (data) {
if (typeof data === 'undefined') return;
- if (typeof data.mods === 'object') updateButtonColor($(".refmod.btn-primary"), data.mods);
- if (typeof data.confs === 'object') updateButtonColor($(".refconf.btn-primary"), data.confs);
+ if (typeof data.mods === 'object') updateButtonColor('.modrow', data.mods);
+ if (typeof data.confs === 'object') updateButtonColor('.confrow', data.confs);
}, 'json');
}
-function updateButtonColor(list,ids) {
- list.each(function() {
- if (ids.indexOf($(this).val()) >= 0) $(this).removeClass('btn-primary').addClass('btn-default');
- });
+function updateButtonColor(rowclass,ids) {
+ for (var i = 0; i < ids.length; ++i) {
+ var e = ids[i];
+ var $row = $(rowclass + '[data-id=' + e.id + ']');
+ $row.find('.btn-rebuild').removeClass('btn-primary').addClass('btn-default');
+ if (e.warnings && (typeof e.warnings === 'string') && e.warnings.length > 0) {
+ $row.find('.row-warnings').text(e.warnings);
+ $row.find('.btn-warnings').removeClass('hidden');
+ }
+ }
}
diff --git a/modules-available/sysconfig/hooks/bootup.inc.php b/modules-available/sysconfig/hooks/bootup.inc.php
new file mode 100644
index 00000000..8e445dc4
--- /dev/null
+++ b/modules-available/sysconfig/hooks/bootup.inc.php
@@ -0,0 +1,3 @@
+<?php
+
+ConfigModuleBaseLdap::ldadp(); \ No newline at end of file
diff --git a/modules-available/sysconfig/hooks/locations-column.inc.php b/modules-available/sysconfig/hooks/locations-column.inc.php
new file mode 100644
index 00000000..8042b51c
--- /dev/null
+++ b/modules-available/sysconfig/hooks/locations-column.inc.php
@@ -0,0 +1,57 @@
+<?php
+
+if (!User::hasPermission('.sysconfig.config.*') || !Module::isAvailable('sysconfig'))
+ return null;
+
+class SysconfigLocationColumn extends AbstractLocationColumn
+{
+
+ private $lookup = [];
+
+ public function __construct()
+ {
+ $confs = SysConfig::getAll();
+ foreach ($confs as $conf) {
+ if (!isset($conf['locs']) || strlen($conf['locs']) === 0)
+ continue;
+ $confLocs = explode(',', $conf['locs']);
+ foreach ($confLocs as $locId) {
+ $this->lookup[$locId] = $conf['title'];
+ }
+ }
+ }
+
+ public function getColumnHtml(int $locationId): string
+ {
+ return htmlspecialchars($this->lookup[$locationId] ?? '');
+ }
+
+ public function getEditUrl(int $locationId): string
+ {
+ if (!User::hasPermission('.sysconfig.config.assign', $locationId))
+ return '';
+ return '?do=sysconfig&locationid=' . $locationId;
+ }
+
+ public function header(): string
+ {
+ return Dictionary::translateFileModule('sysconfig', 'module', 'location-column-header');
+ }
+
+ public function priority(): int
+ {
+ return 2000;
+ }
+
+ public function propagateColumn(): bool
+ {
+ return true;
+ }
+
+ public function propagateDefaultHtml(): string
+ {
+ return htmlspecialchars($this->lookup[0] ?? '');
+ }
+}
+
+return new SysconfigLocationColumn(); \ No newline at end of file
diff --git a/modules-available/sysconfig/inc/configmodule.inc.php b/modules-available/sysconfig/inc/configmodule.inc.php
index a9035d78..729cb959 100644
--- a/modules-available/sysconfig/inc/configmodule.inc.php
+++ b/modules-available/sysconfig/inc/configmodule.inc.php
@@ -7,18 +7,23 @@ abstract class ConfigModule
{
/**
- * @var array list of known module types
+ * @var ?array{'title': string,
+ * 'description': string,
+ * 'group': string,
+ * 'unique': bool,
+ * 'sortOrder': int,
+ * 'moduleClass': string,
+ * 'wizardClass': string}[] list of known module types
*/
- private static $moduleTypes = false;
+ private static $moduleTypes = null;
private $moduleId = 0;
- private $moduleArchive = false;
- private $moduleTitle = false;
- private $moduleStatus = false;
- /**
- * @var int
- */
+ private $moduleArchive = '';
+ private $moduleTitle = '';
+ private $moduleStatus = 'MISSING';
+ /** @var int */
private $dateline = 0;
+ /** @var int */
private $currentVersion = 0;
/**
* @var false|array Data of module, false if not initialized
@@ -33,9 +38,9 @@ abstract class ConfigModule
*/
public static function loadDb()
{
- if (self::$moduleTypes !== false)
+ if (self::$moduleTypes !== null)
return;
- self::$moduleTypes = array();
+ self::$moduleTypes = [];
Module::isAvailable('sysconfig');
foreach (glob(dirname(__FILE__) . '/configmodule/*.inc.php', GLOB_NOSORT) as $file) {
require_once $file;
@@ -44,10 +49,16 @@ abstract class ConfigModule
/**
* Get all known config module types.
- *
- * @return array list of modules
+ * @return array{'title': string,
+ * 'description': string,
+ * 'group': string,
+ * 'unique': bool,
+ * 'sortOrder': int,
+ * 'moduleClass': string,
+ * 'wizardClass': string}[] list of known module types
+ * /
*/
- public static function getList()
+ public static function getList(): array
{
self::loadDb();
return self::$moduleTypes;
@@ -63,20 +74,20 @@ abstract class ConfigModule
* @param string $description Description for this module type
* @param string $group Title for group this module type belongs to
* @param bool $unique Can only one such module be added to a config?
- * @param int $sortOrder Lower comes first, alphabetical ordering otherwiese
+ * @param int $sortOrder Lower comes first, alphabetical ordering otherwise
*/
- public static function registerModule($id, $title, $description, $group, $unique, $sortOrder = 0)
+ public static function registerModule(string $id, string $title, string $description, string $group, bool $unique, int $sortOrder = 0): void
{
if (isset(self::$moduleTypes[$id])) {
- Util::traceError("Config Module $id already registered!");
+ ErrorHandler::traceError("Config Module $id already registered!");
}
$moduleClass = 'ConfigModule_' . $id;
$wizardClass = $id . '_Start';
if (!class_exists($moduleClass)) {
- Util::traceError("Class $moduleClass does not exist!");
+ ErrorHandler::traceError("Class $moduleClass does not exist!");
}
if (!is_subclass_of($moduleClass, 'ConfigModule')) {
- Util::traceError("$moduleClass does not have ConfigModule as its parent!");
+ ErrorHandler::traceError("$moduleClass does not have ConfigModule as its parent!");
}
self::$moduleTypes[$id] = array(
'title' => $title,
@@ -93,21 +104,33 @@ abstract class ConfigModule
* Get fresh instance of ConfigModule subclass for given module type.
*
* @param string $moduleType name of module type
- * @return false|\ConfigModule module instance
+ * @return ConfigModule module instance
*/
- public static function getInstance($moduleType)
+ public static function getInstance(string $moduleType): ConfigModule
+ {
+ $ret = self::getInstanceOrNull($moduleType);
+ if ($ret === null) {
+ Message::addError('main.error-read', $moduleType . '.inc.php');
+ Util::redirect('?do=sysconfig');
+ }
+ return $ret;
+ }
+
+ public static function getInstanceOrNull(string $moduleType): ?ConfigModule
{
self::loadDb();
if (!isset(self::$moduleTypes[$moduleType])) {
error_log('Unknown module type: ' . $moduleType);
- return false;
+ return null;
}
return new self::$moduleTypes[$moduleType]['moduleClass'];
}
- public static function instanceFromDbRow($dbRow)
+ private static function instanceFromDbRow(array $dbRow): ?ConfigModule
{
- $instance = self::getInstance($dbRow['moduletype']);
+ $instance = self::getInstanceOrNull($dbRow['moduletype']);
+ if ($instance === null)
+ return null;
$instance->currentVersion = $dbRow['version'];
$instance->moduleArchive = $dbRow['filepath'];
$instance->moduleData = json_decode($dbRow['contents'], true);
@@ -125,37 +148,37 @@ abstract class ConfigModule
* Get module instance from id.
*
* @param int $moduleId module id to get
- * @return false|\ConfigModule The requested module from DB, or false on error
+ * @return ?ConfigModule The requested module from DB, or null on error
*/
- public static function get($moduleId)
+ public static function get(int $moduleId): ?ConfigModule
{
$ret = Database::queryFirst("SELECT moduleid, title, moduletype, filepath, contents, version, status, dateline FROM configtgz_module "
. " WHERE moduleid = :moduleid LIMIT 1", array('moduleid' => $moduleId));
if ($ret === false)
- return false;
+ return null;
return self::instanceFromDbRow($ret);
}
/**
* Get module instances from module type.
*
- * @param int $moduleType module type to get
- * @return \ConfigModule[]|false The requested modules from DB, or false on error
+ * @param string $moduleType module type to get
+ * @return ?ConfigModule[] The requested modules from DB, or null on error
*/
- public static function getAll($moduleType = false)
+ public static function getAll(string $moduleType = null): ?array
{
- if ($moduleType === false) {
+ if ($moduleType === null) {
$ret = Database::simpleQuery("SELECT moduleid, title, moduletype, filepath, contents, version, status, dateline FROM configtgz_module");
} else {
$ret = Database::simpleQuery("SELECT moduleid, title, moduletype, filepath, contents, version, status, dateline FROM configtgz_module "
. " WHERE moduletype = :moduletype", array('moduletype' => $moduleType));
}
if ($ret === false)
- return false;
+ return null;
$list = array();
- while ($row = $ret->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($ret as $row) {
$instance = self::instanceFromDbRow($row);
- if ($instance === false)
+ if ($instance === null)
continue;
$list[] = $instance;
}
@@ -167,37 +190,37 @@ abstract class ConfigModule
*
* @return int module version
*/
- protected abstract function moduleVersion();
+ protected abstract function moduleVersion(): int;
/**
* Validate the module's configuration.
*
- * @return boolean ok or not
+ * @return bool ok or not
*/
- protected abstract function validateConfig();
+ protected abstract function validateConfig(): bool;
/**
* Set module specific data.
*
* @param string $key key, name or id of data being set
* @param mixed $value Module specific data
- * @return boolean true if data was successfully set, false otherwise (i.e. invalid data being set)
+ * @return bool true if data was successfully set, false otherwise (i.e. invalid data being set)
*/
- public abstract function setData($key, $value);
+ public abstract function setData(string $key, $value): bool;
/**
* Get module specific data.
* Can be overridden by modules.
*
- * @param string $key key, name or id of data to get, or false to get the raw moduleData array
+ * @param ?string $key key, name or id of data to get, or null to get the raw moduleData array
* @return mixed Module specific data
*/
- public function getData($key)
+ public function getData(?string $key)
{
- if ($key === false)
+ if ($key === null)
return $this->moduleData;
if (!is_array($this->moduleData) || !isset($this->moduleData[$key]))
- return false;
+ return null;
return $this->moduleData[$key];
}
@@ -205,25 +228,25 @@ abstract class ConfigModule
* Module specific version of generate.
*
* @param string $tgz File name of tgz module to write final output to
- * @param string $parent Parent task of this task
+ * @param string|null $parent Parent task of this task
* @return array|boolean true if generation is completed immediately,
* a task struct if some task needs to be run for generation,
* false on error
*/
- protected abstract function generateInternal($tgz, $parent);
+ protected abstract function generateInternal(string $tgz, ?string $parent);
- private final function createFileName()
+ private function createFileName(): string
{
return CONFIG_TGZ_LIST_DIR . '/modules/'
. $this->moduleType() . '_id-' . $this->moduleId . '__' . mt_rand() . '-' . time() . '.tgz';
}
- public function allowDownload()
+ public function allowDownload(): bool
{
return false;
}
- public function needRebuild()
+ public function needRebuild(): bool
{
return $this->moduleStatus !== 'OK' || $this->currentVersion < $this->moduleVersion();
}
@@ -233,17 +256,15 @@ abstract class ConfigModule
*
* @return int id
*/
- public final function id()
+ public final function id(): int
{
return $this->moduleId;
}
/**
* Get module title.
- *
- * @return string
*/
- public final function title()
+ public final function title(): string
{
return $this->moduleTitle;
}
@@ -253,29 +274,33 @@ abstract class ConfigModule
*
* @return string tgz file absolute path
*/
- public final function archive()
+ public final function archive(): string
{
return $this->moduleArchive;
}
- public final function status()
+ public final function status(): string
{
return $this->moduleStatus;
}
+
+ public final function currentVersion(): int
+ {
+ return $this->currentVersion;
+ }
/**
* Get the module type.
*
* @return string module type
*/
- public final function moduleType()
+ public final function moduleType(): string
{
+ // Yes, need to pass $this, otherwise we get ConfigModule, the base class this function is part of
$name = get_class($this);
- if ($name === false)
- Util::traceError('ConfigModule::moduleType: get_class($this) returned false!');
// ConfigModule_*
if (!preg_match('/^ConfigModule_(\w+)$/', $name, $out))
- Util::traceError('ConfigModule::moduleType: get_class($this) returned "' . $name . '"');
+ ErrorHandler::traceError('ConfigModule::moduleType: get_class($this) returned "' . $name . '"');
return $out[1];
}
@@ -287,10 +312,10 @@ abstract class ConfigModule
* @param string $title display name of the module
* @return boolean true if inserted successfully, false if module config is invalid
*/
- public final function insert($title)
+ public final function insert(string $title): bool
{
if ($this->moduleId !== 0)
- Util::traceError('ConfigModule::insert called when moduleId != 0');
+ ErrorHandler::traceError('ConfigModule::insert called when moduleId != 0');
if (!$this->validateConfig())
return false;
$this->moduleTitle = $title;
@@ -306,7 +331,7 @@ abstract class ConfigModule
));
$this->moduleId = Database::lastInsertId();
if (!is_numeric($this->moduleId))
- Util::traceError('Inserting new config module into DB did not yield a numeric insert id');
+ ErrorHandler::traceError('Inserting new config module into DB did not yield a numeric insert id');
$this->moduleArchive = $this->createFileName();
Database::exec("UPDATE configtgz_module SET filepath = :path WHERE moduleid = :moduleid LIMIT 1", array(
'path' => $this->moduleArchive,
@@ -321,23 +346,25 @@ abstract class ConfigModule
*
* @return boolean true on success, false otherwise
*/
- public final function update($title)
+ public final function update(string $title = ''): bool
{
if ($this->moduleId === 0)
- Util::traceError('ConfigModule::update called when moduleId == 0');
- if (empty($title))
- $title = $this->moduleTitle;
+ ErrorHandler::traceError('ConfigModule::update called when moduleId == 0');
+ if (!empty($title)) {
+ $this->moduleTitle = $title;
+ }
if (!$this->validateConfig())
return false;
// Update
Database::exec("UPDATE configtgz_module SET title = :title, contents = :contents, status = :status, dateline = :now "
. " WHERE moduleid = :moduleid LIMIT 1", array(
'moduleid' => $this->moduleId,
- 'title' => $title,
+ 'title' => $this->moduleTitle,
'contents' => json_encode($this->moduleData),
'status' => 'OUTDATED',
'now' => time(),
));
+ $this->moduleStatus = 'OUTDATED';
return true;
}
@@ -346,16 +373,16 @@ abstract class ConfigModule
* Updating the database etc. will happen later through a callback.
*
* @param boolean $deleteOnError if true, the db entry will be deleted if generation failed
- * @param string $parent Parent task of this task
+ * @param string|null $parent Parent task of this task
* @param int $timeoutMs maximum time in milliseconds we wait for completion
* @return string|boolean task id if deferred generation was started,
* true if generation succeeded (without using a task or within $timeoutMs)
* false on error
*/
- public final function generate($deleteOnError, $parent = NULL, $timeoutMs = 0)
+ public final function generate(bool $deleteOnError, string $parent = NULL, int $timeoutMs = 0)
{
- if ($this->moduleId === 0 || $this->moduleTitle === false)
- Util::traceError('ConfigModule::generateAsync called on uninitialized/uninserted module!');
+ if ($this->moduleId === 0 || empty($this->moduleTitle))
+ ErrorHandler::traceError('ConfigModule::generateAsync called on uninitialized/uninserted module!');
$tmpTgz = '/tmp/bwlp-id-' . $this->moduleId . '_' . mt_rand() . '_' . time() . '.tgz';
$ret = $this->generateInternal($tmpTgz, $parent);
// Wait for generation if requested
@@ -388,10 +415,10 @@ abstract class ConfigModule
/**
* Delete the module.
*/
- public final function delete()
+ public final function delete(): void
{
if ($this->moduleId === 0)
- Util::traceError('ConfigModule::delete called with invalid module id!');
+ ErrorHandler::traceError('ConfigModule::delete called with invalid module id!');
$ret = Database::exec("DELETE FROM configtgz_module WHERE moduleid = :moduleid LIMIT 1", array(
'moduleid' => $this->moduleId
), true) !== false;
@@ -403,17 +430,19 @@ abstract class ConfigModule
$this->moduleTitle = false;
$this->moduleArchive = false;
}
- return $ret;
}
- private final function markUpdated($tmpTgz)
+ /**
+ * @param ?string $tmpTgz new tar archive to use for this module, or null if the old one is still valid
+ */
+ private function markUpdated(?string $tmpTgz): bool
{
if ($this->moduleId === 0)
- Util::traceError('ConfigModule::markUpdated called with invalid module id!');
- if ($this->moduleArchive === false)
+ ErrorHandler::traceError('ConfigModule::markUpdated called with invalid module id!');
+ if ($this->moduleArchive === null)
$this->moduleArchive = $this->createFileName();
// Move file
- if ($tmpTgz === false) {
+ if ($tmpTgz === null) {
if (!file_exists($this->moduleArchive)) {
EventLog::failure('ConfigModule::markUpdated for "' . $this->moduleTitle . '" called with no tmpTgz and no existing tgz!');
$this->markFailed();
@@ -453,24 +482,26 @@ abstract class ConfigModule
return $retval;
}
- private final function markFailed()
+ private function markFailed(): void
{
if ($this->moduleId === 0)
- Util::traceError('ConfigModule::markFailed called with invalid module id!');
- if ($this->moduleArchive === false)
+ ErrorHandler::traceError('ConfigModule::markFailed called with invalid module id!');
+ if ($this->moduleArchive === '') {
$this->moduleArchive = $this->createFileName();
- if (!file_exists($this->moduleArchive))
+ }
+ if (!file_exists($this->moduleArchive)) {
$status = 'MISSING';
- else
+ } else {
$status = 'OUTDATED';
- return Database::exec("UPDATE configtgz_module SET filepath = :filename, status = :status WHERE moduleid = :id LIMIT 1", array(
+ }
+ Database::exec("UPDATE configtgz_module SET filepath = :filename, status = :status WHERE moduleid = :id LIMIT 1", array(
'id' => $this->moduleId,
'filename' => $this->moduleArchive,
'status' => $status
- )) !== false;
+ ));
}
- public function dateline_s()
+ public function dateline_s(): string
{
return Util::prettyTime($this->dateline);
}
@@ -482,7 +513,7 @@ abstract class ConfigModule
* Override this if you need to handle this, otherwise
* the base implementation does nothing.
*/
- public function event_serverIpChanged()
+ public function event_serverIpChanged(): void
{
// Do::Nothing()
}
@@ -493,11 +524,10 @@ abstract class ConfigModule
* Will be called if the server's IP address changes. The event will be propagated
* to all config module classes so action can be taken if appropriate.
*/
- public static function serverIpChanged()
+ public static function serverIpChanged(): void
{
self::loadDb();
- $list = self::getAll();
- foreach ($list as $mod) {
+ foreach (self::getAll() ?? [] as $mod) {
$mod->event_serverIpChanged();
}
}
@@ -506,53 +536,51 @@ abstract class ConfigModule
* Called when (re)generating a config module failed, so we can
* update the status in the DB and add a server log entry.
*
- * @param array $task
- * @param array $args contains 'moduleid' and optionally 'deleteOnError' and 'tmpTgz'
+ * @param array $args contains 'moduleid' and optionally 'deleteOnError'
*/
- public static function generateFailed($task, $args)
+ public static function generateFailed(array $task, array $args): void
{
if (!isset($args['moduleid']) || !is_numeric($args['moduleid'])) {
EventLog::warning('Ignoring generateFailed event as it has no moduleid assigned.');
return;
}
$module = self::get($args['moduleid']);
- if ($module === false) {
+ if ($module === null) {
EventLog::warning('generateFailed callback for module id ' . $args['moduleid'] . ', but no instance could be generated.');
return;
}
- if (isset($task['data']['error']))
+ if (isset($task['data']['error'])) {
$error = $task['data']['error'];
- elseif (isset($task['data']['messages']))
+ } elseif (isset($task['data']['messages'])) {
$error = $task['data']['messages'];
- else
+ } else {
$error = '';
+ }
EventLog::failure("Generating module '" . $module->moduleTitle . "' failed.", $error);
- if ($args['deleteOnError'])
+ if ($args['deleteOnError'] ?? false) {
$module->delete();
- else
+ } else {
$module->markFailed();
+ }
}
/**
* (Re)generating a config module succeeded. Update db entry.
*
- * @param array $args contains 'moduleid' and optionally 'deleteOnError' and 'tmpTgz'
+ * @param array $args contains 'moduleid' and optionally 'tmpTgz'
*/
- public static function generateSucceeded($args)
+ public static function generateSucceeded(array $args): void
{
if (!isset($args['moduleid']) || !is_numeric($args['moduleid'])) {
EventLog::warning('Ignoring generateSucceeded event as it has no moduleid assigned.');
return;
}
$module = self::get($args['moduleid']);
- if ($module === false) {
+ if ($module === null) {
EventLog::warning('generateSucceeded callback for module id ' . $args['moduleid'] . ', but no instance could be generated.');
return;
}
- if (isset($args['tmpTgz']))
- $module->markUpdated($args['tmpTgz']);
- else
- $module->markUpdated(false);
+ $module->markUpdated($args['tmpTgz'] ?? null);
}
}
diff --git a/modules-available/sysconfig/inc/configmodule/branding.inc.php b/modules-available/sysconfig/inc/configmodule/branding.inc.php
index 8990dbec..7013e3ae 100644
--- a/modules-available/sysconfig/inc/configmodule/branding.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/branding.inc.php
@@ -14,34 +14,34 @@ class ConfigModule_Branding extends ConfigModule
const MODID = 'Branding';
const VERSION = 1;
-
+
+ /** @var false|string */
private $tmpFile = false;
- protected function generateInternal($tgz, $parent)
+ protected function generateInternal(string $tgz, ?string $parent)
{
if (!$this->validateConfig()) {
- return $this->archive() !== false && file_exists($this->archive()); // No new temp file given, old archive still exists, pretend it worked...
+ return !empty($this->archive()) && file_exists($this->archive()); // No new temp file given, old archive still exists, pretend it worked...
}
- $task = Taskmanager::submit('MoveFile', array(
+ return Taskmanager::submit('MoveFile', array(
'source' => $this->tmpFile,
'destination' => $tgz,
'parentTask' => $parent,
'failOnParentFail' => false
));
- return $task;
}
- protected function moduleVersion()
+ protected function moduleVersion(): int
{
return self::VERSION;
}
- protected function validateConfig()
+ protected function validateConfig(): bool
{
return $this->tmpFile !== false && file_exists($this->tmpFile);
}
- public function setData($key, $value)
+ public function setData(string $key, $value): bool
{
if ($key !== 'tmpFile' || !is_string($value) || !file_exists($value))
return false;
@@ -49,12 +49,12 @@ class ConfigModule_Branding extends ConfigModule
return true;
}
- public function getData($key)
+ public function getData(?string $key): bool
{
return false;
}
- public function allowDownload()
+ public function allowDownload(): bool
{
return true;
}
diff --git a/modules-available/sysconfig/inc/configmodule/customodule.inc.php b/modules-available/sysconfig/inc/configmodule/customodule.inc.php
index 3c10bada..0b8e38d2 100644
--- a/modules-available/sysconfig/inc/configmodule/customodule.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/customodule.inc.php
@@ -12,48 +12,62 @@ ConfigModule::registerModule(
class ConfigModule_CustomModule extends ConfigModule
{
const MODID = 'CustomModule';
- const VERSION = 1;
-
+ const VERSION = 2;
+
+ /** @var false|string */
private $tmpFile = false;
- protected function generateInternal($tgz, $parent)
+ protected function generateInternal(string $tgz, ?string $parent)
{
if (!$this->validateConfig()) {
- return $this->archive() !== false && file_exists($this->archive()); // No new temp file given, old archive still exists, pretend it worked...
+ // No temp file given from wizard
+ // Old archive still exists? pretend it worked...
+ if ($this->archive() === '' || !file_exists($this->archive()))
+ return false;
+ if ($this->currentVersion() == 1) {
+ // Need an upgrade
+ return Taskmanager::submit('RecompressArchive', array(
+ 'inputFiles' => [$this->archive() => false],
+ 'outputFile' => $tgz,
+ 'forceRoot' => true, // Force this for old modules for backward compat
+ ));
+ }
+ // Nothing to do
+ return true;
}
- $task = Taskmanager::submit('MoveFile', array(
+ return Taskmanager::submit('MoveFile', array(
'source' => $this->tmpFile,
'destination' => $tgz,
'parentTask' => $parent,
'failOnParentFail' => false
));
- return $task;
}
- protected function moduleVersion()
+ protected function moduleVersion(): int
{
return self::VERSION;
}
- protected function validateConfig()
+ protected function validateConfig(): bool
{
return $this->tmpFile !== false && file_exists($this->tmpFile);
}
- public function setData($key, $value)
+ public function setData(string $key, $value): bool
{
+ // Sets the temp file from the wizard, where it stored the processed archive
if ($key !== 'tmpFile' || !file_exists($value))
return false;
$this->tmpFile = $value;
return true;
}
- public function getData($key)
+ public function getData(?string $key): bool
{
return false;
}
- public function allowDownload()
+ public function allowDownload(): bool
{
return true;
}
diff --git a/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php b/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php
index 7af4671e..64af4c0e 100644
--- a/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/ldapauth.inc.php
@@ -5,7 +5,7 @@ class ConfigModule_LdapAuth extends ConfigModuleBaseLdap
const MODID = 'LdapAuth';
- protected function preTaskmanagerHook(&$config)
+ protected function preTaskmanagerHook(array &$config)
{
// Just set the flag so the taskmanager job knows we're dealing with a normal ldap server,
// not AD scheme
diff --git a/modules-available/sysconfig/inc/configmodule/screensaver.inc.php b/modules-available/sysconfig/inc/configmodule/screensaver.inc.php
index ed97941e..1797331c 100644
--- a/modules-available/sysconfig/inc/configmodule/screensaver.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/screensaver.inc.php
@@ -14,7 +14,7 @@ class ConfigModule_Screensaver extends ConfigModule
const MODID = 'Screensaver';
const VERSION = 1;
- protected function generateInternal($tgz, $parent)
+ protected function generateInternal(string $tgz, ?string $parent)
{
/* Validate if all data are available */
if (!$this->validateConfig())
@@ -23,30 +23,27 @@ class ConfigModule_Screensaver extends ConfigModule
/* Give the Taskmanager the job and create the tgz */
$taskId = 'xscreensaver' . mt_rand() . '-' . microtime(true);
- $task = Taskmanager::submit('MakeTarball', array(
+ return Taskmanager::submit('MakeTarball', array(
'id' => $taskId,
'files' => $this->getFileArray(),
'destination' => $tgz,
), false);
-
- return $task;
}
- protected function moduleVersion()
+ protected function moduleVersion(): int
{
return self::VERSION;
}
- protected function validateConfig()
+ protected function validateConfig(): bool
{
- return isset($this->moduleData['qss']) &&
- isset($this->moduleData['texts']) &&
- isset($this->moduleData['texts']['text-idle-kill']) &&
- isset($this->moduleData['texts']['text-no-timeout']) &&
- isset($this->moduleData['texts']['text-shutdown']);
+ return isset($this->moduleData['texts']['text-no-timeout'])
+ && isset($this->moduleData['texts']['text-idle-kill'])
+ && isset($this->moduleData['texts']['text-shutdown'])
+ && isset($this->moduleData['qss']);
}
- public function setData($key, $value)
+ public function setData(string $key, $value): bool
{
switch ($key) {
case 'qss':
@@ -60,17 +57,15 @@ class ConfigModule_Screensaver extends ConfigModule
return true;
}
- public function allowDownload()
+ public function allowDownload(): bool
{
return false;
}
/**
* Creates a map with filepath => file content
- *
- * @return array in the form of Map<String, byte[]>
*/
- private function getFileArray()
+ private function getFileArray(): array
{
$files = array(
'/opt/openslx/xscreensaver/style.qss' => $this->moduleData['qss'],
@@ -100,7 +95,7 @@ class ConfigModule_Screensaver extends ConfigModule
return $files;
}
- private function wrapHtmlTags($text_name)
+ private function wrapHtmlTags(string $text_name): string
{
return '<html><body>' . $this->moduleData['texts'][$text_name] . '</body></html>';
}
diff --git a/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php b/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php
index 9975f789..a62d1035 100644
--- a/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php
+++ b/modules-available/sysconfig/inc/configmodule/sshconfig.inc.php
@@ -5,7 +5,7 @@ ConfigModule::registerModule(
Dictionary::translateFileModule('sysconfig', 'config-module', 'sshconfig_title'), // Title
Dictionary::translateFileModule('sysconfig', 'config-module', 'sshconfig_description'), // Description
Dictionary::translateFileModule('sysconfig', 'config-module', 'group_sshconfig'), // Group
- false, // Only one per config?
+ true, // Only one per config?
500
);
@@ -14,7 +14,7 @@ class ConfigModule_SshConfig extends ConfigModule
const MODID = 'SshConfig';
const VERSION = 1;
- protected function generateInternal($tgz, $parent)
+ protected function generateInternal(string $tgz, ?string $parent)
{
if (!$this->validateConfig())
return false;
@@ -23,36 +23,50 @@ class ConfigModule_SshConfig extends ConfigModule
'failOnParentFail' => false,
'parent' => $parent
);
- // Create config module, which will also check if the pubkey is valid
return Taskmanager::submit('SshdConfigGenerator', $config);
}
- protected function moduleVersion()
+ protected function moduleVersion(): int
{
return self::VERSION;
}
- protected function validateConfig()
+ protected function validateConfig(): bool
{
- return isset($this->moduleData['publicKey']) && isset($this->moduleData['allowPasswordLogin']) && isset($this->moduleData['listenPort']);
+ // UPGRADE
+ if (isset($this->moduleData['allowPasswordLogin']) && !isset($this->moduleData['allowedUsersLogin'])) {
+ $this->moduleData['allowPasswordLogin'] = strtoupper($this->moduleData['allowPasswordLogin']);
+ if (!in_array($this->moduleData['allowPasswordLogin'], ['NO', 'USER_ONLY', 'YES'])) {
+ $this->moduleData['allowPasswordLogin'] = 'NO';
+ }
+ $this->moduleData['allowedUsersLogin'] = 'ALL';
+ }
+ return isset($this->moduleData['allowPasswordLogin']) && isset($this->moduleData['allowedUsersLogin'])
+ && isset($this->moduleData['listenPort']);
}
- public function setData($key, $value)
+ public function setData(string $key, $value): bool
{
switch ($key) {
case 'publicKey':
- break;
+ if ($value === false) {
+ error_log('Unsetting publicKey');
+ unset($this->moduleData[$key]);
+ return true;
+ }
+ return false;
case 'allowPasswordLogin':
- if ($value === true || $value === 'yes')
- $value = 'yes';
- elseif ($value === false || $value === 'no')
- $value = 'no';
- else
+ if (!in_array($value, ['NO', 'USER_ONLY', 'YES']))
+ return false;
+ break;
+ case 'allowedUsersLogin';
+ if (!in_array($value, ['ROOT_ONLY', 'USER_ONLY', 'ALL']))
return false;
break;
case 'listenPort':
if (!is_numeric($value) || $value < 1 || $value > 65535)
return false;
+ $value = (int)$value;
break;
default:
return false;
diff --git a/modules-available/sysconfig/inc/configmodule/sshkey.inc.php b/modules-available/sysconfig/inc/configmodule/sshkey.inc.php
new file mode 100644
index 00000000..e4a55ad7
--- /dev/null
+++ b/modules-available/sysconfig/inc/configmodule/sshkey.inc.php
@@ -0,0 +1,55 @@
+<?php
+
+ConfigModule::registerModule(
+ ConfigModule_SshKey::MODID, // ID
+ Dictionary::translateFileModule('sysconfig', 'config-module', 'sshkey_title'), // Title
+ Dictionary::translateFileModule('sysconfig', 'config-module', 'sshkey_description'), // Description
+ Dictionary::translateFileModule('sysconfig', 'config-module', 'group_sshkey'), // Group
+ false, // Only one per config?
+ 510
+);
+
+class ConfigModule_SshKey extends ConfigModule
+{
+ const MODID = 'SshKey';
+ const VERSION = 1;
+
+ protected function generateInternal(string $tgz, ?string $parent)
+ {
+ if (!$this->validateConfig())
+ return false;
+ $config = array(
+ 'files' => [
+ '/root/.ssh/authorized_keys.d/sshkey_' . $this->id() . '_' . Util::sanitizeFilename($this->title()) . '.pub'
+ => $this->moduleData['publicKey']],
+ 'destination' => $tgz,
+ 'failOnParentFail' => false,
+ 'parent' => $parent
+ );
+ // Create config module, which will also check if the pubkey is valid
+ return Taskmanager::submit('MakeTarball', $config);
+ }
+
+ protected function moduleVersion(): int
+ {
+ return self::VERSION;
+ }
+
+ protected function validateConfig(): bool
+ {
+ return isset($this->moduleData['publicKey']);
+ }
+
+ public function setData(string $key, $value): bool
+ {
+ switch ($key) {
+ case 'publicKey':
+ break;
+ default:
+ return false;
+ }
+ $this->moduleData[$key] = $value;
+ return true;
+ }
+
+}
diff --git a/modules-available/sysconfig/inc/configmodulebaseldap.inc.php b/modules-available/sysconfig/inc/configmodulebaseldap.inc.php
index 39f4f68e..770a40e6 100644
--- a/modules-available/sysconfig/inc/configmodulebaseldap.inc.php
+++ b/modules-available/sysconfig/inc/configmodulebaseldap.inc.php
@@ -3,15 +3,15 @@
abstract class ConfigModuleBaseLdap extends ConfigModule
{
- const VERSION = 3;
+ const VERSION = 4;
private static $REQUIRED_FIELDS = array('server', 'searchbase');
- private static $OPTIONAL_FIELDS = array('binddn', 'bindpw', 'home', 'ssl', 'fixnumeric', 'fingerprint', 'certificate', 'homeattr',
+ private static $OPTIONAL_FIELDS = array('binddn', 'bindpw', 'home', 'ssl', 'fingerprint', 'certificate', 'homeattr',
'shareRemapMode', 'shareRemapCreate', 'shareDocuments', 'shareDownloads', 'shareDesktop', 'shareMedia',
'shareOther', 'shareHomeDrive', 'shareDomain', 'credentialPassthrough', 'mapping', 'genuid',
'ldapAttrMountOpts', 'shareHomeMountOpts', 'nohomewarn');
- public static function getMapping($config = false, &$empty = true)
+ public static function getMapping(array $config = null, ?bool &$empty = true): array
{
$list = array(
['name' => 'uid', 'field' => 'uid', 'ad' => 'sAMAccountName'],
@@ -46,10 +46,10 @@ abstract class ConfigModuleBaseLdap extends ConfigModule
*
* @param string $command start, restart, check
* @param bool|int|int[] $ids list of IDs to run command on, or false meaning "all"
- * @param string $parent if not NULL, this will be the parent task of the launch-task
+ * @param string|null $parent if not NULL, this will be the parent task of the launch-task
* @return boolean|string false on error, id of task otherwise
*/
- public static function ldadp($command = 'start', $ids = false, $parent = null)
+ public static function ldadp(string $command = 'start', $ids = false, string $parent = null)
{
if ($ids === false) {
$ids = self::getActiveModuleIds();
@@ -67,7 +67,7 @@ abstract class ConfigModuleBaseLdap extends ConfigModule
return $task['id'];
}
- protected function generateInternal($tgz, $parent)
+ protected function generateInternal(string $tgz, ?string $parent)
{
$config = $this->moduleData;
if (isset($config['certificate']) && !is_string($config['certificate'])) {
@@ -95,15 +95,14 @@ abstract class ConfigModuleBaseLdap extends ConfigModule
if (!isset($config['shareHomeDrive'])) {
$config['shareHomeDrive'] = 'H:';
}
- if (!isset($config['fixnumeric'])) {
- $config['fixnumeric'] = 's';
- }
- $config['genuid'] = isset($config['genuid']) && !empty($config['genuid']);
+ // This is now always on, as we mask it transparently in our lightdm greeter
+ $config['fixnumeric'] = 'true';
+ $config['genuid'] = !empty($config['genuid']);
$config['nohomewarn'] = isset($config['nohomewarn']) ? (int)$config['nohomewarn'] : 0;
$this->preTaskmanagerHook($config);
$task = Taskmanager::submit('CreateLdapConfig', $config);
if (is_array($task) && isset($task['id'])) {
- self::ldadp('restart', $this->id(), $task['id']); // TODO: Use --restart for this one only
+ self::ldadp('restart', $this->id(), $task['id']);
}
return $task;
}
@@ -112,25 +111,23 @@ abstract class ConfigModuleBaseLdap extends ConfigModule
* Hook called before running CreateLdapConfig task with the
* configuration to be passed to the task. Passed by reference
* so it can be modified.
- *
- * @param array $config
*/
- protected function preTaskmanagerHook(&$config)
+ protected function preTaskmanagerHook(array &$config)
{
}
- protected function moduleVersion()
+ protected function moduleVersion(): int
{
return self::VERSION;
}
- protected function validateConfig()
+ protected function validateConfig(): bool
{
// Check if required fields are filled
- return Util::hasAllKeys($this->moduleData, self::$REQUIRED_FIELDS);
+ return ArrayUtil::hasAllKeys($this->moduleData, self::$REQUIRED_FIELDS);
}
- public function setData($key, $value)
+ public function setData(string $key, $value): bool
{
if (!in_array($key, self::$REQUIRED_FIELDS) && !in_array($key, self::$OPTIONAL_FIELDS))
return false;
@@ -143,7 +140,7 @@ abstract class ConfigModuleBaseLdap extends ConfigModule
/**
* Server IP changed - rebuild all AD modules.
*/
- public function event_serverIpChanged()
+ public function event_serverIpChanged(): void
{
$this->generate(false);
}
diff --git a/modules-available/sysconfig/inc/configtgz.inc.php b/modules-available/sysconfig/inc/configtgz.inc.php
index c1df2c93..8ac87908 100644
--- a/modules-available/sysconfig/inc/configtgz.inc.php
+++ b/modules-available/sysconfig/inc/configtgz.inc.php
@@ -4,29 +4,28 @@ class ConfigTgz
{
private $configId = 0;
- private $configTitle = false;
- private $file = false;
+ private $configTitle = '';
+ private $file = '';
private $modules = array();
private function __construct()
{
- ;
}
- public function id()
+ public function id(): int
{
return $this->configId;
}
- public function title()
+ public function title(): string
{
return $this->configTitle;
}
- public function areAllModulesUpToDate()
+ public function areAllModulesUpToDate(): bool
{
if (!$this->configId > 0)
- Util::traceError('ConfigTgz::areAllModulesUpToDate called on un-inserted config.tgz!');
+ ErrorHandler::traceError('ConfigTgz::areAllModulesUpToDate called on un-inserted config.tgz!');
foreach ($this->modules as $module) {
if (!empty($module['filepath']) && file_exists($module['filepath'])) {
if ($module['status'] !== 'OK')
@@ -38,25 +37,32 @@ class ConfigTgz
return true;
}
- public function isActive()
+ public function isActive(): bool
{
return readlink(CONFIG_HTTP_DIR . '/default/config.tgz') === $this->file;
}
-
- public function getModuleIds()
+
+ /**
+ * @return int[]
+ */
+ public function getModuleIds(): array
{
- $ret = array();
+ $ret = [];
foreach ($this->modules as $module) {
- $ret[] = $module['moduleid'];
+ $ret[] = (int)$module['moduleid'];
}
return $ret;
}
-
- public function update($title, $moduleIds)
+
+ /**
+ * @param string $title New title for module
+ * @param int[] $moduleIds List of modules to include in this config
+ */
+ public function update(string $title, array $moduleIds): void
{
- if (!is_array($moduleIds))
- return false;
- $this->configTitle = $title;
+ if (!empty($title)) {
+ $this->configTitle = $title;
+ }
$this->modules = array();
// Get all modules to put in config
$idstr = '0'; // Passed directly in query. Make sure no SQL injection is possible
@@ -67,7 +73,7 @@ class ConfigTgz
// Delete old connections
Database::exec("DELETE FROM configtgz_x_module WHERE configid = :configid", array('configid' => $this->configId));
// Make connection
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
Database::exec("INSERT INTO configtgz_x_module (configid, moduleid) VALUES (:configid, :moduleid)", array(
'configid' => $this->configId,
'moduleid' => $row['moduleid']
@@ -77,41 +83,41 @@ class ConfigTgz
// Update name
Database::exec("UPDATE configtgz SET title = :title, status = :status, dateline = :now WHERE configid = :configid LIMIT 1", array(
'configid' => $this->configId,
- 'title' => $title,
+ 'title' => $this->configTitle,
'status' => 'OUTDATED',
'now' => time(),
));
- return true;
}
/**
*
- * @param bool $deleteOnError
- * @param int $timeoutMs
- * @return string - OK (success)
- * - OUTDATED (updating failed, but old version still exists)
- * - MISSING (failed and no old version available)
+ * @param bool $deleteOnError Delete this config in case of error?
+ * @param int $timeoutMs max time to wait for completion
+ * @param string|null $parentTask parent task to order this (re)build after
+ * @return string|bool true=success, false=error, string=taskid, still running
*/
- public function generate($deleteOnError = false, $timeoutMs = 0)
+ public function generate(bool $deleteOnError = false, int $timeoutMs = 0, ?string $parentTask = null)
{
- if (!($this->configId > 0) || !is_array($this->modules) || $this->file === false)
- Util::traceError ('configId <= 0 or modules not array in ConfigTgz::rebuild()');
+ if (!($this->configId > 0) || empty($this->file))
+ ErrorHandler::traceError('configId <= 0 or no file in ConfigTgz::rebuild()');
$files = array();
// Get all config modules for system config
foreach ($this->modules as $module) {
if (!empty($module['filepath']) && file_exists($module['filepath'])) {
- $files[] = $module['filepath'];
+ // Dupcheck only for custom modules for now
+ $files[$module['filepath']] = ($module['moduletype'] === 'CustomModule');
}
}
- $task = self::recompress($files, $this->file);
+ $task = self::recompress($files, $this->file, $parentTask);
// Wait for completion
- if ($timeoutMs > 0 && !Taskmanager::isFailed($task) && !Taskmanager::isFinished($task))
+ if ($timeoutMs > 0 && !Taskmanager::isFailed($task) && !Taskmanager::isFinished($task)) {
$task = Taskmanager::waitComplete($task, $timeoutMs);
- if ($task === true || (isset($task['statusCode']) && $task['statusCode'] === Taskmanager::TASK_FINISHED)) {
+ }
+ if (Taskmanager::isFinished($task)) {
// Success!
- $this->markUpdated();
+ $this->markUpdated($task);
return true;
}
if (!is_array($task) || !isset($task['id']) || Taskmanager::isFailed($task)) {
@@ -131,54 +137,81 @@ class ConfigTgz
return $task['id'];
}
- public function delete()
+ public function delete(): bool
{
if ($this->configId === 0)
- Util::traceError('ConfigTgz::delete called with invalid config id!');
+ ErrorHandler::traceError('ConfigTgz::delete called with invalid config id!');
$ret = Database::exec("DELETE FROM configtgz WHERE configid = :configid LIMIT 1",
['configid' => $this->configId], true);
if ($ret !== false) {
- if ($this->file !== false)
+ if (!empty($this->file)) {
Taskmanager::submit('DeleteFile', array('file' => $this->file), true);
+ }
$this->configId = 0;
- $this->modules = false;
- $this->file = false;
+ $this->modules = [];
+ $this->file = '';
}
return $ret !== false;
}
- public function markOutdated()
+ public function markOutdated(): void
{
if ($this->configId === 0)
- Util::traceError('ConfigTgz::markOutdated called with invalid config id!');
- return $this->mark('OUTDATED');
+ ErrorHandler::traceError('ConfigTgz::markOutdated called with invalid config id!');
+ $this->mark('OUTDATED');
}
- private function markUpdated()
+ private function markUpdated(array $task): void
{
if ($this->configId === 0)
- Util::traceError('ConfigTgz::markUpdated called with invalid config id!');
- if ($this->areAllModulesUpToDate())
- return $this->mark('OK');
- return $this->mark('OUTDATED');
+ ErrorHandler::traceError('ConfigTgz::markUpdated called with invalid config id!');
+ if ($this->areAllModulesUpToDate()) {
+ if (empty($task['data']['warnings'])) {
+ $warnings = '';
+ } else {
+ // There have been warnings while generating the combined archive
+ // Most likely duplicate file entries.
+ // Get mapping of moduleid to module name for prettier log display
+ $res = Database::simpleQuery('SELECT moduleid, title FROM configtgz_module');
+ $mods = [];
+ foreach ($res as $row) {
+ $mods[$row['moduleid']] = $row['title'];
+ }
+ // Now extract module id from filename and if applicable, replace filename by module name
+ $warnings = preg_replace_callback('#/opt/openslx/configs/modules/(\w+)_id-(\d+)__.*$#m', function ($m) use ($mods) {
+ if (!isset($mods[$m[2]]))
+ return $m[0];
+ return $mods[$m[2]] . ' (' . $m[1] . '#' . $m[2] . ')';
+ }, $task['data']['warnings']);
+ }
+ Database::exec("UPDATE configtgz SET status = :status, warnings = :warnings
+ WHERE configid = :configid LIMIT 1", [
+ 'configid' => $this->configId,
+ 'status' => 'OK',
+ 'warnings' => $warnings,
+ ]);
+ return;
+ }
+ $this->mark('OUTDATED');
}
- private function markFailed()
+ private function markFailed(): void
{
if ($this->configId === 0)
- Util::traceError('ConfigTgz::markFailed called with invalid config id!');
- if ($this->file === false || !file_exists($this->file))
- return $this->mark('MISSING');
- return $this->mark('OUTDATED');
+ ErrorHandler::traceError('ConfigTgz::markFailed called with invalid config id!');
+ if (empty($this->file) || !file_exists($this->file)) {
+ $this->mark('MISSING');
+ } else {
+ $this->mark('OUTDATED');
+ }
}
- private function mark($status)
+ private function mark($status): void
{
- Database::exec("UPDATE configtgz SET status = :status WHERE configid = :configid LIMIT 1", array(
+ Database::exec("UPDATE configtgz SET status = :status WHERE configid = :configid LIMIT 1", [
'configid' => $this->configId,
- 'status' => $status
- ));
- return $status;
+ 'status' => $status,
+ ]);
}
/*
@@ -186,28 +219,30 @@ class ConfigTgz
*/
/**
- * @param string[] $files source files to include
+ * @param bool[] $files source files to include key = file, value = dupCheck
* @param string $destFile where to store final result
* @return false|array taskmanager task
*/
- private static function recompress($files, $destFile)
+ private static function recompress(array $files, string $destFile, $parentTask = null)
{
// Get stuff other modules want to inject
$handler = function($hook) {
include $hook->file;
- return isset($file) ? $file : false;
+ return $file ?? false;
};
foreach (Hook::load('config-tgz') as $hook) {
$file = $handler($hook);
if ($file !== false) {
- $files[] = $file;
+ $files[$file] = true;
}
}
// Hand over to tm
return Taskmanager::submit('RecompressArchive', array(
'inputFiles' => $files,
- 'outputFile' =>$destFile
+ 'outputFile' =>$destFile,
+ 'parentTask' => $parentTask,
+ 'failOnParentFail' => false,
));
}
@@ -216,15 +251,15 @@ class ConfigTgz
* on each one. This mostly makes sense to call if a global module
* that is injected via a hook has changed.
*/
- public static function rebuildAllConfigs()
+ public static function rebuildAllConfigs(): void
{
Database::exec("UPDATE configtgz SET status = :status", array(
'status' => 'OUTDATED'
));
$res = Database::simpleQuery("SELECT configid FROM configtgz");
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
$configTgz = self::get($row['configid']);
- if ($configTgz !== false) {
+ if ($configTgz !== null) {
$configTgz->generate();
}
}
@@ -233,12 +268,10 @@ class ConfigTgz
/**
* @param string $title Title of config
* @param int[] $moduleIds Modules to include in config
- * @return false|ConfigTgz The module instance, false on error
+ * @return ConfigTgz The module instance
*/
- public static function insert($title, $moduleIds)
+ public static function insert(string $title, array $moduleIds): ConfigTgz
{
- if (!is_array($moduleIds))
- return false;
$instance = new ConfigTgz;
$instance->configTitle = $title;
// Create output file name (config.tgz)
@@ -260,7 +293,7 @@ class ConfigTgz
}
$res = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_module WHERE moduleid IN ($idstr)");
// Make connection
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
Database::exec("INSERT INTO configtgz_x_module (configid, moduleid) VALUES (:configid, :moduleid)", array(
'configid' => $instance->configId,
'moduleid' => $row['moduleid']
@@ -270,53 +303,53 @@ class ConfigTgz
return $instance;
}
- public static function get($configId)
+ /**
+ * @param array{configid: int, title: string, filepath: string} $row Input data, fields mandatory
+ */
+ private static function instanceFromRow(array $row): ConfigTgz
{
- $ret = Database::queryFirst("SELECT configid, title, filepath FROM configtgz WHERE configid = :configid", array(
- 'configid' => $configId
- ));
- if ($ret === false)
- return false;
$instance = new ConfigTgz;
- $instance->configId = $ret['configid'];
- $instance->configTitle = $ret['title'];
- $instance->file = $ret['filepath'];
- $ret = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_x_module "
+ $instance->configId = $row['configid'];
+ $instance->configTitle = $row['title'];
+ $instance->file = $row['filepath'];
+ $innerRes = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_x_module "
. " INNER JOIN configtgz_module USING (moduleid) "
. " WHERE configid = :configid", array('configid' => $instance->configId));
$instance->modules = array();
- while ($row = $ret->fetch(PDO::FETCH_ASSOC)) {
- $instance->modules[] = $row;
+ foreach ($innerRes as $innerRow) {
+ $instance->modules[] = $innerRow;
}
return $instance;
}
+ public static function get(int $configId): ?ConfigTgz
+ {
+ $ret = Database::queryFirst("SELECT configid, title, filepath FROM configtgz WHERE configid = :configid", array(
+ 'configid' => $configId
+ ));
+ if ($ret === false)
+ return null;
+ return self::instanceFromRow($ret);
+ }
+
/**
* @param int $moduleId ID of config module
- * @return ConfigTgz[]|false
+ * @return ConfigTgz[]
*/
- public static function getAllForModule($moduleId)
+ public static function getAllForModule(int $moduleId): array
{
$res = Database::simpleQuery("SELECT configid, title, filepath FROM configtgz_x_module "
. " INNER JOIN configtgz USING (configid) "
. " WHERE moduleid = :moduleid", array(
'moduleid' => $moduleId
));
- if ($res === false)
- return false;
+ if ($res === false) {
+ EventLog::warning('ConfigTgz::getAllForModule failed: ' . Database::lastError());
+ return [];
+ }
$list = array();
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- $instance = new ConfigTgz;
- $instance->configId = $row['configid'];
- $instance->configTitle = $row['title'];
- $instance->file = $row['filepath'];
- $innerRes = Database::simpleQuery("SELECT moduleid, moduletype, filepath, status FROM configtgz_x_module "
- . " INNER JOIN configtgz_module USING (moduleid) "
- . " WHERE configid = :configid", array('configid' => $instance->configId));
- $instance->modules = array();
- while ($innerRow = $innerRes->fetch(PDO::FETCH_ASSOC)) {
- $instance->modules[] = $innerRow;
- }
+ foreach ($res as $row) {
+ $instance = self::instanceFromRow($row);
$list[] = $instance;
}
return $list;
@@ -326,50 +359,52 @@ class ConfigTgz
* Called when (re)generating a config tgz failed, so we can
* update the status in the DB and add a server log entry.
*
- * @param array $task
* @param array $args contains 'configid' and optionally 'deleteOnError'
*/
- public static function generateFailed($task, $args)
+ public static function generateFailed(array $task, array $args): void
{
if (!isset($args['configid']) || !is_numeric($args['configid'])) {
EventLog::warning('Ignoring generateFailed event as it has no configid assigned.');
return;
}
$config = self::get($args['configid']);
- if ($config === false) {
+ if ($config === null) {
EventLog::warning('generateFailed callback for config id ' . $args['configid'] . ', but no instance could be generated.');
return;
}
- if (isset($task['data']['error']))
+ if (isset($task['data']['error'])) {
$error = $task['data']['error'];
- elseif (isset($task['data']['messages']))
+ } elseif (isset($task['data']['messages'])) {
$error = $task['data']['messages'];
- else
+ } else {
$error = '';
+ }
EventLog::failure("Generating config.tgz '" . $config->configTitle . "' failed.", $error);
- if ($args['deleteOnError'])
+ if ($args['deleteOnError']) {
$config->delete();
- else
+ } else {
$config->markFailed();
+ }
}
/**
* (Re)generating a config tgz succeeded. Update db entry.
*
+ * @param array $task the task object
* @param array $args contains 'configid' and optionally 'deleteOnError'
*/
- public static function generateSucceeded($args)
+ public static function generateSucceeded(array $task, array $args): void
{
if (!isset($args['configid']) || !is_numeric($args['configid'])) {
EventLog::warning('Ignoring generateSucceeded event as it has no configid assigned.');
return;
}
$config = self::get($args['configid']);
- if ($config === false) {
+ if ($config === null) {
EventLog::warning('generateSucceeded callback for config id ' . $args['configid'] . ', but no instance could be generated.');
return;
}
- $config->markUpdated();
+ $config->markUpdated($task);
}
-
+
}
diff --git a/modules-available/sysconfig/inc/ldap.inc.php b/modules-available/sysconfig/inc/ldap.inc.php
index 349a662e..e974a8a3 100644
--- a/modules-available/sysconfig/inc/ldap.inc.php
+++ b/modules-available/sysconfig/inc/ldap.inc.php
@@ -3,7 +3,7 @@
class Ldap
{
- public static function normalizeDn($dn)
+ public static function normalizeDn(string $dn): string
{
return trim(preg_replace('/[,;]\s*/', ',', $dn));
}
diff --git a/modules-available/sysconfig/inc/ppd.inc.php b/modules-available/sysconfig/inc/ppd.inc.php
index 9bd5d171..c28e0355 100644
--- a/modules-available/sysconfig/inc/ppd.inc.php
+++ b/modules-available/sysconfig/inc/ppd.inc.php
@@ -247,8 +247,8 @@ class Ppd
private $data;
private $dataLen;
- private $error;
- private $warnings;
+ private $error = null;
+ private $warnings = [];
private $knownKeywordMalformed;
@@ -301,16 +301,16 @@ class Ppd
$this->dataLen = strlen($this->data);
$this->encoder = false;
$this->sourceEncoding = false;
- $this->error = false;
+ $this->error = null;
$this->warnings = array();
$this->knownKeywordMalformed = false;
$this->settings = array();
$this->requiredKeywords = array();
// Parse
- /* @var $rawOption \PpdOption */
- /* @var $currentBlock \PpdBlockInternal */
- $currentBlock = false;
+ /* @var PpdOption $rawOption */
+ /* @var ?PpdBlockInternal $currentBlock */
+ $currentBlock = null;
$inRawBlock = false; // True if in a multi-line InvocationValue or QuotedValue (3.6: Parsing Summary for Values)
$wantsEnd = false;
// For now we ignore values mostly while parsing. The spec says that InvocationValues must only contain printable
@@ -318,9 +318,9 @@ class Ppd
$lStart = -1;
$lEnd = -1;
$no = 0;
- while ($lStart < $this->dataLen && $lEnd !== false) {
+ while ($lStart < $this->dataLen) {
unset($mainKeyword, $optionKeyword, $optionTranslation, $option, $value, $valueTranslation);
- if ($no !== 0 && $this->data{$lEnd} === "\r" && $this->data{$lEnd + 1} === "\n") {
+ if ($no !== 0 && $this->data[$lEnd] === "\r" && $this->data[$lEnd + 1] === "\n") {
$lEnd++;
}
if ($no === 1) {
@@ -332,6 +332,8 @@ class Ppd
}
$lStart = $lEnd + 1;
$lEnd = $this->nextLineEnd($lStart);
+ if ($lEnd === null)
+ break;
$no++;
// Validate
$len = $lEnd - $lStart;
@@ -343,7 +345,7 @@ class Ppd
$this->warn($no, 'Exceeds length of 255');
}
if (!$inRawBlock && preg_match_all('/[^\x09\x0A\x0D\x20-\xFF]/', $line, $out)) {
- $chars = $this->escapeBinaryArray($out[0]);
+ $chars = self::escapeBinaryArray($out[0]);
$this->warn($no, 'Contains invalid character(s) ' . $chars);
}
// Handle
@@ -373,13 +375,13 @@ class Ppd
}
}
// 3) Handle "key [option]: value"
- if ($line{0} === '*') {
- if ($line{1} === '%') {
+ if ($line[0] === '*') {
+ if ($line[1] === '%') {
// Skip comment
continue;
}
$parts = preg_split('/\s*:\s*/', $line, 2); // TODO: UIConstrains
- if (count($parts) !== 2) {
+ if (!is_array($parts) || count($parts) !== 2) {
$this->warn($no, 'No colon found; not in "key [option]: value" format, ignoring line');
continue;
}
@@ -390,11 +392,12 @@ class Ppd
continue;
}
$mainKeyword = $out[1];
- $optionKeyword = isset($out[3]) ? $out[3] : false;
+ $optionKeyword = $out[3] ?? null;
$optionTranslation = isset($out[4]) ? $this->unhexTranslation($no, substr($out[4], 1)) : $optionKeyword; // If no translation given, fallback to option
// 3b) Handle value
+ /** @var string $value */
$value = $parts[1];
- if ($value{0} === '"') {
+ if ($value[0] === '"') {
// Start of InvocationValue or QuotedValue
if (preg_match(',^"([^"]*)"(/.*)?$,', $value, $vMatch)) {
// Single line
@@ -419,28 +422,23 @@ class Ppd
// Key-value-pair parsed, now the fun part
// Special cases for opening closing certain groups
if ($mainKeyword === 'OpenGroup') {
- if ($currentBlock !== false) {
+ if ($currentBlock !== null) {
$this->error = 'Line ' . $no . ': OpenGroup while other block (type=' . $currentBlock->type
. ', id=' . $currentBlock->id . ') was not closed yet';
return;
}
// TODO: Check unique
- $nb = new PpdBlockInternal($value, $valueTranslation, 'Group', $currentBlock, $lStart);
- if ($currentBlock !== false) {
- $currentBlock->childBlocks[] = $nb;
- }
+ $nb = new PpdBlockInternal($value, $valueTranslation, 'Group', null, $lStart);
$currentBlock = $nb;
continue;
} elseif ($mainKeyword === 'OpenSubGroup') {
- if ($currentBlock === false || $currentBlock->type !== 'Group') {
+ if ($currentBlock === null || $currentBlock->type !== 'Group') {
$this->error = 'Line ' . $no . ': OpenSubGroup with no preceding OpenGroup';
return;
}
// TODO: Check unique
$nb = new PpdBlockInternal($value, $valueTranslation, 'SubGroup', $currentBlock, $lStart);
- if ($currentBlock !== false) {
- $currentBlock->childBlocks[] = $nb;
- }
+ $currentBlock->childBlocks[] = $nb;
$currentBlock = $nb;
continue;
} elseif ($mainKeyword === 'OpenUI' || $mainKeyword === 'JCLOpenUI') {
@@ -450,23 +448,24 @@ class Ppd
} else {
$type = substr($type, 4);
}
- if ($currentBlock !== false && $currentBlock->isUi()) {
+ if ($currentBlock !== null && $currentBlock->isUi()) {
$this->error = 'Line ' . $no . ': ' . $mainKeyword . ' while previous ' . $type . ' "'
. $currentBlock->id . '" was not closed yet';
return;
}
- if ($optionKeyword === false) {
+ if ($optionKeyword === null) {
$this->error = 'Line ' . $no . ': ' . $mainKeyword . ' with no option keyword';
return;
}
- if ($optionKeyword{0} !== '*') {
+ if ($optionKeyword[0] !== '*') {
$this->error = 'Line ' . $no . ': ' . $mainKeyword . " with option keyword that doesn't start with asterisk (*).";
return;
}
// TODO: Check unique
- $nb = new PpdBlockInternal($optionKeyword, $optionTranslation, $type, $currentBlock, $lStart);
+ $nb = new PpdBlockInternal($optionKeyword, $optionTranslation ?? $optionKeyword,
+ $type, $currentBlock, $lStart);
$nb->value = $value;
- if ($currentBlock !== false) {
+ if ($currentBlock !== null) {
$currentBlock->childBlocks[] = $nb;
}
$currentBlock = $nb;
@@ -481,7 +480,7 @@ class Ppd
} else {
$type = substr($type, 5);
}
- if ($currentBlock === false) {
+ if ($currentBlock === null) {
$this->error = 'Line ' . $no . ': ' . $mainKeyword . ' with no Open' . $type;
return;
}
@@ -498,7 +497,7 @@ class Ppd
$currentBlock = $currentBlock->parent;
continue;
} elseif ($mainKeyword === 'OrderDependency') {
- if ($currentBlock === false || $currentBlock->isUi()) {
+ if ($currentBlock === null || $currentBlock->isUi()) {
$this->warn($no, 'OrderDependency outside OpenUI/CloseUI block');
}
continue;
@@ -521,9 +520,10 @@ class Ppd
$this->warn($no, 'Required keyword ' . $mainKeyword . ' declared twice, ignoring');
continue;
}
+ } else {
+ $this->requiredKeywords[$mainKeyword] = array($value);
}
- $this->requiredKeywords[$mainKeyword] = array($value);
- if (($err = $this->validateLine($this->REQUIRED_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) {
+ if (($err = Ppd::validateLine($this->REQUIRED_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) {
$this->warn($no, 'Required main keyword ' . $mainKeyword . ': ' . $err);
$this->knownKeywordMalformed = true;
}
@@ -531,7 +531,7 @@ class Ppd
}
// Other well known keywords
if (isset($this->KNOWN_KEYWORDS[$mainKeyword])) {
- if (($err = $this->validateLine($this->KNOWN_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) {
+ if (($err = Ppd::validateLine($this->KNOWN_KEYWORDS[$mainKeyword], $optionKeyword, $value)) !== true) {
$this->warn($no, 'Known main keyword ' . $mainKeyword . ': ' . $err);
$this->knownKeywordMalformed = true;
}
@@ -541,17 +541,18 @@ class Ppd
$option = $this->getOption(substr($mainKeyword, 7), $currentBlock);
$option->default = new PpdOption($lStart, $len, $value, $valueTranslation);
continue;
- } elseif (substr($mainKeyword, 0, 17) === 'FoomaticRIPOption') {
- if ($optionKeyword === false) {
+ }
+ if (substr($mainKeyword, 0, 17) === 'FoomaticRIPOption') {
+ if ($optionKeyword === null) {
$this->warn($no, "$mainKeyword with no option keyword");
- } elseif ($currentBlock !== false && isset($this->settings[$optionKeyword])) {
+ } elseif ($currentBlock !== null && isset($this->settings[$optionKeyword])) {
$option = $this->getOption($optionKeyword, $currentBlock);
$option->foomatic[substr($mainKeyword, 11)] = new PpdOption($lStart, $len, $value, $valueTranslation);
} else {
$this->warn($no, 'TODO: ' . $line);
}
} elseif (substr($mainKeyword, 0, 6) === 'Custom') {
- if ($optionKeyword === false) {
+ if ($optionKeyword === null) {
$this->warn($no, "$mainKeyword with no option keyword");
} elseif ($optionKeyword !== 'True') {
$this->warn($no, "$mainKeyword with option keyword other than 'True'; ignored");
@@ -560,7 +561,7 @@ class Ppd
$option->custom = new PpdOption($lStart, $len, $value, $valueTranslation);
}
} elseif (substr($mainKeyword, 0, 11) === 'ParamCustom') {
- if ($optionKeyword === false) {
+ if ($optionKeyword === null) {
$this->warn($no, "$mainKeyword with no option keyword");
} elseif (substr($mainKeyword, 11) !== $optionKeyword) {
$this->warn($no, "Don't know how to handle $mainKeyword with option keyword $optionKeyword "
@@ -569,20 +570,20 @@ class Ppd
$option = $this->getOption($optionKeyword, $currentBlock);
$option->customParam = new PpdOption($lStart, $len, $value, $valueTranslation);
}
- } elseif ($mainKeyword{0} === '?') {
+ } elseif ($mainKeyword[0] === '?') {
// Ignoring option query for now
- } elseif ($optionKeyword === false && !isset($this->KNOWN_KEYWORDS[$mainKeyword])) {
+ } elseif ($optionKeyword === null && !isset($this->KNOWN_KEYWORDS[$mainKeyword])) {
// Must be a definition for an option
$this->warn($no, "Don't know how to handle line with main keyword '$mainKeyword', no option keyword found.");
} else {
// Some option for some option ;)
- if ($optionKeyword === false) {
+ if ($optionKeyword === null) {
// We know that this is a known main keyword otherwise we would have hit the previous elseif block
$optionKeyword = $value;
$optionTranslation = $valueTranslation;
}
$option = $this->getOption($mainKeyword, $currentBlock);
- $optionInstance = new PpdOption($lStart, $len, $optionKeyword, $optionTranslation);
+ $optionInstance = new PpdOption($lStart, $len, $optionKeyword, $optionTranslation ?? $optionKeyword);
if ($this->binary_in_array($mainKeyword, $this->REPEATED_KEYWORDS)) {
// This can occur multiple times, just pile them up
$option->values[] = $optionInstance;
@@ -603,9 +604,9 @@ class Ppd
} elseif (strlen(trim($line)) !== 0) {
$this->warn($no, 'Invalid format; not empty and not starting with asterisk (*)');
}
- }
+ } // end while loop over ppd contents
//
- if ($currentBlock !== false) {
+ if ($currentBlock !== null) {
$this->error = 'Block ' . $currentBlock->id . ' (' . $currentBlock->type . ') was never closed.';
return;
}
@@ -615,11 +616,11 @@ class Ppd
$this->error = 'One or more required keywords missing';
}
}
- if ($this->error !== false) {
+ if ($this->error !== null) {
return;
}
// All required keywords exist
- if (preg_match('/utf\-?8/i', $this->requiredKeywords['LanguageEncoding'][0])) {
+ if (preg_match('/utf-?8/i', $this->requiredKeywords['LanguageEncoding'][0])) {
$this->sourceEncoding = false; // Would be a NOOP
} elseif (isset($this->ENCODINGS[$this->requiredKeywords['LanguageEncoding'][0]])) {
$this->sourceEncoding = $this->ENCODINGS[$this->requiredKeywords['LanguageEncoding'][0]];
@@ -669,12 +670,12 @@ class Ppd
}
}
- private function nextLineEnd($start)
+ private function nextLineEnd(int $start): ?int
{
if ($start >= $this->dataLen)
- return false;
+ return null;
while ($start < $this->dataLen) {
- $char = $this->data{$start};
+ $char = $this->data[$start];
if ($char === "\r" || $char === "\n")
return $start;
++$start;
@@ -682,27 +683,26 @@ class Ppd
return $this->dataLen;
}
- private function warn($lineNo, $message)
+ private function warn(int $lineNo, string $message): void
{
$line = 'Line ' . $lineNo . ': ' . $message;
$this->warnings[] = $line;
}
- private function escapeBinaryArray($array)
+ private static function escapeBinaryArray(array $array): string
{
- $chars = array_reduce(array_unique($array), function ($carry, $item) {
+ return array_reduce(array_unique($array), function ($carry, $item) {
return $carry . '\x' . dechex(ord($item));
}, '');
- return $chars;
}
- private function unhexTranslation($lineNo, $translation)
+ private function unhexTranslation(int $lineNo, string $translation): string
{
if (strpos($translation, '<') === false)
return $translation;
return preg_replace_callback('/<[^>]*>/', function ($match) use ($lineNo) {
if (preg_match_all('/[^a-fA-F0-9\<\>\s]/', $match[0], $out)) {
- $this->warn($lineNo, 'Invalid character(s) in hex substring: ' . $this->escapeBinaryArray($out[0]));
+ $this->warn($lineNo, 'Invalid character(s) in hex substring: ' . self::escapeBinaryArray($out[0]));
}
$string = preg_replace('/[^a-fA-F0-9]/', '', $match[0]);
if (strlen($string) % 2 !== 0) {
@@ -713,7 +713,7 @@ class Ppd
}, $translation);
}
- private function hexTranslation($translation)
+ private function hexTranslation(string $translation): string
{
return preg_replace_callback('/[\x00-\x1f\x7b-\xff\:\<\>]+/', function ($match) {
return '<' . unpack('H*', $match[0])[1] . '>';
@@ -724,23 +724,23 @@ class Ppd
* Get option object
*
* @param string $name option name
- * @param \PpdBlockInternal $block which block this option is defined in
- * @return \PpdSettingInternal the option object
+ * @param ?PpdBlockInternal $block which block this option is defined in
+ * @return PpdSettingInternal the option object
*/
- private function getOption($name, $block = false)
+ private function getOption(string $name, ?PpdBlockInternal $block = null): PpdSettingInternal
{
if (!isset($this->settings[$name])) {
$this->settings[$name] = new PpdSettingInternal();
$this->settings[$name]->block = $block;
- } elseif ($block !== false) {
- if ($this->settings[$name]->block === false || $block->isChildOf($this->settings[$name]->block)) {
+ } elseif ($block !== null) {
+ if ($this->settings[$name]->block === null || $block->isChildOf($this->settings[$name]->block)) {
$this->settings[$name]->block = $block;
}
}
return $this->settings[$name];
}
- private function binary_in_array($elem, $array)
+ private function binary_in_array($elem, $array): bool
{
$top = sizeof($array) - 1;
$bot = 0;
@@ -755,7 +755,7 @@ class Ppd
return false;
}
- private function validateLine($validator, $option, $value)
+ private static function validateLine($validator, ?string $option, string $value)
{
if (is_array($validator)) {
$oExp = $validator[0];
@@ -780,7 +780,7 @@ class Ppd
return true;
}
- private function getEolChar()
+ private function getEolChar(): string
{
$rn = substr_count("\r\n", $this->data);
$r = substr_count("\r", $this->data) - $rn;
@@ -799,21 +799,21 @@ class Ppd
*
*/
- public function getError()
+ public function getError(): ?string
{
return $this->error;
}
- public function getWarnings()
+ public function getWarnings(): array
{
return $this->warnings;
}
- public function getUISettings()
+ public function getUISettings(): array
{
$result = array();
foreach ($this->settings as $mk => $option) {
- $isUi = ($option->block !== false && $option->block->isUi()) || isset($this->UI_KEYWORDS[$mk]);
+ $isUi = ($option->block !== null && $option->block->isUi()) || isset($this->UI_KEYWORDS[$mk]);
if ($isUi) {
$result[] = $mk;
}
@@ -821,30 +821,30 @@ class Ppd
return $result;
}
- public function getSetting($name)
+ public function getSetting(string $name): ?PpdSetting
{
if (!isset($this->settings[$name]))
- return false;
+ return null;
return new PpdSetting($this->settings[$name], isset($this->UI_KEYWORDS[$name]), $this->encoder);
}
- public function removeSetting($name)
+ public function removeSetting(string $name): bool
{
if (!isset($this->settings[$name]))
return false;
$setting = $this->settings[$name];
$ranges = array();
- $this->mergeRanges($ranges, $setting->default);
- $this->mergeRanges($ranges, $setting->custom);
- $this->mergeRanges($ranges, $setting->customParam);
+ Ppd::mergeRangesFromOption($ranges, $setting->default);
+ Ppd::mergeRangesFromOption($ranges, $setting->custom);
+ Ppd::mergeRangesFromOption($ranges, $setting->customParam);
foreach ($setting->foomatic as $obj) {
- $this->mergeRanges($ranges, $obj);
+ Ppd::mergeRangesFromOption($ranges, $obj);
}
foreach ($setting->values as $obj) {
- $this->mergeRanges($ranges, $obj);
+ Ppd::mergeRangesFromOption($ranges, $obj);
}
- if ($setting->block !== false && $setting->block->isUi()) {
- $this->mergeRanges($ranges, $setting->block->start, $setting->block->end);
+ if ($setting->block !== null && $setting->block->isUi()) {
+ Ppd::mergeRanges($ranges, $setting->block->start, $setting->block->end);
}
$tmp = array_map(function ($e) { return $e[0]; }, $ranges);
array_multisort($tmp, SORT_NUMERIC, $ranges);
@@ -853,20 +853,20 @@ class Ppd
foreach ($ranges as $range) {
$new .= substr($this->data, $last, $range[0] - $last);
$last = $range[1];
- if ($this->data{$last} === "\r") {
+ if ($this->data[$last] === "\r") {
$last++;
}
- if ($this->data{$last} === "\n") {
+ if ($this->data[$last] === "\n") {
$last++;
}
}
$new .= substr($this->data, $last);
$this->data = $new;
$this->parse();
- return $this->error === false;
+ return $this->error === null;
}
- public function addEmptyOption($settingName, $option, $translation = false, $prepend = true)
+ public function addEmptyOption(string $settingName, string $option, string $translation = null, bool $prepend = true): bool
{
if (!isset($this->settings[$settingName]))
return false;
@@ -874,15 +874,15 @@ class Ppd
$pos = false;
if (!empty($setting->values)) {
if ($prepend) {
- $pos = array_reduce($setting->values, function ($carry, $option) { return min($carry, $option->lineOffset); }, PHP_INT_MAX);
+ $pos = array_reduce($setting->values, function (int $carry, PpdOption $option) { return min($carry, $option->lineOffset); }, PHP_INT_MAX);
} else {
- $pos = array_reduce($setting->values, function ($carry, $option) { return max($carry, $option->lineOffset); }, 0);
+ $pos = array_reduce($setting->values, function (int $carry, PpdOption $option) { return max($carry, $option->lineOffset); }, 0);
}
- } elseif ($setting->default !== false) {
+ } elseif ($setting->default !== null) {
$pos = $setting->default->lineOffset;
- } elseif ($setting->block !== false && $setting->block->isUi()) {
+ } elseif ($setting->block !== null && $setting->block->isUi()) {
$pos = $this->nextLineEnd($setting->block->start);
- while ($pos !== false && $pos < $this->dataLen && ($this->data{$pos} === "\r" || $this->data{$pos} === "\n")) {
+ while ($pos !== null && $pos < $this->dataLen && ($this->data[$pos] === "\r" || $this->data[$pos] === "\n")) {
$pos++;
}
}
@@ -890,23 +890,23 @@ class Ppd
return false;
}
$line = '*' . $settingName . ' ' . $option;
- if ($translation !== false) {
+ if ($translation !== null) {
$line .= '/' . $this->hexTranslation(($this->encoder)($translation, true));
}
$eol = $this->getEolChar();
$line .= ': ""' . $eol;
$this->data = substr($this->data, 0, $pos) . $line . substr($this->data, $pos);
$this->parse();
- return $this->error === false;
+ return $this->error === null;
}
- public function setDefaultOption($settingName, $optionName)
+ public function setDefaultOption($settingName, $optionName): bool
{
if (!isset($this->settings[$settingName]))
return false;
$setting = $this->settings[$settingName];
$line = '*Default' . $settingName . ': ' . $optionName;
- if ($setting->default !== false) {
+ if ($setting->default !== null) {
$start = $setting->default->lineOffset;
$end = $start + $setting->default->lineLen;
} elseif (empty($setting->values)) {
@@ -918,22 +918,21 @@ class Ppd
}
$this->data = substr($this->data, 0, $start) . $line . substr($this->data, $end);
$this->parse();
- return $this->error === false;
+ return $this->error === null;
}
- public function write($file)
+ public function write(string $file)
{
return file_put_contents($file, $this->data);
}
- private function mergeRanges(&$ranges, $start, $end = false)
+ private static function mergeRangesFromOption(array &$ranges, PpdOption $option): void
+ {
+ self::mergeRanges($ranges, $option->lineOffset, $option->lineOffset + $option->lineLen);
+ }
+
+ private static function mergeRanges(array &$ranges, int $start, int $end): void
{
- if (is_object($start) && get_class($start) === 'PpdOption') {
- $end = $start->lineOffset + $start->lineLen;
- $start = $start->lineOffset;
- }
- if ($start === false || $end === false)
- return;
if ($start >= $end)
return; // Don't even bother
foreach (array_keys($ranges) as $key) {
@@ -956,7 +955,7 @@ class Ppd
// $start must lie before range start, otherwise we'd have hit the case above
$end = $ranges[$key][1];
unset($ranges[$key]);
- continue;
+ //continue;
}
}
$ranges[] = array($start, $end);
@@ -965,7 +964,7 @@ class Ppd
/**
* @return bool whether there was at least one known option with format restriction violated.
*/
- public function hasInvalidOption()
+ public function hasInvalidOption(): bool
{
return $this->knownKeywordMalformed;
}
@@ -1013,15 +1012,13 @@ class PpdSetting
/**
* PpdSetting constructor.
- *
- * @param \PpdSettingInternal $setting
*/
- public function __construct($setting, $isUi, $enc)
+ public function __construct(PpdSettingInternal $setting, bool $isUi, callable $enc)
{
- if ($setting->default !== false) {
+ if ($setting->default !== null) {
$this->default = $setting->default->option;
}
- if ($setting->block !== false && $setting->block->isUi()) {
+ if ($setting->block !== null && $setting->block->isUi()) {
$this->uiOptionType = $setting->block->value;
$this->uiOptionTranslation = $enc($setting->block->translation);
$this->isUi = true;
@@ -1055,9 +1052,9 @@ class PpdSetting
class PpdSettingInternal
{
/**
- * @var \PpdOption
+ * @var ?PpdOption
*/
- public $default = false;
+ public $default = null;
/**
* @var \PpdOption[]
*/
@@ -1067,17 +1064,17 @@ class PpdSettingInternal
*/
public $foomatic = array();
/**
- * @var \PpdOption
+ * @var ?PpdOption
*/
- public $custom = false;
+ public $custom = null;
/**
- * @var \PpdOption
+ * @var ?PpdOption
*/
- public $customParam = false;
+ public $customParam = null;
/**
- * @var \PpdBlockInternal the innermost block this option resides in
+ * @var ?PpdBlockInternal the innermost block this option resides in
*/
- public $block = false;
+ public $block = null;
}
class PpdOption
@@ -1088,7 +1085,7 @@ class PpdOption
public $lineLen;
public $multiLine = false;
- public function __construct($lineOffset, $lineLen, $option, $optionTranslation)
+ public function __construct(int $lineOffset, int $lineLen, string $option, string $optionTranslation)
{
$this->option = $option;
$this->optionTranslation = $optionTranslation;
@@ -1106,13 +1103,13 @@ class PpdBlockInternal
public $translation;
public $type;
/**
- * @var \PpdBlockInternal[]
+ * @var PpdBlockInternal[]
*/
public $childBlocks = array();
/**
- * @var \PpdBlockInternal
+ * @var ?PpdBlockInternal
*/
- public $parent;
+ public $parent = null;
/**
* @var int start byte in ppd
@@ -1120,16 +1117,16 @@ class PpdBlockInternal
public $start;
/**
- * @var int|bool end byte in ppd, false if block is not closed
+ * @var ?int end byte in ppd, null if block is not closed
*/
- public $end = false;
+ public $end = null;
/**
* @var string value of opening line for block, e.g. 'PickOne' for OpenUI
*/
- public $value = false;
+ public $value = '';
- public function __construct($id, $translation, $type, $parent, $start)
+ public function __construct(string $id, string $translation, string $type, ?PpdBlockInternal $parent, int $start)
{
$this->id = $id;
$this->translation = $translation;
@@ -1141,16 +1138,16 @@ class PpdBlockInternal
/**
* @return bool true if this is a UI block
*/
- public function isUi()
+ public function isUi(): bool
{
return $this->type == 'UI' || $this->type === 'JCLUI';
}
/**
- * @param \PpdBlockInternal $block some other PpdBlock instance
+ * @param PpdBlockInternal $block some other PpdBlock instance
* @return bool true if this is a child of $block
*/
- public function isChildOf($block)
+ public function isChildOf(PpdBlockInternal $block): bool
{
$parent = $this->parent;
while ($parent !== false) {
diff --git a/modules-available/sysconfig/inc/sysconfig.inc.php b/modules-available/sysconfig/inc/sysconfig.inc.php
index 15bd4104..09860c7d 100644
--- a/modules-available/sysconfig/inc/sysconfig.inc.php
+++ b/modules-available/sysconfig/inc/sysconfig.inc.php
@@ -3,15 +3,42 @@
class SysConfig
{
- public static function getAll()
+ public static function getAll(): array
{
$res = Database::simpleQuery("SELECT c.configid, c.title, c.filepath, c.status, Group_Concat(cl.locationid) AS locs FROM configtgz c"
. " LEFT JOIN configtgz_location cl USING (configid) GROUP BY c.configid");
$ret = array();
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
$ret[] = $row;
}
return $ret;
}
+ public static function archiveContentsFromTask($status, &$userGroupWarn = null) : array
+ {
+ // Sort files for better display
+ $dirs = array();
+ foreach ($status['data']['entries'] as $file) {
+ if ($file['isdir']) continue;
+ $dirs[dirname($file['name'])][] = $file;
+ if ($file['userId'] > 0 || $file['groupId'] > 0) {
+ $userGroupWarn = true;
+ }
+ }
+ ksort($dirs);
+ $list = array();
+ foreach ($dirs as $dir => $files) {
+ $list[] = array(
+ 'name' => $dir,
+ 'isdir' => true
+ );
+ sort($files);
+ foreach ($files as $file) {
+ $file['size'] = Util::readableFileSize($file['size']);
+ $list[] = $file;
+ }
+ }
+ return $list;
+ }
+
} \ No newline at end of file
diff --git a/modules-available/sysconfig/install.inc.php b/modules-available/sysconfig/install.inc.php
index f7ff4405..53882882 100644
--- a/modules-available/sysconfig/install.inc.php
+++ b/modules-available/sysconfig/install.inc.php
@@ -7,6 +7,7 @@ $update[] = tableCreate('configtgz', "
`title` varchar(200) NOT NULL,
`filepath` varchar(255) NOT NULL,
`status` enum('OK','OUTDATED','MISSING') NOT NULL DEFAULT 'MISSING',
+ `warnings` TEXT NULL DEFAULT NULL,
`dateline` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`configid`)
");
@@ -86,7 +87,7 @@ if (!tableHasColumn('configtgz_module', 'dateline')) {
$update[] = UPDATE_DONE;
// Infer from module's filemtime
$res = Database::simpleQuery('SELECT moduleid, filepath FROM configtgz_module');
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
Database::exec('UPDATE configtgz_module SET dateline = :mtime WHERE moduleid = :moduleid',
['moduleid' => $row['moduleid'], 'mtime' => filemtime($row['filepath'])]);
}
@@ -101,7 +102,7 @@ if (!tableHasColumn('configtgz', 'dateline')) {
INNER JOIN configtgz_x_module cxm USING (configid)
INNER JOIN configtgz_module m USING (moduleid)
GROUP BY configid');
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
Database::exec('UPDATE configtgz SET dateline = :mtime WHERE configid = :configid',
['configid' => $row['configid'], 'mtime' => $row['dateline']]);
}
@@ -110,19 +111,68 @@ if (!tableHasColumn('configtgz', 'dateline')) {
// 2020-01-16: Change contents column type
Database::exec("ALTER TABLE `configtgz_module` CHANGE `contents` `contents` LONGBLOB NOT NULL");
+// 2020-11-02: Add warnings column
+if (!tableHasColumn('configtgz', 'warnings')) {
+ if (Database::exec("ALTER TABLE `configtgz` ADD `warnings` TEXT NULL DEFAULT NULL") === false) {
+ finalResponse(UPDATE_FAILED, 'Could not add warnings to configtgz: ' . Database::lastError());
+ }
+ $update[] = UPDATE_DONE;
+}
+
// ----- rebuild configs ------
-// TEMPORARY HACK; Rebuild configs.. move somewhere else?
+// PERMANENT HACK; Rebuild configs.. move somewhere else?
Module::isAvailable('sysconfig');
$list = ConfigModule::getAll();
-if ($list === false) {
- EventLog::warning('Could not regenerate AD/LDAP configs - please do so manually');
+$parentTask = null;
+$configList = [];
+if ($list === null) {
+ EventLog::warning('Could not regenerate configs - please do so manually');
} else {
- foreach ($list as $ad) {
- if ($ad->needRebuild()) {
- $ad->generate(false);
+ foreach ($list as $confMod) {
+ if ($confMod->moduleType() === 'SshConfig') {
+ // 2020-11-12: Split SshConfig into SshConfig and SshKey
+ $pubkey = $confMod->getData('publicKey');
+ if (!empty($pubkey)) {
+ error_log('Legacy module with pubkey ' . $confMod->id());
+ $key = ConfigModule::getInstanceOrNull('SshKey');
+ if ($key !== null) {
+ $key->setData('publicKey', $pubkey);
+ if ($key->insert($confMod->title())) {
+ // Insert worked, remove key from old module, add this module to the same configs
+ $task = $key->generate(false, $parentTask);
+ if ($task !== false) {
+ $parentTask = $task;
+ }
+ error_log('Inserted new module with id ' . $key->id());
+ $confMod->setData('publicKey', false);
+ $confMod->update();
+ $configs = ConfigTgz::getAllForModule($confMod->id());
+ foreach ($configs as $config) {
+ // Add newly created key-only module to all configs
+ $new = array_merge($config->getModuleIds(), [$key->id()]);
+ error_log(implode(',', $config->getModuleIds()) . ' -> ' . implode(',', $new));
+ $config->update('', $new);
+ $configList[] = $config;
+ }
+ }
+ }
+ }
}
+ if ($confMod->needRebuild()) {
+ $update[] = UPDATE_DONE;
+ $task = $confMod->generate(false, $parentTask);
+ if ($task !== false) {
+ $parentTask = $task;
+ }
+ }
+ }
+ foreach ($configList as $config) {
+ $config->generate(false, 0, $parentTask);
}
}
+// Start any changed services
+ConfigModuleBaseLdap::ldadp();
+
// Create response for browser
responseFromArray($update);
diff --git a/modules-available/sysconfig/lang/de/config-module.json b/modules-available/sysconfig/lang/de/config-module.json
index f2ed9a90..33c743a5 100644
--- a/modules-available/sysconfig/lang/de/config-module.json
+++ b/modules-available/sysconfig/lang/de/config-module.json
@@ -9,11 +9,14 @@
"group_branding": "Einrichtungsspezifisches Logo",
"group_generic": "Generisch",
"group_screensaver": "Bildschirmschoner Styling",
- "group_sshconfig": "SSH",
+ "group_sshconfig": "SSH-Dämon",
+ "group_sshkey": "SSH-Key",
"ldapAuth_description": "Mit diesem Modul l\u00e4sst sich eine generische LDAP-Authentifizierung einrichten.",
"ldapAuth_title": "LDAP Authentifizierung",
"screensaver_title": "Bildschirmschoner Anpassungen",
"screensaver_description": "Mit diesem Modul können sie den Style (QSS) und die Texte des Bildschirmschoners anpassen.",
"sshconfig_description": "Mit diesem Modul l\u00e4sst sich steuern, ob und wie der sshd auf den gebooteten Clients startet, und welche Funktionen er zur Verf\u00fcgung stellt. Wenn Sie keinen sshd auf den Clients nutzen wollen, brauchen Sie kein solches Modul zu erstellen.",
- "sshconfig_title": "SSH-D\u00e4mon"
-} \ No newline at end of file
+ "sshconfig_title": "SSH-D\u00e4mon",
+ "sshkey_title": "SSH-Key",
+ "sshkey_description": "Einen öffentlichen SSH-Schlüssel zu den authorized_keys des root-Benutzers hinzufügen. Mit dem zugehörigen privaten Schlüssel kann dann via SSH auf die gebooteten Clients zugegriffen werden, sofern root-Login im zugehörigen SSH-Dämon-Modul aktiviert wurde."
+}
diff --git a/modules-available/sysconfig/lang/de/module.json b/modules-available/sysconfig/lang/de/module.json
index 02d55e5b..4bc1642f 100644
--- a/modules-available/sysconfig/lang/de/module.json
+++ b/modules-available/sysconfig/lang/de/module.json
@@ -1,12 +1,28 @@
{
"config-module": "Konfigurationsmodul",
- "lang_clientSshConfig": "SSH-Konfiguration",
"lang_configurationCompilation": "Konfiguration zusammenstellen",
"lang_contentOf": "Inhalt von",
"lang_moduleAdd": "Modul hinzuf\u00fcgen",
"lang_moduleAssign": "Modul zu Systemkonfigurationen zuweisen",
"lang_noModuleFromThisGroup": "(Kein Modul dieser Gruppe)",
"lang_unknwonTaskManager": "Unbekannter Taskmanager-Fehler",
+ "location-column-header": "Lokalisierung",
"module_name": "Lokalisierung + Integration",
- "page_title": "Lokalisierung + Integration"
+ "page_title": "Lokalisierung + Integration",
+ "saver_DescriptionIdleKill": "Ein Bildschirmschoner mit Timeout, nach dessen Ablauf alle Anwendungen ohne weitere Nachfragen geschlossen werden und der Nutzer ausgeloggt wird.",
+ "saver_DescriptionNoTimeout": "Ein Bildschirmschoner ohne Timeout.",
+ "saver_DescriptionShutdown": "Ein Bildschirmschoner mit Timeout, nach dessen Ablauf alle Anwendungen ohne weitere Nachfragen geschlossen werden und der PC heruntergefahren oder neugestartet wird.",
+ "saver_MessageDefaultIdleKill": "Diese Sitzung wird bei Inaktivit\u00e4t in %1 beendet.",
+ "saver_MessageDefaultIdleKillLocked": "Diese Sitzung wird in %1 beendet, wenn sie nicht entsperrt wird.",
+ "saver_MessageDefaultNoTimeout": "Dieser Bildschirm wird gerade geschont.",
+ "saver_MessageDefaultNoTimeoutLocked": "Dieser Rechner ist gesperrt.",
+ "saver_MessageDefaultShutdown": "Achtung: Rechner wird in %1 heruntergefahren!",
+ "saver_MessageDefaultShutdownLocked": "Achtung: Rechner wird in %1 heruntergefahren!",
+ "saver_QssDefault": "#Saver {\r\n background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #443, stop:1 #000)\r\n}\r\n\r\nQLabel {\r\n color: #f64;\r\n}\r\n\r\n#lblClock {\r\n color: #999;\r\n font-size: 20pt;\r\n}\r\n\r\n#lblHeader {\r\n font-size: 20pt;\r\n}\r\n",
+ "saver_TextDefaultIdleKill": "<html><body>Keine Nutzeraktivit\u00e4t festgestellt. <br>Zum oben angegebenen Zeitpunkt wird die aktuell laufende Sitzung beendet, wenn der Rechner nicht mehr verwendet wird. <br>Alle noch laufenden Programme <br>werden ohne Nachfrage geschlossen. Stellen Sie daher sicher, bis zum angegebenen Zeitpunkt <br>s\u00e4mtliche sich in Bearbeitung befindlichen Daten abzuspeichern. <br><br>Dies dient dazu zu vermeiden, dass ein Rechner stundenlang gesperrt wird und somit <br>anderen Nutzern nicht zur Verf\u00fcgung steht.<\/body><\/html>",
+ "saver_TextDefaultIdleKillLocked": "<html><body><br>Zum oben angegebenen Zeitpunkt wird die aktuell laufende Sitzung beendet, wenn sie zuvor nicht wieder entsperrt wird. <br>Alle noch laufenden Programme werden ohne Nachfrage geschlossen. <br>Stellen Sie daher sicher, bis zum angegebenen Zeitpunkt <br>s\u00e4mtliche sich in Bearbeitung befindlichen Daten abzuspeichern, bzw. die Sitzung wieder zu entsperren. <br><br>Dies dient dazu zu vermeiden, dass ein Rechner stundenlang gesperrt wird und somit<br>anderen Nutzern nicht zur Verf\u00fcgung steht.<\/body><\/html>",
+ "saver_TextDefaultShutdown": "<html><body>Achtung: Zum oben angegebenen Zeitpunkt wird der Computer heruntergefahren bzw. neugestartet. <br>Alle noch laufenden Programme werden ohne Nachfrage beendet. Stellen Sie daher sicher, bis <br>zum angegebenen Zeitpunkt s\u00e4mtliche Daten abzuspeichern und die Sitzung zu verlassen.<\/body><\/html>",
+ "saver_TitleIdleKill": "Idle Kill",
+ "saver_TitleNoTimeout": "Ohne Timeout",
+ "saver_TitleShutdown": "Herunterfahren"
} \ No newline at end of file
diff --git a/modules-available/sysconfig/lang/de/template-tags.json b/modules-available/sysconfig/lang/de/template-tags.json
index 0acdb8a7..16b2c672 100644
--- a/modules-available/sysconfig/lang/de/template-tags.json
+++ b/modules-available/sysconfig/lang/de/template-tags.json
@@ -8,8 +8,6 @@
"lang_adText3": "Normalerweise k\u00f6nnen Sie als Bind DN die Kurzform im Format dom\u00e4ne\\benutzer angeben. Wenn dies nicht funktioniert, m\u00fcssen Sie den DN des Benutzers ermitteln. Z.B. unter Eingabe des folgenden Befehls auf einem DC:",
"lang_adText4": "Nach Eingabe aller ben\u00f6tigten Daten wird im n\u00e4chsten Schritt \u00fcberpr\u00fcft, ob die Kommunikation mit dem AD m\u00f6glich ist.",
"lang_add": "Hinzuf\u00fcgen",
- "lang_allowPass": "Login mit Passwort zulassen",
- "lang_allowPassInfo": "Wenn aktiviert, l\u00e4sst der sshd Logins mit Benutzername\/Passwort-Kombination zu. Ansonsten werden nur Logins nach dem pubkey-Verfahren zugelassen.",
"lang_asteriskMandatory": "Mit (*) gekennzeichnete Felder sind Pflichtfelder",
"lang_availableModules": "Verf\u00fcgbare Konfigurationsmodule",
"lang_availableSystem": "Verf\u00fcgbare Systemkonfigurationen",
@@ -44,9 +42,8 @@
"lang_driveLetterNote": "WICHTIG: Bitte w\u00e4hlen Sie einen Laufwerksbuchstaben, der in den eingesetzten VMs verf\u00fcgbar ist, da ansonsten auf einen anderen Buchstaben ausgewichen werden muss.",
"lang_editLong": "Modul oder Konfiguration bearbeiten.",
"lang_editingLocationInfo": "Sie setzen die Konfiguration eines bestimmten Raums\/Orts, nicht die globale Konfiguration",
- "lang_fixNumeric": "Numerischen Account-Namen muss ein 's' vorangestellt werden",
- "lang_fixNumericDescription": "Wenn Sie diese Option aktivieren, m\u00fcssen Benutzer, deren Account-Name nur aus Ziffern besteht, diesem ein 's' voranstellen beim Login. Diese Option ist beim alten Login-Manager (KDM) zwingend erforderlich, da sonst der Loginvorgang fehlschl\u00e4gt. Mit dem neuen lightdm-basierten Login-Screen lassen sich numerische Account-Namen jedoch direkt verwenden. Wenn Sie an Ihrer Einrichtung keine numerischen Account-Namen verwenden, hat diese Option keine Auswirkung.",
"lang_folderRedirection": "Folder Redirection",
+ "lang_forceRootOwner": "Besitzrechte des Inhalts auf root:root setzen",
"lang_genUid": "uid-Nummern generieren",
"lang_genUidDescription": "Wenn aktiviert, generiert der Satellitenserver nummerische IDs f\u00fcr die Benutzer, anstatt diese aus dem LDAP\/AD zu extrahieren.",
"lang_generateModule": "Modul erzeugen",
@@ -74,14 +71,17 @@
"lang_mapModeNativeFallback": "Nativ in der VM einbinden; Fallback auf VMware Shared Folders",
"lang_mapModeNone": "Verzeichnisse nicht durchreichen",
"lang_mapModeVmware": "VMware Shared Folders [VMwareTools]",
+ "lang_modStillUsedBy": "Modul noch in Verwendung durch:",
"lang_mode": "Modus",
- "lang_modeEasy": "Vereinfachter Modus",
"lang_modeAdvanced": "Fortgeschrittener Modus",
- "lang_modStillUsedBy": "Modul noch in Verwendung durch:",
+ "lang_modeEasy": "Vereinfachter Modus",
"lang_moduleChoose": "Bitte w\u00e4hlen Sie aus, welche Art Konfigurationsmodul Sie erstellen m\u00f6chten.",
"lang_moduleConfiguration": "Konfigurationsmodule",
"lang_moduleName": "Modulname",
+ "lang_moduleOwnerWarn": "Einige Dateien oder Verzeichnisse in diesem Archiv haben als Besitzer order Gruppe etwas anderes als \"root\" gesetzt. Dies ist nur in besonderen F\u00e4llen sinnvoll bzw. erforderlich.",
"lang_moduleTitle": "Titel",
+ "lang_moduleUnused": "Ungenutzt",
+ "lang_moduleUnusedLong": "Dieses Modul ist mit keiner Systemkonfiguration verkn\u00fcpft.",
"lang_mountOptionsNote": "Diese Einstellungen beziehen sich nur auf Linux und \u00e4hnliche Systeme (sowohl das MiniLinux als auch laufende VMs) und beeinflussen die Optionen, die beim Mounten des Verzeichnisses verwendet werden sollen. Sofern es im LDAP\/AD ein Nutzerattribut gibt, welches die passenden Optionen enth\u00e4lt, k\u00f6nnen Sie dieses hier angeben. Das Attribut wird dann vorrangig behandelt. Ist das Attribut leer oder nicht vorhanden, werden die Optionen verwendet, die Sie im Feld \"feste Mount-Optionen\" eingetragen haben. Sind beide Felder leer, werden verschiedene Optionen automatisch durchprobiert.",
"lang_name": "Name",
"lang_newConfiguration": "Neue Konfiguration",
@@ -95,6 +95,7 @@
"lang_noValidCert": "Der Server besitzt kein oder ein nicht valides Zertifikat.",
"lang_onProblemSearchBase": "Werden keine Benutzer gefunden, dann \u00fcberpr\u00fcfen Sie bitte die Suchbasis",
"lang_or": "oder",
+ "lang_pwlogin_user_only": "Alle au\u00dfer root",
"lang_rebuild": "Neu generieren",
"lang_rebuildLong": "Modul oder Konfiguration neu generieren. Das entsprechende Modul bzw. Konfiguration ist aktuell und sollte nicht neu generiert werden m\u00fcssen.",
"lang_rebuildOutdatedLong": "Modul oder Konfiguration neu generieren. Das entsprechende Modul bzw. Konfiguration ist veraltet oder nicht vorhanden.",
@@ -102,33 +103,17 @@
"lang_replaces": "Ersetzt Modul: ",
"lang_restartWizard": "Wizard neu starten",
"lang_rootKey": "root pubkey (\u00f6ffentlicher Schl\u00fcssel)",
- "lang_rootKeyInfo": "Tragen Sie hier den \u00f6ffentlichen Schl\u00fcssel eines Schl\u00fcsselpaars ein, mit dem Sie sich als root-Benutzer an den Clients anmelden wollen. Lassen Sie das Feld leer, um diese Funktion nicht zu verwenden.",
+ "lang_rootKeyInfo": "Tragen Sie hier den \u00f6ffentlichen Schl\u00fcssel eines Schl\u00fcsselpaars ein, mit dem Sie sich als root-Benutzer an den Clients anmelden wollen.",
"lang_screenBackground": "Hintergrund",
"lang_screenBackgroundDescription": " - Ein Hintergrund, bestehend aus einem zweifarbigem Gradienten.",
- "lang_screenColor": "Farbe",
"lang_screenClock": "Uhr",
- "lang_screenDescriptionIdleKill": "Ein Bildschirmschoner mit Timeout, nach dessen Ablauf alle Anwendungen ohne weitere Nachfragen geschlossen werden und der Nutzer ausgeloggt wird.",
- "lang_screenDescriptionNoTimeout": "Ein Bildschirmschoner ohne Timeout.",
- "lang_screenDescriptionShutdown": "Ein Bildschirmschoner mit Timeout, nach dessen Ablauf alle Anwendungen ohne weitere Nachfragen geschlossen werden und der PC heruntergefahren oder neugestartet wird.",
+ "lang_screenColor": "Farbe",
"lang_screenHeader": "Header",
"lang_screenLabel": "Label",
"lang_screenLocked": "Sperrbildschirm",
- "lang_screenMessageDefaultIdleKill": "Diese Sitzung wird bei Inaktivität in %1 beendet.",
- "lang_screenMessageDefaultIdleKillLocked": "Diese Sitzung wird in %1 beendet, wenn sie nicht entsperrt wird.",
- "lang_screenMessageDefaultNoTimeout": "Dieser Bildschirm wird gerade geschont.",
- "lang_screenMessageDefaultNoTimeoutLocked": "Dieser Rechner ist gesperrt.",
- "lang_screenMessageDefaultShutdown": "Achtung: Rechner wird in %1 heruntergefahren!",
- "lang_screenMessageDefaultShutdownLocked": "Achtung: Rechner wird in %1 heruntergefahren!",
"lang_screenQss": "QSS",
- "lang_screenQssDefault": "#Saver {\n background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #443, stop:1 #000)\n}\n\nQLabel {\n color: #f64;\n}\n\n#lblClock {\n color: #999;\n font-size: 20pt;\n}\n\n#lblHeader {\n font-size: 20pt;\n}\n",
- "lang_screenSize": "Gr\u00f6ße",
- "lang_screenTitleIdleKill": "Idle Kill",
- "lang_screenTitleNoTimeout": "Ohne Timeout",
- "lang_screenTitleShutdown": "Herunterfahren",
+ "lang_screenSize": "Gr\u00f6\u00dfe",
"lang_screenText": "Inhaltstext Bearbeiten",
- "lang_screenTextDefaultIdleKill": "<html><body>Keine Nutzeraktivität festgestellt. <br>Zum oben angegebenen Zeitpunkt wird die aktuell laufende Sitzung beendet, wenn der Rechner nicht mehr verwendet wird. <br>Alle noch laufenden Programme <br>werden ohne Nachfrage geschlossen. Stellen Sie daher sicher, bis zum angegebenen Zeitpunkt <br>sämtliche sich in Bearbeitung befindlichen Daten abzuspeichern. <br><br>Dies dient dazu zu vermeiden, dass ein Rechner stundenlang gesperrt wird und somit <br>anderen Nutzern nicht zur Verfügung steht.</body></html>",
- "lang_screenTextDefaultIdleKillLocked": "<html><body><br>Zum oben angegebenen Zeitpunkt wird die aktuell laufende Sitzung beendet, wenn sie zuvor nicht wieder entsperrt wird. <br>Alle noch laufenden Programme werden ohne Nachfrage geschlossen. <br>Stellen Sie daher sicher, bis zum angegebenen Zeitpunkt <br>sämtliche sich in Bearbeitung befindlichen Daten abzuspeichern, bzw. die Sitzung wieder zu entsperren. <br><br>Dies dient dazu zu vermeiden, dass ein Rechner stundenlang gesperrt wird und somit<br>anderen Nutzern nicht zur Verfügung steht.</body></html>",
- "lang_screenTextDefaultShutdown": "<html><body>Achtung: Zum oben angegebenen Zeitpunkt wird der Computer heruntergefahren bzw. neugestartet. <br>Alle noch laufenden Programme werden ohne Nachfrage beendet. Stellen Sie daher sicher, bis <br>zum angegebenen Zeitpunkt sämtliche Daten abzuspeichern und die Sitzung zu verlassen.</body></html>",
"lang_screenTextInherit": "Werte Erben",
"lang_screenUnlocked": "Bildschirmschoner",
"lang_searchBase": "Suchbasis",
@@ -150,7 +135,10 @@
"lang_show": "Ansehen",
"lang_showLong": "Inhalt des Moduls anzeigen.",
"lang_skip": "Weiter",
- "lang_sshMultipleHeadsup": "Wenn Sie mehrere Pubkeys angeben wollen, k\u00f6nnen Sie entsprechend mehrere Module vom Typ SSH zu einer Systemkonfiguration hinzuf\u00fcgen. In diesem Fall sollten Sie jedoch darauf achten, dass alle Konfigurationen die gleichen Einstellungen f\u00fcr Port und Passwortlogin haben, da ansonsten undefiniert ist, welche der Einstellungen greifen wird.",
+ "lang_sshAllowPass": "Login via Passwort zulassen",
+ "lang_sshAllowPassInfo": "Legt fest, ob sich per SSH mit Passwort eingeloggt werden darf, oder nur das pubkey-Verfahren erlaubt ist.",
+ "lang_sshAllowedUsers": "Zugelassene Nutzer",
+ "lang_sshAllowedUsersInfo": "Legt fest, welche Nutzer sich per SSH einloggen d\u00fcrfen. Der spezielle Nutzer \"demo\" kann sich generell nicht per SSH einloggen, unabh\u00e4ngig der Konfiguration.",
"lang_ssl": "SSL",
"lang_sslDescription": "Die Verbindung zum AD\/LDAP-Server mit SSL sichern. (Die Verbindung zwischen Client und Proxy wird in jedem Fall mit SSL abgewickelt.)",
"lang_supportedFiles": "Unterst\u00fctzte Archivformate",
@@ -167,5 +155,8 @@
"lang_userDirectory": "Benutzerverzeichnis",
"lang_userDirectoryInfo1": "Optionale Angabe: Wenn die Clients f\u00fcr die Benutzer ein eigenes Verzeichnis (Homeverzeichnis, Benutzerverzeichnis) von einem Server einbinden sollen, geben Sie bitte hier das Format in UNC-Notation an, also z.B.",
"lang_userDirectoryInfo2": "%s ist dabei ein Platzhalter f\u00fcr den Login-Namen des Benutzers.",
- "lang_userDirectoryInfo3": "Das Verzeichnis wird mit den gleichen Zugangsdaten eingebunden, die der Benutzer beim Login angibt. (D.h. kein Kerberos Support o.\u00e4.)"
-}
+ "lang_userDirectoryInfo3": "Das Verzeichnis wird mit den gleichen Zugangsdaten eingebunden, die der Benutzer beim Login angibt. (D.h. kein Kerberos Support o.\u00e4.)",
+ "lang_user_all": "Alle Nutzer",
+ "lang_user_root_only": "Nur root",
+ "lang_user_user_only": "Alle au\u00dfer root"
+} \ No newline at end of file
diff --git a/modules-available/sysconfig/lang/en/config-module.json b/modules-available/sysconfig/lang/en/config-module.json
index 6728f5fd..d4e1a8cc 100644
--- a/modules-available/sysconfig/lang/en/config-module.json
+++ b/modules-available/sysconfig/lang/en/config-module.json
@@ -9,11 +9,14 @@
"group_branding": "Branding",
"group_generic": "Generic",
"group_screensaver": "Screen saver styling",
- "group_sshconfig": "SSH",
+ "group_sshconfig": "SSH config",
+ "group_sshkey": "SSH key",
"ldapAuth_description": "This module enables you to create a simple LDAP authentication module.",
"ldapAuth_title": "LDAP Authentication",
"screensaver_title": "Screensaver customization",
"screensaver_description": "With this module you can customize the style (QSS) and texts of the screensaver.",
"sshconfig_description": "Here you can set whether the sshd on the clients will start, and what options it will use.",
- "sshconfig_title": "SSH daemon"
-} \ No newline at end of file
+ "sshconfig_title": "SSH daemon",
+ "sshkey_title": "SSH key",
+ "sshkey_description": "Add a public key to the authorized_keys file of the root user. You can then use the according private key to log in on a running client as root via SSH. root login needs to be enabled in the according SSH daemon module."
+}
diff --git a/modules-available/sysconfig/lang/en/module.json b/modules-available/sysconfig/lang/en/module.json
index 278de8ed..dbfacdb8 100644
--- a/modules-available/sysconfig/lang/en/module.json
+++ b/modules-available/sysconfig/lang/en/module.json
@@ -1,12 +1,28 @@
{
"config-module": "Config module",
- "lang_clientSshConfig": "SSH configuration",
"lang_configurationCompilation": "Compile configuration",
"lang_contentOf": "Content of",
"lang_moduleAdd": "Add Module",
"lang_moduleAssign": "Assign Module to System Configurations",
"lang_noModuleFromThisGroup": "(No module from this group)",
"lang_unknwonTaskManager": "Unknown Task Manager error",
+ "location-column-header": "SysConfig",
"module_name": "Localization",
- "page_title": "Localize and integrate"
+ "page_title": "Localize and integrate",
+ "saver_DescriptionIdleKill": "A screensaver with a timeout which on it's expiration will close all running applications without further requests and logout the user.",
+ "saver_DescriptionNoTimeout": "A screensaver without a timeout.",
+ "saver_DescriptionShutdown": "A screensaver with a timeout which on it's expiration the PC will shutdown or restart. All applications will be closed without further requests.",
+ "saver_MessageDefaultIdleKill": "This session will end in %1 when inactive.",
+ "saver_MessageDefaultIdleKillLocked": "This session will end in %1 if the session is not unlocked.",
+ "saver_MessageDefaultNoTimeout": "This screen is in saving mode.",
+ "saver_MessageDefaultNoTimeoutLocked": "This computer is locked.",
+ "saver_MessageDefaultShutdown": "Caution: Computer will shutdown in %1!",
+ "saver_MessageDefaultShutdownLocked": "Caution: Computer will shutdown in %1!",
+ "saver_QssDefault": "#Saver {\r\n background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #443, stop:1 #000)\r\n}\r\n\r\nQLabel {\r\n color: #f64;\r\n}\r\n\r\n#lblClock {\r\n color: #999;\r\n font-size: 20pt;\r\n}\r\n\r\n#lblHeader {\r\n font-size: 20pt;\r\n}\r\n",
+ "saver_TextDefaultIdleKill": "<html><body>No user activity detected. <br>If the computer is not used until the time specified above, the session will end. <br> All running applications <br>will be closed without further requests. Make sure that all files and changes are saved <br> before the time runs out. <br><br>It prevents computers from beeing locked for hours and <br>not beeing available for other users.<\/body><\/html>",
+ "saver_TextDefaultIdleKillLocked": "<html><body><br>The current session will end by the time specified above if the computer isn't unlocked before. <br>All running applications will be closed without further requests. <br>Make sure that all files and changes are saved <br>or the session is unlocked before the time runs out. <br><br>It prevents computers from beeing locked for hours and <br>not beeing available for other users.<\/body><\/html>",
+ "saver_TextDefaultShutdown": "<html><body>Caution: The computer will shutdown or restart respectively at the specified time above. <br>All running applications will be closed without further requests. Make sure to save all files and changes and leave the session<br>before the time runs out.<\/body><\/html>",
+ "saver_TitleIdleKill": "Idle Kill",
+ "saver_TitleNoTimeout": "No Timeout",
+ "saver_TitleShutdown": "Shutdown"
} \ No newline at end of file
diff --git a/modules-available/sysconfig/lang/en/template-tags.json b/modules-available/sysconfig/lang/en/template-tags.json
index 40484b5a..eddd03d4 100644
--- a/modules-available/sysconfig/lang/en/template-tags.json
+++ b/modules-available/sysconfig/lang/en/template-tags.json
@@ -8,8 +8,6 @@
"lang_adText3": "Next the distinguished name of the user must be specified. You can determine this by dsquery command line program on a domain controller as the following call:",
"lang_adText4": "After entering all required data in the next step, it checks whether communication is possible with the AD.",
"lang_add": "Add",
- "lang_allowPass": "Allow password login",
- "lang_allowPassInfo": "When active, logins via username and password are allowed. Otherwise, only pubkey authentication is possible.",
"lang_asteriskMandatory": "Fields marked with (*) are mandatory",
"lang_availableModules": "Available Configuration Modules",
"lang_availableSystem": "Available System Configuration",
@@ -44,9 +42,8 @@
"lang_driveLetterNote": "IMPORTANT: Pick a drive letter for the home directory that will be free in the Virtual Machines. Otherwise, a random letter will be assigned.",
"lang_editLong": "Edit module or configuration.",
"lang_editingLocationInfo": "You're setting the configuration for a specific location, not the global one",
- "lang_fixNumeric": "Numeric account names have to be prefixed by 's'",
- "lang_fixNumericDescription": "If enabled, users with account names that consist entirely of digits have to prefix their user id by 's' when logging in. This is required with the old login manager (KDM) to prevent crashes. The new lightdm-based login manager will accept numeric account names, so you can leave this option disabled. If your organization doesn't have any numeric account names, this option will have no effect.",
"lang_folderRedirection": "Folder Redirection",
+ "lang_forceRootOwner": "Change ownership of archive content to root:root",
"lang_genUid": "Generate uid numbers",
"lang_genUidDescription": "When selected, the satellite server will generate numeric IDs for the users, instead of extracting them from AD\/LDAP.",
"lang_generateModule": "Generating module",
@@ -74,14 +71,17 @@
"lang_mapModeNativeFallback": "Natively map inside VM; fallback to VMware Shared Folders",
"lang_mapModeNone": "Don't map shares at all",
"lang_mapModeVmware": "VMware Shared Folders [VMwareTools]",
+ "lang_modStillUsedBy": "Module still in use by:",
"lang_mode": "Mode",
- "lang_modeEasy": "Easy Mode",
"lang_modeAdvanced": "Advanced Mode",
- "lang_modStillUsedBy": "Module still in use by:",
+ "lang_modeEasy": "Easy Mode",
"lang_moduleChoose": "Please select which type of configuration module you want to create.",
"lang_moduleConfiguration": "Module Configuration",
"lang_moduleName": "Module Name",
+ "lang_moduleOwnerWarn": "Some files or directories in this archive belong to another user or group than \"root\". This is only necessary\/required in special cases.",
"lang_moduleTitle": "Title",
+ "lang_moduleUnused": "Unused",
+ "lang_moduleUnusedLong": "This module is not attached to any system configuration.",
"lang_mountOptionsNote": "These settings are relevant for the MiniLinux and VMs containing non-Windows OSes. If you specify an LDAP user attribute, its contents will be used as mount options when mounting the user's home directory. If the attribute is not specified or its contents are empty, the mount attributes specified in the other field will be used. If you leave both fields empty, the clients will try to determine the options automatically.",
"lang_name": "Name",
"lang_newConfiguration": "New Configuration",
@@ -95,6 +95,7 @@
"lang_noValidCert": "The server did not supply a certificate, or the certificate is invalid.",
"lang_onProblemSearchBase": "If no users are found, please check the search base",
"lang_or": "or",
+ "lang_pwlogin_user_only": "Everyone except root",
"lang_rebuild": "Rebuild",
"lang_rebuildLong": "Rebuild module or configuration.",
"lang_rebuildOutdatedLong": "Rebuild module or configuration. The module\/configuration is outdated or missing and should be regenerated.",
@@ -102,33 +103,17 @@
"lang_replaces": "Replaces module: ",
"lang_restartWizard": "Restart wizard",
"lang_rootKey": "root pubkey",
- "lang_rootKeyInfo": "Here you can add the public key of a keypair that you want to use for authentication as root-user. Leave this field blank to disable the feature.",
+ "lang_rootKeyInfo": "Here you can add the public key of a keypair that you want to use for authentication as root-user.",
"lang_screenBackground": "Background",
"lang_screenBackgroundDescription": " - A background consisting of a gradient with two colors.",
- "lang_screenColor": "Color",
"lang_screenClock": "Clock",
- "lang_screenDescriptionIdleKill": "A screensaver with a timeout which on it's expiration will close all running applications without further requests and logout the user.",
- "lang_screenDescriptionNoTimeout": "A screensaver without a timeout.",
- "lang_screenDescriptionShutdown": "A screensaver with a timeout which on it's expiration the PC will shutdown or restart. All applications will be closed without further requests.",
+ "lang_screenColor": "Color",
"lang_screenHeader": "Header",
"lang_screenLabel": "Label",
"lang_screenLocked": "Lockscreen",
- "lang_screenMessageDefaultIdleKill": "This session will end in %1 when inactive.",
- "lang_screenMessageDefaultIdleKillLocked": "This session will end in %1 if the session is not unlocked.",
- "lang_screenMessageDefaultNoTimeout": "This screen is in saving mode.",
- "lang_screenMessageDefaultNoTimeoutLocked": "This computer is locked.",
- "lang_screenMessageDefaultShutdown": "Caution: Computer will shutdown in %1!",
- "lang_screenMessageDefaultShutdownLocked": "Caution: Computer will shutdown in %1!",
"lang_screenQss": "QSS",
- "lang_screenQssDefault": "#Saver {\n background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #443, stop:1 #000)\n}\n\nQLabel {\n color: #f64;\n}\n\n#lblClock {\n color: #999;\n font-size: 20pt;\n}\n\n#lblHeader {\n font-size: 20pt;\n}\n",
"lang_screenSize": "Size",
- "lang_screenTitleIdleKill": "Idle Kill",
- "lang_screenTitleNoTimeout": "No Timeout",
- "lang_screenTitleShutdown": "Shutdown",
"lang_screenText": "Edit Contenttext",
- "lang_screenTextDefaultIdleKill": "<html><body>No user activity detected. <br>If the computer is not used until the time specified above, the session will end. <br> All running applications <br>will be closed without further requests. Make sure that all files and changes are saved <br> before the time runs out. <br><br>It prevents computers from beeing locked for hours and <br>not beeing available for other users.</body></html>",
- "lang_screenTextDefaultIdleKillLocked": "<html><body><br>The current session will end by the time specified above if the computer isn't unlocked before. <br>All running applications will be closed without further requests. <br>Make sure that all files and changes are saved <br>or the session is unlocked before the time runs out. <br><br>It prevents computers from beeing locked for hours and <br>not beeing available for other users.</body></html>",
- "lang_screenTextDefaultShutdown": "<html><body>Caution: The computer will shutdown or restart respectively at the specified time above. <br>All running applications will be closed without further requests. Make sure to save all files and changes and leave the session<br>before the time runs out.</body></html>",
"lang_screenTextInherit": "Inherit Values",
"lang_screenUnlocked": "Screensaver",
"lang_searchBase": "Search Base",
@@ -150,7 +135,10 @@
"lang_show": "Show",
"lang_showLong": "Show content of module.",
"lang_skip": "Next",
- "lang_sshMultipleHeadsup": "If you want to add multiple SSH keys to the system, you can simply create multiple modules of type SSH and add them all to your system config. Note that you should have matching port and password settings for those configs, as it is currently undefined which of the settings will apply to the final configuration.",
+ "lang_sshAllowPass": "Allow login with password",
+ "lang_sshAllowPassInfo": "Set whether users can log in via SSH using the account's password; otherwise, only pubkey-auth is enabled.",
+ "lang_sshAllowedUsers": "Allowed users",
+ "lang_sshAllowedUsersInfo": "Decides which users are allowed to log in via SSH. The special user account \"demo\" is never allowed to log in via SSH, regardless of this setting.",
"lang_ssl": "SSL",
"lang_sslDescription": "Use SSL encryption to talk to AD\/LDAP server.",
"lang_supportedFiles": "Supported File Formats",
@@ -167,5 +155,8 @@
"lang_userDirectory": "User Directory",
"lang_userDirectoryInfo1": "Optional: If the clients should embed a separate directory (home directory, user directory) from a server for the user, please enter here the format in UNC notation, eg",
"lang_userDirectoryInfo2": "%s is a placeholder for the user's login name.",
- "lang_userDirectoryInfo3": "The directory is loaded with the same credentials that the user specifies when login. (That is no Kerberos support, etc.)"
+ "lang_userDirectoryInfo3": "The directory is loaded with the same credentials that the user specifies when login. (That is no Kerberos support, etc.)",
+ "lang_user_all": "Everyone",
+ "lang_user_root_only": "Only root",
+ "lang_user_user_only": "Everyone except root"
} \ No newline at end of file
diff --git a/modules-available/sysconfig/page.inc.php b/modules-available/sysconfig/page.inc.php
index 64162294..b11f399e 100644
--- a/modules-available/sysconfig/page.inc.php
+++ b/modules-available/sysconfig/page.inc.php
@@ -152,11 +152,12 @@ class Page_SysConfig extends Page
$listid = Request::post('list', Request::REQUIRED, 'int');
$this->listConfigContents($listid);
return;
+ default:
}
Message::addError('invalid-action', $action, 'main');
}
- private function getLocationNames($locations, $ids)
+ private function getLocationNames(array $locations, array $ids): string
{
$ret = array();
foreach ($ids as $id) {
@@ -174,12 +175,12 @@ class Page_SysConfig extends Page
private function listConfigs()
{
// Configs
- $res = Database::simpleQuery("SELECT c.configid, c.title, c.filepath, c.status, c.dateline,
+ $res = Database::simpleQuery("SELECT c.configid, c.title, c.filepath, c.status, c.dateline, c.warnings,
GROUP_CONCAT(DISTINCT cl.locationid) AS loclist, GROUP_CONCAT(DISTINCT cxm.moduleid) AS modlist
FROM configtgz c
LEFT JOIN configtgz_x_module cxm USING (configid)
LEFT JOIN configtgz_location cl ON (c.configid = cl.configid)
- GROUP BY configid
+ GROUP BY configid, title
ORDER BY title ASC");
$configs = array();
if ($this->currentLoc !== 0) {
@@ -188,7 +189,7 @@ class Page_SysConfig extends Page
$locationName = false;
}
$hasDefault = false;
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
if (is_null($row['loclist'])) {
$locList = array();
} else {
@@ -208,6 +209,8 @@ class Page_SysConfig extends Page
$this->haveOverriddenLocations = true;
}
$configs[] = array(
+ 'warnings' => $row['warnings'],
+ 'warnings_hidden' => (!empty($row['warnings']) && $row['status'] === 'OK') ? '' : 'hidden',
'configid' => $row['configid'],
'config' => $row['title'],
'modlist' => $row['modlist'],
@@ -234,7 +237,7 @@ class Page_SysConfig extends Page
private function listModules()
{
// Config modules
- $modules = ConfigModule::getAll();
+ $modules = ConfigModule::getAll() ?? [];
$types = array_map(function ($mod) { return $mod->moduleType(); }, $modules);
$titles = array_map(function ($mod) { return $mod->title(); }, $modules);
array_multisort($types, SORT_ASC, $titles, SORT_ASC, $modules);
@@ -265,27 +268,7 @@ class Page_SysConfig extends Page
Taskmanager::addErrorMessage($status);
Util::redirect('?do=sysconfig&locationid=' . $this->currentLoc);
}
-
- // Sort files for better display
- $dirs = array();
- foreach ($status['data']['entries'] as $file) {
- if ($file['isdir'])
- continue;
- $dirs[dirname($file['name'])][] = $file;
- }
- ksort($dirs);
- $list = array();
- foreach ($dirs as $dir => $files) {
- $list[] = array(
- 'name' => $dir,
- 'isdir' => true
- );
- sort($files);
- foreach ($files as $file) {
- $file['size'] = Util::readableFileSize($file['size']);
- $list[] = $file;
- }
- }
+ $list = SysConfig::archiveContentsFromTask($status);
// render the template
Render::addDialog(Dictionary::translate('lang_contentOf') . ' ' . $row['title'], false, 'custom-filelist', array(
@@ -309,7 +292,7 @@ class Page_SysConfig extends Page
. " ORDER BY module.title ASC", array('configid' => $configid));
$modules = array();
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($res as $row) {
$modules[] = array(
'module' => $row['moduletitle'],
'moduleid' => $row['moduleid']
@@ -354,7 +337,7 @@ class Page_SysConfig extends Page
{
$configid = Request::post('rebuild', Request::REQUIRED, 'int');
$config = ConfigTgz::get($configid);
- if ($config === false) {
+ if ($config === null) {
Message::addError('config-invalid', $configid);
Util::redirect('?do=sysconfig&locationid=' . $this->currentLoc);
}
@@ -393,9 +376,9 @@ class Page_SysConfig extends Page
Message::addSuccess('module-deleted', $module['title']);
}
// Rebuild depending config.tgz
- while ($crow = $existing->fetch(PDO::FETCH_ASSOC)) {
+ foreach ($existing as $crow) {
$config = ConfigTgz::get($crow['configid']);
- if ($config !== false) {
+ if ($config !== null) {
$config->generate();
}
}
@@ -419,11 +402,11 @@ class Page_SysConfig extends Page
{
$moduleid = Request::post('rebuild', Request::REQUIRED);
$module = ConfigModule::get($moduleid);
- if ($module === false) {
+ if ($module === null) {
Message::addError('config-invalid', $moduleid);
Util::redirect('?do=sysconfig');
}
- $ret = $module->generate(false, 250);
+ $ret = $module->generate(false, null, 500);
if ($ret === true)
Message::addSuccess('module-rebuilt', $module->title());
elseif ($ret === false)
@@ -437,7 +420,7 @@ class Page_SysConfig extends Page
{
$configid = Request::post('del', Request::REQUIRED);
$config = ConfigTgz::get($configid);
- if ($config === false) {
+ if ($config === null) {
Message::addError('config-invalid', $configid);
Util::redirect('?do=sysconfig&locationid=' . $this->currentLoc);
}
@@ -481,22 +464,14 @@ class Page_SysConfig extends Page
if (Request::post('action') === 'status') {
$mods = Request::post('mods');
$confs = Request::post('confs');
- $outMods = array();
- $outConfs = array();
$mods = explode(',', $mods);
$confs = explode(',', $confs);
// Mods
- $res = Database::simpleQuery("SELECT moduleid FROM configtgz_module
+ $outMods = Database::queryAll("SELECT moduleid AS id FROM configtgz_module
WHERE moduleid in (:mods) AND status = 'OK'", compact('mods'));
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- $outMods[] = $row['moduleid'];
- }
// Confs
- $res = Database::simpleQuery("SELECT configid FROM configtgz
+ $outConfs = Database::queryAll("SELECT configid AS id, warnings FROM configtgz
WHERE configid in (:confs) AND status = 'OK'", compact('confs'));
- while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
- $outConfs[] = $row['configid'];
- }
Header('Content-Type: application/json');
die(json_encode(array('mods' => $outMods, 'confs' => $outConfs)));
}
diff --git a/modules-available/sysconfig/templates/ad-selfsearch.html b/modules-available/sysconfig/templates/ad-selfsearch.html
index e6a19468..0eefc372 100644
--- a/modules-available/sysconfig/templates/ad-selfsearch.html
+++ b/modules-available/sysconfig/templates/ad-selfsearch.html
@@ -42,7 +42,6 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<button type="submit" class="btn btn-primary">&laquo; {{lang_back}}</button>
</form>
@@ -67,7 +66,6 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<input name="fingerprint" value="{{fingerprint}}" type="hidden">
<button id="nextbutton" type="submit" class="btn btn-primary" style="display:none">{{lang_skip}} &raquo;</button>
diff --git a/modules-available/sysconfig/templates/ad-start.html b/modules-available/sysconfig/templates/ad-start.html
index 933859fd..6dd6208a 100644
--- a/modules-available/sysconfig/templates/ad-start.html
+++ b/modules-available/sysconfig/templates/ad-start.html
@@ -21,7 +21,7 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
<span class="input-group-addon slx-ga2">{{lang_moduleTitle}}</span>
- <input tabindex="1" name="title" value="{{title}}" type="text" class="form-control" autofocus>
+ <input tabindex="1" name="title" value="{{title}}" type="text" class="form-control" autofocus required>
</div>
<div class="input-group">
<span class="input-group-addon slx-ga2">Server *</span>
@@ -77,16 +77,6 @@
<br>
<div>
<div class="checkbox">
- <input id="num-cb" type="checkbox" name="fixnumeric" {{#fixnumeric}}checked{{/fixnumeric}}>
- <label for="num-cb"><b>{{lang_fixNumeric}}</b></label>
- </div>
- <div>
- <i>{{lang_fixNumericDescription}}</i>
- </div>
- </div>
- <br>
- <div>
- <div class="checkbox">
<input id="ssl-cb" type="checkbox" name="ssl" onchange="$('#cert-box').css('display', this.checked ? '' : 'none')" {{#ssl}}checked{{/ssl}}>
<label for="ssl-cb"><b>{{lang_ssl}}</b></label>
</div>
diff --git a/modules-available/sysconfig/templates/ad_ldap-checkconnection.html b/modules-available/sysconfig/templates/ad_ldap-checkconnection.html
index e686c29f..ced65650 100644
--- a/modules-available/sysconfig/templates/ad_ldap-checkconnection.html
+++ b/modules-available/sysconfig/templates/ad_ldap-checkconnection.html
@@ -30,7 +30,6 @@
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<button type="submit" class="btn btn-primary">&laquo; {{lang_back}}</button>
</form>
@@ -55,7 +54,6 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<input name="originalbinddn" value="{{binddn}}" type="hidden">
<button id="nextbutton" type="submit" class="btn btn-primary" style="display:none">{{lang_next}} &raquo;</button>
diff --git a/modules-available/sysconfig/templates/ad_ldap-checkcredentials.html b/modules-available/sysconfig/templates/ad_ldap-checkcredentials.html
index d698d994..b560eecd 100644
--- a/modules-available/sysconfig/templates/ad_ldap-checkcredentials.html
+++ b/modules-available/sysconfig/templates/ad_ldap-checkcredentials.html
@@ -25,7 +25,6 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<button type="submit" class="btn btn-primary">&laquo; {{lang_back}}</button>
</form>
@@ -49,13 +48,13 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<input name="fingerprint" value="{{fingerprint}}" type="hidden">
<input name="originalbinddn" value="{{binddn}}" type="hidden">
<button id="nextbutton" type="submit" class="btn btn-primary" style="display:none">{{lang_skip}} &raquo;</button>
</form>
</div>
+<div class="clearfix"></div>
<script type="text/javascript">
function ldapCb(task)
{
diff --git a/modules-available/sysconfig/templates/ad_ldap-homedir.html b/modules-available/sysconfig/templates/ad_ldap-homedir.html
index 8a6c10de..33f55c16 100644
--- a/modules-available/sysconfig/templates/ad_ldap-homedir.html
+++ b/modules-available/sysconfig/templates/ad_ldap-homedir.html
@@ -17,7 +17,6 @@
{{#mapping}}
<input type="hidden" name="mapping[{{field}}]" value="{{value}}">
{{/mapping}}
- <input name="fixnumeric" value="{{fixnumeric}}" type="hidden">
<input name="genuid" value="{{genuid}}" type="hidden">
<input name="fingerprint" value="{{fingerprint}}" type="hidden">
diff --git a/modules-available/sysconfig/templates/branding-check.html b/modules-available/sysconfig/templates/branding-check.html
index d48f9631..80eb4d48 100644
--- a/modules-available/sysconfig/templates/branding-check.html
+++ b/modules-available/sysconfig/templates/branding-check.html
@@ -20,7 +20,7 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="form-group">
<label for="title-id">{{lang_title}}</label>
- <input type="text" name="title" value="{{title}}" id ="title-id" class="form-control" placeholder="Name des Moduls">
+ <input type="text" name="title" value="{{title}}" id ="title-id" class="form-control" placeholder="Name des Moduls" required>
</div>
<div class="btn-group">
<a class="btn btn-default" href="?do=SysConfig&action=addmodule&step=Branding_Start">{{lang_cancel}}</a>
diff --git a/modules-available/sysconfig/templates/branding-start.html b/modules-available/sysconfig/templates/branding-start.html
index 0db085d9..a6346552 100644
--- a/modules-available/sysconfig/templates/branding-start.html
+++ b/modules-available/sysconfig/templates/branding-start.html
@@ -14,7 +14,7 @@
<input type="text" class="form-control" readonly placeholder="{{lang_selectFile}}">
<span class="input-group-btn">
<span class="btn btn-default btn-file">
- {{lang_browseForFile}}&hellip; <input type="file" name="file" id="input-file">
+ {{lang_browseForFile}}&hellip; <input type="file" accept="image/svg+xml" name="file" id="input-file">
</span>
</span>
</div>
diff --git a/modules-available/sysconfig/templates/cfg-start.html b/modules-available/sysconfig/templates/cfg-start.html
index b4628cba..018cf89f 100644
--- a/modules-available/sysconfig/templates/cfg-start.html
+++ b/modules-available/sysconfig/templates/cfg-start.html
@@ -3,7 +3,7 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
<span class="input-group-addon">{{lang_name}} *</span>
- <input type="text" name="title" value="{{title}}" class="form-control" placeholder="{{lang_configuration}}" autofocus="autofocus">
+ <input type="text" name="title" value="{{title}}" class="form-control" placeholder="{{lang_configuration}}" autofocus="autofocus" required>
</div>
<hr>
<p>{{lang_configurationChoose}}</p>
diff --git a/modules-available/sysconfig/templates/custom-filelist.html b/modules-available/sysconfig/templates/custom-filelist.html
index 344eece3..20cedfda 100644
--- a/modules-available/sysconfig/templates/custom-filelist.html
+++ b/modules-available/sysconfig/templates/custom-filelist.html
@@ -4,11 +4,23 @@
{{#files}}
<tr>
{{#isdir}}
- <td class="fileEntry slx-bold" colspan="2">{{name}}</td>
+ <td class="fileEntry slx-bold" colspan="4">{{name}}</td>
{{/isdir}}
{{^isdir}}
- <td class="fileEntry">{{name}}</td>
- <td>{{size}}</td>
+ <td class="fileEntry">
+ {{name}}
+ {{#linkTarget}}
+ -&gt;
+ <span class="text-nowrap">{{linkTarget}}</span>
+ {{/linkTarget}}
+ </td>
+ <td class="text-nowrap">{{user}}{{#user}}{{#group}}/{{/group}}{{/user}}{{group}}</td>
+ <td class="text-nowrap">{{userId}}:{{groupId}}</td>
+ <td class="text-nowrap">
+ {{^linkTarget}}
+ {{size}}
+ {{/linkTarget}}
+ </td>
{{/isdir}}
</tr>
{{/files}}
diff --git a/modules-available/sysconfig/templates/custom-fileselect.html b/modules-available/sysconfig/templates/custom-fileselect.html
index f14a6fde..5f190f08 100644
--- a/modules-available/sysconfig/templates/custom-fileselect.html
+++ b/modules-available/sysconfig/templates/custom-fileselect.html
@@ -4,7 +4,8 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
<span class="input-group-addon">{{lang_moduleName}}</span>
- <input type="text" name="title" value="{{title}}" class="form-control" placeholder="Mein Konfigurationsmodul" autofocus="autofocus">
+ <input type="text" name="title" value="{{title}}" class="form-control" placeholder="Mein Konfigurationsmodul"
+ autofocus="autofocus" required>
</div>
<div class="pull-right">
<button type="submit" class="btn btn-primary">{{lang_next}} &raquo;</button>
@@ -12,20 +13,43 @@
<div class="clearfix"></div>
<hr>
<p>{{lang_checkFileContent}}</p>
+ {{#userGroupWarn}}
+ <div class="alert alert-warning">
+ {{lang_moduleOwnerWarn}}
+ </div>
+ <div class="checkbox">
+ <input id="force-owner" type="checkbox" name="force-owner" value="1" checked>
+ <label for="force-owner">{{lang_forceRootOwner}}</label>
+ </div>
+ <div class="slx-space"></div>
+ {{/userGroupWarn}}
<table class="table table-bordered table-condensed">
- {{#files}}
+ {{#files}}
<tr>
{{#isdir}}
- <td class="fileEntry slx-bold" colspan="2">{{name}}</td>
+ <td class="fileEntry slx-bold" colspan="4">{{name}}</td>
{{/isdir}}
{{^isdir}}
- <td class="fileEntry">{{name}}</td>
- <td>{{size}}</td>
+ <td class="fileEntry">
+ {{name}}
+ {{#linkTarget}}
+ -&gt;
+ <span class="text-nowrap">{{linkTarget}}</span>
+ {{/linkTarget}}
+ </td>
+ <td class="text-nowrap">{{user}}{{#user}}{{#group}}/{{/group}}{{/user}}{{group}}</td>
+ <td class="text-nowrap">{{userId}}:{{groupId}}</td>
+ <td class="text-nowrap">
+ {{^linkTarget}}
+ {{size}}
+ {{/linkTarget}}
+ </td>
{{/isdir}}
</tr>
- {{/files}}
+ {{/files}}
</table>
<div class="pull-right">
<button type="submit" class="btn btn-primary">{{lang_next}} &raquo;</button>
</div>
+ <div class="clearfix"></div>
</form>
diff --git a/modules-available/sysconfig/templates/ldap-finish.html b/modules-available/sysconfig/templates/ldap-finish.html
index a735e792..bd998bfd 100644
--- a/modules-available/sysconfig/templates/ldap-finish.html
+++ b/modules-available/sysconfig/templates/ldap-finish.html
@@ -12,6 +12,7 @@
<div id="finish" class="pull-right" style="display:none">
<a href="?do=SysConfig" class="btn btn-primary">{{lang_toSystemConfiguration}}</a>
</div>
+<div class="clearfix"></div>
<script type="text/javascript">
function ldapCb(task)
{
diff --git a/modules-available/sysconfig/templates/ldap-start.html b/modules-available/sysconfig/templates/ldap-start.html
index 28019d9e..e6c98680 100644
--- a/modules-available/sysconfig/templates/ldap-start.html
+++ b/modules-available/sysconfig/templates/ldap-start.html
@@ -11,7 +11,7 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
<span class="input-group-addon slx-ga2">{{lang_moduleTitle}}</span>
- <input tabindex="1" name="title" value="{{title}}" type="text" class="form-control">
+ <input tabindex="1" name="title" value="{{title}}" type="text" class="form-control" required>
</div>
<div class="input-group">
<span class="input-group-addon slx-ga2">Server *</span>
@@ -78,16 +78,6 @@
<br>
<div>
<div class="checkbox">
- <input id="num-cb" type="checkbox" name="fixnumeric" {{#fixnumeric}}checked{{/fixnumeric}}>
- <label for="num-cb"><b>{{lang_fixNumeric}}</b></label>
- </div>
- <div>
- <i>{{lang_fixNumericDescription}}</i>
- </div>
- </div>
- <br>
- <div>
- <div class="checkbox">
<input id="ssl-cb" type="checkbox" name="ssl" onchange="$('#cert-box').css('display', this.checked ? '' : 'none')" {{#ssl}}checked{{/ssl}}>
<label for="ssl-cb"><b>{{lang_ssl}}</b></label>
</div>
diff --git a/modules-available/sysconfig/templates/list-configs.html b/modules-available/sysconfig/templates/list-configs.html
index 83feeaa6..1370155f 100644
--- a/modules-available/sysconfig/templates/list-configs.html
+++ b/modules-available/sysconfig/templates/list-configs.html
@@ -20,11 +20,17 @@
<input type="hidden" name="locationid" value="{{locationid}}">
<table id="conftable" class="slx-table table-hover" style="width:100%">
{{#configs}}
- <tr>
- <td data-id="{{configid}}" data-modlist="{{modlist}}" class="confrow slx-pointer" width="100%" title="{{dateline_s}}">
- <table class="slx-ellipsis"><tr><td>{{config}}</td></tr></table>
+ <tr data-id="{{configid}}" data-modlist="{{modlist}}" class="confrow">
+ <td class="title slx-pointer" width="100%" title="{{dateline_s}}">
+ <table class="slx-ellipsis"><tr><td>
+ <button type="button" class="btn btn-xs btn-default btn-warnings {{warnings_hidden}}" data-confirm="#confirm-mod-{{configid}}">
+ <span class="glyphicon glyphicon-exclamation-sign text-danger"></span>
+ </button>
+ {{config}}
+ </td></tr></table>
</td>
<td>
+ <pre id="confirm-mod-{{configid}}" class="hidden row-warnings">{{warnings}}</pre>
{{^current}}
<button class="btn btn-primary btn-xs" name="activate" value="{{configid}}" {{perms.config.assign.disabled}}>
<span class="glyphicon glyphicon-flag"></span>
@@ -49,10 +55,10 @@
{{^locationid}}
<button
{{#needrebuild}}
- class="refconf btn btn-primary btn-xs"
+ class="btn-rebuild btn btn-primary btn-xs"
{{/needrebuild}}
{{^needrebuild}}
- class="refconf btn btn-default btn-xs"
+ class="btn-rebuild btn btn-default btn-xs"
{{/needrebuild}}
name="rebuild" value="{{configid}}" title="{{lang_rebuild}}"
{{perms.config.edit.disabled}}>
diff --git a/modules-available/sysconfig/templates/list-legend.html b/modules-available/sysconfig/templates/list-legend.html
index 809a0449..49974a5f 100644
--- a/modules-available/sysconfig/templates/list-legend.html
+++ b/modules-available/sysconfig/templates/list-legend.html
@@ -25,6 +25,10 @@
<span class="btn btn-danger btn-xs" title="{{lang_delete}}"><span class="glyphicon glyphicon-trash"></span></span>
{{lang_deleteLong}}
</p>
+ <p>
+ <span class="glyphicon glyphicon-question-sign" title="{{lang_moduleUnused}}"></span>
+ {{lang_moduleUnusedLong}}
+ </p>
{{#showLocationBadge}}
<p>
<span class="badge">+4</span>
diff --git a/modules-available/sysconfig/templates/list-modules.html b/modules-available/sysconfig/templates/list-modules.html
index b8783c59..5bd19446 100644
--- a/modules-available/sysconfig/templates/list-modules.html
+++ b/modules-available/sysconfig/templates/list-modules.html
@@ -10,10 +10,13 @@
<input type="hidden" name="action" value="module">
<table id="modtable" class="slx-table table-hover" style="width:100%">
{{#modules}}
- <tr>
+ <tr data-id="{{id}}" class="modrow">
<td class="badge text-nowrap">{{moduleType}}</td>
- <td data-id="{{id}}" class="modrow slx-pointer" width="100%" title="{{lang_lastEdited}} {{dateline_s}}">
- <table class="slx-ellipsis"><tr><td>{{title}}</td></tr></table>
+ <td class="title slx-pointer" width="100%" title="{{lang_lastEdited}} {{dateline_s}}">
+ <table class="slx-ellipsis"><tr><td>
+ <span class="glyphicon glyphicon-question-sign pull-right icon-unused hidden" title="{{lang_moduleUnused}}"></span>
+ {{title}}
+ </td></tr></table>
</td>
<td class="text-nowrap">
{{#allowDownload}}
@@ -27,10 +30,10 @@
<td class="text-nowrap">
<button
{{#needRebuild}}
- class="refmod btn btn-primary btn-xs"
+ class="btn-rebuild btn btn-primary btn-xs"
{{/needRebuild}}
{{^needRebuild}}
- class="refmod btn btn-default btn-xs"
+ class="btn-rebuild btn btn-default btn-xs"
{{/needRebuild}}
name="rebuild" value="{{id}}" title="{{lang_rebuild}}" {{perms.module.edit.disabled}}>
<span class="glyphicon glyphicon-refresh"></span>
diff --git a/modules-available/sysconfig/templates/sshconfig-start.html b/modules-available/sysconfig/templates/sshconfig-start.html
index 33108161..b56be415 100644
--- a/modules-available/sysconfig/templates/sshconfig-start.html
+++ b/modules-available/sysconfig/templates/sshconfig-start.html
@@ -3,35 +3,43 @@
<input type="hidden" name="edit" value="{{edit}}">
<div class="input-group">
<span class="input-group-addon">{{lang_moduleName}}</span>
- <input type="text" name="title" value="{{title}}" class="form-control" autofocus="autofocus">
+ <input type="text" name="title" value="{{title}}" class="form-control" autofocus="autofocus" required>
</div>
+ <br>
<div class="form-group">
- <div class="checkbox">
- <input type="checkbox" name="allowPasswordLogin" value="yes" {{#apl}}checked{{/apl}}>
- <label><b>{{lang_allowPass}}</b></label>
- </div>
+ <label>{{lang_sshAllowedUsers}}
+ <select class="form-control" name="allowedUsersLogin">
+ <option value="ROOT_ONLY" {{USR_ROOT_ONLY_selected}}>{{lang_user_root_only}}</option>
+ <option value="USER_ONLY" {{USR_USER_ONLY_selected}}>{{lang_user_user_only}}</option>
+ <option value="ALL" {{USR_ALL_selected}}>{{lang_user_all}}</option>
+ </select>
+ </label>
<div>
- <i>{{lang_allowPassInfo}}</i>
+ <i>{{lang_sshAllowedUsersInfo}}</i>
</div>
</div>
<div class="form-group">
- <label for="root-key">{{lang_rootKey}}</label>
- <input class="form-control" type="text" name="publicKey" value="{{publicKey}}" id="root-key" pattern="[a-z0-9\-]+ +[a-zA-Z0-9=/\+]+ +.*">
- <i>{{lang_rootKeyInfo}}</i>
+ <label>{{lang_sshAllowPass}}
+ <select class="form-control" name="allowPasswordLogin">
+ <option value="NO" {{PWD_NO_selected}}>{{lang_no}}</option>
+ <option value="USER_ONLY" {{PWD_USER_ONLY_selected}}>{{lang_pwlogin_user_only}}</option>
+ <option value="YES" {{PWD_YES_selected}}>{{lang_yes}}</option>
+ </select>
+ </label>
+ <div>
+ <i>{{lang_sshAllowPassInfo}}</i>
+ </div>
</div>
<div class="form-group">
<label for="port">{{lang_listenPort}}</label>
<input class="form-control" type="text" name="listenPort" value="{{listenPort}}" id="port" pattern="\d+" placeholder="22">
<i>{{lang_listenPortInfo}}</i>
</div>
- <p>
- <i>
- {{lang_sshMultipleHeadsup}}
- </i>
- </p>
+ <div class="btn-group">
+ <a class="btn btn-default" href="?do=SysConfig&action=addmodule">{{lang_back}}</a>
+ </div>
<div class="btn-group pull-right">
<button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
<div class="clearfix"></div>
</form>
-
diff --git a/modules-available/sysconfig/templates/sshkey-start.html b/modules-available/sysconfig/templates/sshkey-start.html
new file mode 100644
index 00000000..8033740c
--- /dev/null
+++ b/modules-available/sysconfig/templates/sshkey-start.html
@@ -0,0 +1,21 @@
+<form role="form" enctype="multipart/form-data" method="post" action="?do=SysConfig&amp;action=addmodule&amp;step={{step}}">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="edit" value="{{edit}}">
+ <div class="input-group">
+ <span class="input-group-addon">{{lang_moduleName}}</span>
+ <input type="text" name="title" value="{{title}}" class="form-control" autofocus="autofocus" required>
+ </div>
+ <div class="form-group">
+ <label for="root-key">{{lang_rootKey}}</label>
+ <input class="form-control" type="text" name="publicKey" value="{{publicKey}}" id="root-key" required pattern="[a-z0-9\-]+ +[a-zA-Z0-9=/\+]+ +.*">
+ <i>{{lang_rootKeyInfo}}</i>
+ </div>
+ <div class="btn-group">
+ <a class="btn btn-default" href="?do=SysConfig&action=addmodule">{{lang_back}}</a>
+ </div>
+ <div class="btn-group pull-right">
+ <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
+ </div>
+ <div class="clearfix"></div>
+</form>
+