summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2015-02-06 16:12:45 +0100
committerSimon Rettberg2015-02-06 16:12:45 +0100
commit161180cdf4e915526bc8d62c0301a09130fbf59e (patch)
tree3f59fd0da89fe42c2838885eef82b23064cac8a4
parentFinish config module editing (diff)
downloadslx-admin-161180cdf4e915526bc8d62c0301a09130fbf59e.tar.gz
slx-admin-161180cdf4e915526bc8d62c0301a09130fbf59e.tar.xz
slx-admin-161180cdf4e915526bc8d62c0301a09130fbf59e.zip
Add sshd config module
-rw-r--r--inc/configmodule.inc.php21
-rw-r--r--inc/configmodule/adauth.inc.php7
-rw-r--r--inc/configmodule/customodule.inc.php4
-rw-r--r--inc/configmodule/sshconfig.inc.php63
-rw-r--r--lang/de/config-module.json19
-rw-r--r--lang/de/templates/sysconfig/sshconfig-start.json10
-rw-r--r--lang/de/templates/translation/_page.json3
-rw-r--r--lang/en/config-module.json5
-rw-r--r--lang/en/templates/sysconfig/sshconfig-start.json10
-rw-r--r--lang/en/templates/translation/_page.json1
-rw-r--r--lang/pt/config-module.json3
-rw-r--r--lang/pt/templates/sysconfig/sshconfig-start.json3
-rw-r--r--lang/pt/templates/translation/_page.json3
-rw-r--r--modules/sysconfig/addmodule_adauth.inc.php4
-rw-r--r--modules/sysconfig/addmodule_branding.inc.php4
-rw-r--r--modules/sysconfig/addmodule_custommodule.inc.php6
-rw-r--r--modules/sysconfig/addmodule_sshconfig.inc.php72
-rw-r--r--modules/translation.inc.php21
-rw-r--r--templates/sysconfig/sshconfig-start.html26
-rw-r--r--templates/translation/_page.html1
20 files changed, 247 insertions, 39 deletions
diff --git a/inc/configmodule.inc.php b/inc/configmodule.inc.php
index 31c19953..4dd7c951 100644
--- a/inc/configmodule.inc.php
+++ b/inc/configmodule.inc.php
@@ -165,12 +165,20 @@ abstract class ConfigModule
public abstract function setData($key, $value);
/**
- * Get module specific data
+ * Get module specific data.
+ * Can be overridden by modules.
*
- * @param string $key key, name or id of data to get
+ * @param string $key key, name or id of data to get, or false to get the raw moduleData array
* @return mixed Module specific data
*/
- public abstract function getData($key);
+ public function getData($key)
+ {
+ if ($key === false)
+ return $this->moduleData;
+ if (!is_array($this->moduleData) || !isset($this->moduleData[$key]))
+ return false;
+ return $this->moduleData[$key];
+ }
/**
* Module specific version of generate.
@@ -275,16 +283,19 @@ abstract class ConfigModule
*
* @return boolean true on success, false otherwise
*/
- public final function update()
+ public final function update($title)
{
if ($this->moduleId === 0)
Util::traceError('ConfigModule::update called when moduleId == 0');
+ if (empty($title))
+ $title = $this->moduleTitle;
if (!$this->validateConfig())
return false;
// Update
- Database::exec("UPDATE configtgz_module SET contents = :contents, status = :status "
+ Database::exec("UPDATE configtgz_module SET title = :title, contents = :contents, status = :status "
. " WHERE moduleid = :moduleid LIMIT 1", array(
'moduleid' => $this->moduleId,
+ 'title' => $title,
'contents' => json_encode($this->moduleData),
'status' => 'OUTDATED'
));
diff --git a/inc/configmodule/adauth.inc.php b/inc/configmodule/adauth.inc.php
index 11087286..828469c3 100644
--- a/inc/configmodule/adauth.inc.php
+++ b/inc/configmodule/adauth.inc.php
@@ -47,13 +47,6 @@ class ConfigModule_AdAuth extends ConfigModule
return true;
}
- public function getData($key)
- {
- if (!is_array($this->moduleData) || !isset($this->moduleData[$key]))
- return false;
- return $this->moduleData[$key];
- }
-
// ############## Callbacks #############################
/**
diff --git a/inc/configmodule/customodule.inc.php b/inc/configmodule/customodule.inc.php
index 89f63549..31796e9c 100644
--- a/inc/configmodule/customodule.inc.php
+++ b/inc/configmodule/customodule.inc.php
@@ -19,9 +19,7 @@ class ConfigModule_CustomModule extends ConfigModule
protected function generateInternal($tgz, $parent)
{
if (!$this->validateConfig()) {
- if ($this->archive() !== false && file_exists($this->archive()))
- return true; // No new temp file given, old archive still exists, pretend it worked...
- return false;
+ return $this->archive() !== false && file_exists($this->archive()); // No new temp file given, old archive still exists, pretend it worked...
}
$task = Taskmanager::submit('MoveFile', array(
'source' => $this->tmpFile,
diff --git a/inc/configmodule/sshconfig.inc.php b/inc/configmodule/sshconfig.inc.php
new file mode 100644
index 00000000..853acf6a
--- /dev/null
+++ b/inc/configmodule/sshconfig.inc.php
@@ -0,0 +1,63 @@
+<?php
+
+ConfigModule::registerModule(
+ ConfigModule_SshConfig::MODID, // ID
+ Dictionary::translate('config-module', 'sshconfig_title'), // Title
+ Dictionary::translate('config-module', 'sshconfig_description'), // Description
+ Dictionary::translate('config-module', 'group_sshconfig'), // Group
+ true // Only one per config?
+);
+
+class ConfigModule_SshConfig extends ConfigModule
+{
+ const MODID = 'SshConfig';
+ const VERSION = 1;
+
+ protected function generateInternal($tgz, $parent)
+ {
+ if (!$this->validateConfig())
+ return false;
+ $config = $this->moduleData + array(
+ 'filename' => $tgz,
+ 'failOnParentFail' => false,
+ 'parent' => $parent
+ );
+ // Create config module, which will also check if the pubkey is valid
+ return Taskmanager::submit('SshdConfigGenerator', $config);
+ }
+
+ protected function moduleVersion()
+ {
+ return self::VERSION;
+ }
+
+ protected function validateConfig()
+ {
+ return isset($this->moduleData['publicKey']) && isset($this->moduleData['allowPasswordLogin']) && isset($this->moduleData['listenPort']);
+ }
+
+ public function setData($key, $value)
+ {
+ switch ($key) {
+ case 'publicKey':
+ break;
+ case 'allowPasswordLogin':
+ if ($value === true || $value === 'yes')
+ $value = 'yes';
+ elseif ($value === false || $value === 'no')
+ $value = 'no';
+ else
+ return false;
+ break;
+ case 'listenPort':
+ if (!is_numeric($value) || $value < 1 || $value > 65535)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ $this->moduleData[$key] = $value;
+ return true;
+ }
+
+}
diff --git a/lang/de/config-module.json b/lang/de/config-module.json
index 1e0874e1..6a6037ff 100644
--- a/lang/de/config-module.json
+++ b/lang/de/config-module.json
@@ -1,11 +1,14 @@
{
+ "adAuth_description": "Mit diesem Modul ist die Anmeldung an den Client-PCs mit den Benutzerkonten eines Active Directory m\u00f6glich. Je nach Konfiguration ist auch die Nutzung eines Benutzerverzeichnisses auf dem Client m\u00f6glich.",
"adAuth_title": "Active Directory Authentifizierung",
- "adAuth_description": "Mit diesem Modul ist die Anmeldung an den Client-PCs mit den Benutzerkonten eines Active Directory m\u00f6glich. Je nach Konfiguration ist auch die Nutzung eines Benutzerverzeichnisses auf dem Client m\u00f6glich.",
- "custom_title": "Generisches Modul hinzuf\u00fcgen",
- "custom_description": "Mit einem Erweiterten Modul ist es m\u00f6glich, beliebige Dateien zum Grundsystem hinzuzuf\u00fcgen Nutzen Sie dieses Modul, um z.B. spezielle Konfigurationsdateien auf den Client PCs zu verwenden, die sich nicht mit einem der anderen Wizards erstellen l\u00e4sst. Das Hinzuf\u00fcgen eines Erweiterten Moduls erfordert in der Regel zumindest grundlegende Systemkenntnisse im Linuxbereich.",
+ "branding_description": "Das Logo wird am Anmeldebildschirm und beim Starten des Systems angezeigt.",
"branding_title": "Einrichtungsspezifisches Logo",
- "branding_description": "Das Logo wird am Anmeldebildschirm und beim Starten des Systems angezeigt.",
- "group_authentication": "Authentifizierung",
- "group_branding": "Einrichtungsspezifisches Logo",
- "group_generic": "Generisch"
-}
+ "custom_description": "Mit einem Erweiterten Modul ist es m\u00f6glich, beliebige Dateien zum Grundsystem hinzuzuf\u00fcgen Nutzen Sie dieses Modul, um z.B. spezielle Konfigurationsdateien auf den Client PCs zu verwenden, die sich nicht mit einem der anderen Wizards erstellen l\u00e4sst. Das Hinzuf\u00fcgen eines Erweiterten Moduls erfordert in der Regel zumindest grundlegende Systemkenntnisse im Linuxbereich.",
+ "custom_title": "Generisches Modul hinzuf\u00fcgen",
+ "group_authentication": "Authentifizierung",
+ "group_branding": "Einrichtungsspezifisches Logo",
+ "group_generic": "Generisch",
+ "group_sshconfig": "SSH",
+ "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
diff --git a/lang/de/templates/sysconfig/sshconfig-start.json b/lang/de/templates/sysconfig/sshconfig-start.json
new file mode 100644
index 00000000..f9e412fe
--- /dev/null
+++ b/lang/de/templates/sysconfig/sshconfig-start.json
@@ -0,0 +1,10 @@
+{
+ "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_listenPort": "Listen port",
+ "lang_listenPortInfo": "Der Port, auf dem der sshd lauscht. Der offizielle Standard ist 22.",
+ "lang_moduleName": "Modulname",
+ "lang_rootKey": "root pubkey (\u00f6ffentlicher Schl\u00fcssel)",
+ "lang_rootKeyInfo": "Tragen Sie hier den \u00f6ffentlichen Schl\u00fcssel eines Schl\u00fcssel\u00fcpaars 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_save": "Speichern"
+} \ No newline at end of file
diff --git a/lang/de/templates/translation/_page.json b/lang/de/templates/translation/_page.json
index 1e59df52..639697de 100644
--- a/lang/de/templates/translation/_page.json
+++ b/lang/de/templates/translation/_page.json
@@ -1,8 +1,9 @@
{
"lang_adminInfo": "In diesem Abschnitt k\u00f6nnen Sie die JSON-Tags, die \u00fcbersetzten Texte durch die Website verwendet wird, enth\u00e4lt zu \u00e4ndern. Um dies zu tun, w\u00e4hlen Sie eine Vorlage aus, um ihre jeweiligen Tags \u00e4ndern. Alternativ klicken Sie auf den Link unten, um die Nachrichten der Website \u00e4ndern.",
+ "lang_editConfigModule": "Konfigurationsmodulbezeichnungsphrasen editieren",
"lang_editHardcoded": "Hardcoded-Texte bearbeiten",
"lang_editMessages": "Nachrichten bearbeiten",
- "lang_editSettings": "Einstellungs-Texte bearbeiten",
+ "lang_editSettings": "Einstellungstexte bearbeiten",
"lang_editTemplates": "Template-Texte bearbeiten",
"lang_langAdministration": "Sprache Verwaltung"
} \ No newline at end of file
diff --git a/lang/en/config-module.json b/lang/en/config-module.json
new file mode 100644
index 00000000..14ea9e93
--- /dev/null
+++ b/lang/en/config-module.json
@@ -0,0 +1,5 @@
+{
+ "group_sshconfig": "SSH",
+ "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
diff --git a/lang/en/templates/sysconfig/sshconfig-start.json b/lang/en/templates/sysconfig/sshconfig-start.json
new file mode 100644
index 00000000..1ce553cd
--- /dev/null
+++ b/lang/en/templates/sysconfig/sshconfig-start.json
@@ -0,0 +1,10 @@
+{
+ "lang_allowPass": "Allow password login",
+ "lang_allowPassInfo": "When active, logins via username and password are allowed. Otherwise, only pubkey authentication is possible.",
+ "lang_listenPort": "Listen port",
+ "lang_listenPortInfo": "Listen port for the sshd. Default is 22.",
+ "lang_moduleName": "Module name",
+ "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_save": "Save"
+} \ No newline at end of file
diff --git a/lang/en/templates/translation/_page.json b/lang/en/templates/translation/_page.json
index c9c6020d..5a48b696 100644
--- a/lang/en/templates/translation/_page.json
+++ b/lang/en/templates/translation/_page.json
@@ -1,5 +1,6 @@
{
"lang_adminInfo": "In this section you can change the JSON tags that contains the translated texts used by the site. To do this, select a template below to modify their respective tags. Alternatively, click the link below to change the messages of the site.",
+ "lang_editConfigModule": "Edit config module strings",
"lang_editHardcoded": "Edit hardcoded strings",
"lang_editMessages": "Edit Messages",
"lang_editSettings": "Edit configuration variables related strings",
diff --git a/lang/pt/config-module.json b/lang/pt/config-module.json
new file mode 100644
index 00000000..c44dc44f
--- /dev/null
+++ b/lang/pt/config-module.json
@@ -0,0 +1,3 @@
+[
+
+] \ No newline at end of file
diff --git a/lang/pt/templates/sysconfig/sshconfig-start.json b/lang/pt/templates/sysconfig/sshconfig-start.json
new file mode 100644
index 00000000..c44dc44f
--- /dev/null
+++ b/lang/pt/templates/sysconfig/sshconfig-start.json
@@ -0,0 +1,3 @@
+[
+
+] \ No newline at end of file
diff --git a/lang/pt/templates/translation/_page.json b/lang/pt/templates/translation/_page.json
index 68043805..491425a4 100644
--- a/lang/pt/templates/translation/_page.json
+++ b/lang/pt/templates/translation/_page.json
@@ -1,8 +1,5 @@
{
"lang_adminInfo": "Nesta se\u00e7\u00e3o \u00e9 poss\u00edvel alterar as TAGs de JSON que cont\u00e9m os textos traduzidos utilizados no site. Para fazer isto, selecione um template abaixo para modificar suas respectivas TAGs. Alternativamente, clique no link abaixo para alterar as mensagens do site.",
- "lang_editHardcoded": "",
"lang_editMessages": "Editar Mensagens",
- "lang_editSettings": "",
- "lang_editTemplates": "",
"lang_langAdministration": "Administra\u00e7\u00e3o da L\u00edngua"
} \ No newline at end of file
diff --git a/modules/sysconfig/addmodule_adauth.inc.php b/modules/sysconfig/addmodule_adauth.inc.php
index 26ca5b79..e39eac40 100644
--- a/modules/sysconfig/addmodule_adauth.inc.php
+++ b/modules/sysconfig/addmodule_adauth.inc.php
@@ -147,14 +147,14 @@ class AdAuth_Finish extends AddModule_Base
$module->setData('bindpw', Request::post('bindpw'));
$module->setData('home', Request::post('home'));
if ($this->edit !== false)
- $ret = $module->update();
+ $ret = $module->update($title);
else
$ret = $module->insert($title);
if (!$ret) {
Message::addError('value-invalid', 'any', 'any');
$tgz = false;
} else {
- $tgz = $module->generate(true, NULL, 200);
+ $tgz = $module->generate($this->edit === false, NULL, 200);
}
if ($tgz === false) {
AddModule_Base::setStep('AdAuth_Start'); // Continues with AdAuth_Start for render()
diff --git a/modules/sysconfig/addmodule_branding.inc.php b/modules/sysconfig/addmodule_branding.inc.php
index 7fc7abc5..c1c5f6b7 100644
--- a/modules/sysconfig/addmodule_branding.inc.php
+++ b/modules/sysconfig/addmodule_branding.inc.php
@@ -215,12 +215,12 @@ class Branding_Finish extends AddModule_Base
}
$module->setData('tmpFile', $tgz);
if ($this->edit !== false)
- $ret = $module->update();
+ $ret = $module->update($title);
else
$ret = $module->insert($title);
if (!$ret)
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
- elseif ($module->generate(true, NULL, 200) === false)
+ elseif ($module->generate($this->edit === false, NULL, 200) === false)
Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start');
Session::set('logo_tgz', false);
Session::set('logo_name', false);
diff --git a/modules/sysconfig/addmodule_custommodule.inc.php b/modules/sysconfig/addmodule_custommodule.inc.php
index dfa03a19..e3ddeca8 100644
--- a/modules/sysconfig/addmodule_custommodule.inc.php
+++ b/modules/sysconfig/addmodule_custommodule.inc.php
@@ -113,7 +113,7 @@ class CustomModule_CompressModule extends AddModule_Base
$tempfile = Session::get('mod_temp');
if (empty($title) || empty($tempfile) || !file_exists($tempfile)) {
Message::addError('empty-field');
- return;
+ Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start');
}
// Recompress using task manager
$this->taskId = 'tgzmod' . mt_rand() . '-' . microtime(true);
@@ -142,12 +142,12 @@ class CustomModule_CompressModule extends AddModule_Base
}
$module->setData('tmpFile', $destFile);
if ($this->edit !== false)
- $ret = $module->update();
+ $ret = $module->update($title);
else
$ret = $module->insert($title);
if (!$ret)
Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start');
- elseif (!$module->generate(true, NULL, 200))
+ elseif (!$module->generate($this->edit === false, NULL, 200))
Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start');
Session::set('mod_temp', false);
Session::save();
diff --git a/modules/sysconfig/addmodule_sshconfig.inc.php b/modules/sysconfig/addmodule_sshconfig.inc.php
new file mode 100644
index 00000000..e50ca72c
--- /dev/null
+++ b/modules/sysconfig/addmodule_sshconfig.inc.php
@@ -0,0 +1,72 @@
+<?php
+
+/*
+ * Wizard for configuring the sshd (client side).
+ */
+
+class SshConfig_Start extends AddModule_Base
+{
+
+ protected function renderInternal()
+ {
+ if ($this->edit !== false) {
+ $data = $this->edit->getData(false) + array(
+ 'title' => $this->edit->title(),
+ 'edit' => $this->edit->id(),
+ 'apl' => $this->edit->getData('allowPasswordLogin') === 'yes'
+ );
+ } else {
+ $data = array();
+ }
+ Render::addDialog(Dictionary::translate('lang_clientSshConfig'), false, 'sysconfig/sshconfig-start', $data + array(
+ 'step' => 'SshConfig_Finish',
+ ));
+ }
+
+}
+
+class SshConfig_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 === false)
+ $module = ConfigModule::getInstance('SshConfig');
+ else
+ $module = $this->edit;
+ if ($module === false) {
+ Message::addError('error-read', 'sshconfig.inc.php');
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
+ }
+ $module->setData('allowPasswordLogin', Request::post('allowPasswordLogin') === 'yes');
+ if (!$module->setData('listenPort', Request::post('listenPort'))) {
+ Message::addError('value-invalid', 'port', Request::post('listenPort'));
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
+ }
+ if (!$module->setData('publicKey', Request::post('publicKey'))) {
+ Message::addError('value-invalid', 'pubkey', Request::post('publicKey'));
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
+ }
+ if ($this->edit !== false)
+ $ret = $module->update($title);
+ else
+ $ret = $module->insert($title);
+ if (!$ret)
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
+ elseif (!$module->generate($this->edit === false, NULL, 200))
+ Util::redirect('?do=SysConfig&action=addmodule&step=SshConfig_Start');
+ // Yay
+ if ($this->edit !== false)
+ Message::addSuccess('module-edited');
+ else
+ Message::addSuccess('module-added');
+ Util::redirect('?do=SysConfig');
+ }
+
+}
diff --git a/modules/translation.inc.php b/modules/translation.inc.php
index 4dc2f515..5b8b452a 100644
--- a/modules/translation.inc.php
+++ b/modules/translation.inc.php
@@ -13,9 +13,6 @@ class Page_Translation extends Page
*/
private $template = false;
private $page = false;
- private $update = false;
- private $delete = false;
- private $tags = false;
protected function doPreprocess()
{
@@ -74,6 +71,14 @@ class Page_Translation extends Page
'tags' => $this->loadSettingsArray()
));
break;
+ case 'config-module':
+ //renders the hardcoded messages edit page
+ Render::addTemplate('translation/edit', array(
+ 'path' => 'config-module',
+ 'langs' => $langs,
+ 'tags' => $this->buildTranslationTable('config-module')
+ ));
+ break;
case 'template':
$this->template = Util::safePath($this->template);
if ($this->template === false) {
@@ -315,8 +320,7 @@ class Page_Translation extends Page
}
}
}
-
- //finds every JSON tag withing the JSON language files
+ // Finds every JSON tag withing the JSON language files
foreach ($langArray as $lang) {
$jsonTags = Dictionary::getArray($path, $lang);
if (!is_array($jsonTags))
@@ -333,6 +337,13 @@ class Page_Translation extends Page
$tags[$tag]['missing'] --;
}
}
+ // Fill the blanks
+ foreach ($langArray as $lang) {
+ foreach (array_keys($tags) as $tagName) {
+ if (!isset($tags[$tagName]['langs'][$lang]))
+ $tags[$tagName]['langs'][$lang]['lang'] = $lang;
+ }
+ }
// Finally remove $lang from the keys so mustache will iterate over them via {{#..}}
foreach ($tags as &$tag) {
$tag['langs'] = array_values($tag['langs']);
diff --git a/templates/sysconfig/sshconfig-start.html b/templates/sysconfig/sshconfig-start.html
new file mode 100644
index 00000000..9d1426d1
--- /dev/null
+++ b/templates/sysconfig/sshconfig-start.html
@@ -0,0 +1,26 @@
+<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">
+ </div>
+ <div class="form-group">
+ <label class="checkbox" for="allow-pw">{{lang_allowPass}}
+ <input type="checkbox" name="allowPasswordLogin" value="yes" {{#apl}}checked{{/apl}}>
+ </label>
+ <i>{{lang_allowPassInfo}}</i>
+ </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>
+ </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+">
+ <i>{{lang_listenPortInfo}}</i>
+ </div>
+ <button type="submit" class="btn btn-primary">{{lang_save}}</button>
+</form>
+
diff --git a/templates/translation/_page.html b/templates/translation/_page.html
index ed4e8c35..37122d7e 100644
--- a/templates/translation/_page.html
+++ b/templates/translation/_page.html
@@ -9,6 +9,7 @@
<li><a href="?do=Translation&amp;page=messages">{{lang_editMessages}}</a></li>
<li><a href="?do=Translation&amp;page=hardcoded">{{lang_editHardcoded}}</a></li>
<li><a href="?do=Translation&amp;page=settings">{{lang_editSettings}}</a></li>
+ <li><a href="?do=Translation&amp;page=config-module">{{lang_editConfigModule}}</a></li>
</ul>
</div>
</div>