diff --git a/data/web/admin.php b/data/web/admin.php index e01035a4..980f663b 100644 --- a/data/web/admin.php +++ b/data/web/admin.php @@ -137,6 +137,47 @@ $tfa_data = get_tfa(); + +
+
+

Rspamd UI

+
+
+
+
+
+
+
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+
+
+
+ Rspamd UI +
+
+
+
@@ -148,6 +189,7 @@ $tfa_data = get_tfa(); Relayhosts + Rspamd settings map
@@ -429,13 +471,13 @@ $tfa_data = get_tfa();
- +
- +
@@ -456,6 +498,89 @@ $tfa_data = get_tfa(); + +
+
Rspamd settings map
+
+ Active settings map + +
+ +
+
+
+
+ + + + (ID #) + + +
+
+
+
+ +
+

+
+ +
+

+
+ +
+ + +
+ + +
+
+ + +
+
+ +
+ + + +
+ +
+
+
+ +
+
+
diff --git a/data/web/debug.php b/data/web/debug.php index 35511898..5bf97d32 100644 --- a/data/web/debug.php +++ b/data/web/debug.php @@ -24,13 +24,6 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
  • API
  • -
    @@ -275,60 +268,6 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
    -
    -
    -
    -

    Rspamd UI

    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - -
    -
    -
    -
    -
    - Rspamd UI -
    -
    -
    -
    -
    - -
    -
    -
    -

    Rspamd settings map

    -
    -
    - -
    -
    -
    - diff --git a/data/web/inc/footer.inc.php b/data/web/inc/footer.inc.php index 683b844c..34fe9c7e 100644 --- a/data/web/inc/footer.inc.php +++ b/data/web/inc/footer.inc.php @@ -152,6 +152,9 @@ $(document).ready(function() { 'use strict'; if ($('a[data-toggle="tab"]').length) { $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { + if ($(this).data('dont-remember') == 1) { + return true; + } var id = $(this).parents('[role="tablist"]').attr('id'); var key = 'lastTag'; if (id) { diff --git a/data/web/inc/functions.rsettings.inc.php b/data/web/inc/functions.rsettings.inc.php new file mode 100644 index 00000000..478e41e4 --- /dev/null +++ b/data/web/inc/functions.rsettings.inc.php @@ -0,0 +1,164 @@ + 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + $content = $_data['content']; + $desc = $_data['desc']; + $active = $_data['active']; + if (empty($content)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'Content cannot be empty' + ); + return false; + } + try { + $stmt = $pdo->prepare("INSERT INTO `settingsmap` (`content`, `desc`, `active`) + VALUES (:content, :desc, :active)"); + $stmt->execute(array( + ':content' => $content, + ':desc' => $desc, + ':active' => $active + )); + } + catch (PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + $_SESSION['return'] = array( + 'type' => 'success', + 'msg' => 'Added settings map entry' + ); + break; + case 'edit': + if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + $ids = (array)$_data['id']; + foreach ($ids as $id) { + $is_now = rsettings('details', $id); + if (!empty($is_now)) { + $content = (!empty($_data['content'])) ? $_data['content'] : $is_now['content']; + $desc = (!empty($_data['desc'])) ? $_data['desc'] : $is_now['desc']; + $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int']; + } + else { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'Settings map invalid' + ); + return false; + } + $content = trim($content); + try { + $stmt = $pdo->prepare("UPDATE `settingsmap` SET + `content` = :content, + `desc` = :desc, + `active` = :active + WHERE `id` = :id"); + $stmt->execute(array( + ':content' => $content, + ':desc' => $desc, + ':active' => $active, + ':id' => $id + )); + } + catch (PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + } + $_SESSION['return'] = array( + 'type' => 'success', + 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars(implode(', ', $ids))) + ); + break; + case 'delete': + if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + $ids = (array)$_data['id']; + foreach ($ids as $id) { + try { + $stmt = $pdo->prepare("DELETE FROM `settingsmap` WHERE `id`= :id"); + $stmt->execute(array(':id' => $id)); + } + catch (PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + } + $_SESSION['return'] = array( + 'type' => 'success', + 'msg' => 'Removed settings map ID' + ); + break; + case 'get': + if ($_SESSION['mailcow_cc_role'] != "admin") { + return false; + } + $settingsmaps = array(); + try { + $stmt = $pdo->query("SELECT `id`, `desc`, `active` FROM `settingsmap`"); + $settingsmaps = $stmt->fetchAll(PDO::FETCH_ASSOC); + } + catch(PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + } + return $settingsmaps; + break; + case 'details': + if ($_SESSION['mailcow_cc_role'] != "admin" || !isset($_data)) { + return false; + } + $settingsmapdata = array(); + try { + $stmt = $pdo->prepare("SELECT `id`, + `desc`, + `content`, + `active` AS `active_int`, + CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active` + FROM `settingsmap` + WHERE `id` = :id"); + $stmt->execute(array(':id' => $_data)); + $settingsmapdata = $stmt->fetch(PDO::FETCH_ASSOC); + } + catch(PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + } + return $settingsmapdata; + break; + } +} \ No newline at end of file diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php index 20f12eb0..24f16793 100644 --- a/data/web/inc/init_db.inc.php +++ b/data/web/inc/init_db.inc.php @@ -3,7 +3,7 @@ function init_db_schema() { try { global $pdo; - $db_version = "06052018_1839"; + $db_version = "05062018_2039"; $stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); @@ -130,10 +130,15 @@ function init_db_schema() { ), "sender_acl" => array( "cols" => array( + "id" => "INT NOT NULL AUTO_INCREMENT", "logged_in_as" => "VARCHAR(255) NOT NULL", "send_as" => "VARCHAR(255) NOT NULL" ), - "keys" => array(), + "keys" => array( + "primary" => array( + "" => array("id") + ) + ), "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" ), "domain" => array( @@ -303,6 +308,8 @@ function init_db_schema() { "object" => "VARCHAR(255) NOT NULL DEFAULT ''", "option" => "VARCHAR(50) NOT NULL DEFAULT ''", "value" => "VARCHAR(100) NOT NULL DEFAULT ''", + "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)", + "modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP", "prefid" => "INT(11) NOT NULL AUTO_INCREMENT" ), "keys" => array( @@ -315,6 +322,22 @@ function init_db_schema() { ), "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" ), + "settingsmap" => array( + "cols" => array( + "id" => "INT NOT NULL AUTO_INCREMENT", + "desc" => "VARCHAR(255) NOT NULL", + "content" => "LONGTEXT NOT NULL", + "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)", + "modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP", + "active" => "TINYINT(1) NOT NULL DEFAULT '0'" + ), + "keys" => array( + "primary" => array( + "" => array("id") + ) + ), + "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" + ), "quota2" => array( "cols" => array( "username" => "VARCHAR(255) NOT NULL", @@ -330,12 +353,16 @@ function init_db_schema() { ), "domain_admins" => array( "cols" => array( + "id" => "INT NOT NULL AUTO_INCREMENT", "username" => "VARCHAR(255) NOT NULL", "domain" => "VARCHAR(255) NOT NULL", "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)", "active" => "TINYINT(1) NOT NULL DEFAULT '1'" ), "keys" => array( + "primary" => array( + "" => array("id") + ), "key" => array( "username" => array("username") ) @@ -454,12 +481,16 @@ function init_db_schema() { ), "sogo_acl" => array( "cols" => array( + "id" => "INT NOT NULL AUTO_INCREMENT", "c_folder_id" => "INT NOT NULL", "c_object" => "VARCHAR(255) NOT NULL", "c_uid" => "VARCHAR(255) NOT NULL", "c_role" => "VARCHAR(80) NOT NULL" ), "keys" => array( + "primary" => array( + "" => array("id") + ), "key" => array( "sogo_acl_c_folder_id_idx" => array("c_folder_id"), "sogo_acl_c_uid_idx" => array("c_uid") @@ -469,6 +500,7 @@ function init_db_schema() { ), "sogo_alarms_folder" => array( "cols" => array( + "id" => "INT NOT NULL AUTO_INCREMENT", "c_path" => "VARCHAR(255) NOT NULL", "c_name" => "VARCHAR(255) NOT NULL", "c_uid" => "VARCHAR(255) NOT NULL", @@ -476,7 +508,11 @@ function init_db_schema() { "c_alarm_number" => "INT(11) NOT NULL", "c_alarm_date" => "INT(11) NOT NULL" ), - "keys" => array(), + "keys" => array( + "primary" => array( + "" => array("id") + ) + ), "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" ), "sogo_cache_folder" => array( @@ -669,6 +705,9 @@ function init_db_schema() { $stmt = $pdo->query("SHOW COLUMNS FROM `" . $table . "` LIKE '" . $column . "'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); if ($num_results == 0) { + if (strpos($type, 'AUTO_INCREMENT') !== false) { + $type = $type . ' PRIMARY KEY '; + } $pdo->query("ALTER TABLE `" . $table . "` ADD `" . $column . "` " . $type); } else { diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php index f7041d07..ad201a68 100644 --- a/data/web/inc/prerequisites.inc.php +++ b/data/web/inc/prerequisites.inc.php @@ -88,6 +88,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.dkim.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fwdhost.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.relayhost.inc.php'; +require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.rsettings.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fail2ban.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.docker.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/init_db.inc.php'; diff --git a/data/web/js/admin.js b/data/web/js/admin.js index c0929538..389a24c4 100644 --- a/data/web/js/admin.js +++ b/data/web/js/admin.js @@ -9,6 +9,16 @@ jQuery(function($){ e.preventDefault(); $('#import_dkim_arrow').toggleClass("animation"); }); + $("#rspamd_preset_1").on('click', function(e) { + e.preventDefault(); + $("form[data-id=rsetting]").find("#desc").val(lang.rsettings_preset_1); + $("form[data-id=rsetting]").find("#content").val('priority = 10;\nauthenticated = yes;\napply "default" {\n symbols_enabled = ["DKIM_SIGNED", "DYN_RL_CHECK", "HISTORY_SAVE", "MILTER_HEADERS", "ARC_SIGNED"];\n}'); + }); + $("#rspamd_preset_2").on('click', function(e) { + e.preventDefault(); + $("form[data-id=rsetting]").find("#desc").val(lang.rsettings_preset_2); + $("form[data-id=rsetting]").find("#content").val('priority = 10;\nrcpt = "/postmaster@.*/";\nwant_spam = yes;'); + }); function draw_domain_admins() { ft_domainadmins = FooTable.init('#domainadminstable', { "columns": [ @@ -182,6 +192,9 @@ jQuery(function($){ $(window).load(function(){ initial_width = $("#sidebar-admin").width(); $("#scrollbox").css("width", initial_width); + if (sessionStorage.scrollTop > 70) { + $('#scrollbox').addClass('scrollboxFixed'); + } $(window).bind('scroll', function() { if ($(window).scrollTop() > 70) { $('#scrollbox').addClass('scrollboxFixed'); diff --git a/data/web/lang/lang.de.php b/data/web/lang/lang.de.php index efa3310b..6e92806f 100644 --- a/data/web/lang/lang.de.php +++ b/data/web/lang/lang.de.php @@ -373,6 +373,9 @@ $lang['tfa']['scan_qr_code'] = "Bitte scannen Sie jetzt den angezeigten QR-Code: $lang['tfa']['enter_qr_code'] = "Falls Sie den angezeigten QR-Code nicht scannen können, verwenden Sie bitte nachstehenden Sicherheitsschlüssel"; $lang['tfa']['confirm_totp_token'] = "Bitte bestätigen Sie die Änderung durch Eingabe eines generierten Tokens"; +$lang['admin']['rspamd-com_settings'] = 'Rspamd docs + - Ein Name wird automatisch generiert. Beispielinhalte zur Einsicht stehen nachstehend bereit.'; + $lang['admin']['no_new_rows'] = 'Keine weiteren Zeilen vorhanden'; $lang['admin']['additional_rows'] = ' zusätzliche Zeilen geladen'; // parses to 'n additional rows were added' $lang['admin']['private_key'] = 'Private Key'; @@ -404,6 +407,15 @@ $lang['admin']['active'] = 'Aktiv'; $lang['admin']['inactive'] = 'Inaktiv'; $lang['admin']['action'] = 'Aktion'; $lang['admin']['add_domain_admin'] = 'Domain-Administrator hinzufügen'; +$lang['admin']['add_settings_rule'] = 'Rspamd Setting hinzufügen'; +$lang['admin']['rsetting_desc'] = 'Kurze Beschreibung'; +$lang['admin']['rsetting_content'] = 'Regelinhalt'; +$lang['admin']['rsetting_none'] = 'Keine Regel hinterlegt'; +$lang['admin']['rsetting_no_selection'] = 'Bitte eine Regel auswählen'; +$lang['admin']['rsettings_preset_1'] = 'Alles außer DKIM and Ratelimits für authentifizierte Benutzer deaktivieren"'; +$lang['admin']['rsettings_preset_2'] = 'Spam an Postmaster-Addressen nicht blockieren'; +$lang['admin']['rsettings_insert_preset'] = 'Beispiel "%s" laden'; +$lang['admin']['rsetting_add_rule'] = 'Regel hinzufügen'; $lang['admin']['admin_domains'] = 'Domain-Zuweisungen'; $lang['admin']['domain_admins'] = 'Domain-Administratoren'; $lang['admin']['username'] = 'Benutzername'; @@ -440,8 +452,8 @@ $lang['admin']['activate_api'] = "API aktivieren"; $lang['admin']['regen_api_key'] = "API-Key regenerieren"; $lang['admin']['quarantine'] = "Quarantäne"; -$lang['admin']['quarantine_retention_size'] = "Rückhaltungen pro Mailbox:"; -$lang['admin']['quarantine_max_size'] = "Maximale Größe in MiB (größere Elemente werden verworfen):"; +$lang['admin']['quarantine_retention_size'] = "Rückhaltungen pro Mailbox
    0 bedeutet inaktiv!"; +$lang['admin']['quarantine_max_size'] = "Maximale Größe in MiB (größere Elemente werden verworfen)
    0 bedeutet nicht unlimitert!"; $lang['admin']['quarantine_exclude_domains'] = "Domains und Alias-Domains ausschließen:"; $lang['success']['forwarding_host_removed'] = "Weiterleitungs-Host %s wurde entfernt"; diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php index 01fbca00..bdc25143 100644 --- a/data/web/lang/lang.en.php +++ b/data/web/lang/lang.en.php @@ -376,6 +376,9 @@ $lang['tfa']['scan_qr_code'] = "Please scan the following code with your authent $lang['tfa']['enter_qr_code'] = "Your TOTP code if your device cannot scan QR codes"; $lang['tfa']['confirm_totp_token'] = "Please confirm your changes by entering the generated token"; +$lang['admin']['rspamd-com_settings'] = 'Rspamd docs + - A setting name will be auto-generated, please see the example presets below.'; + $lang['admin']['no_new_rows'] = 'No further rows available'; $lang['admin']['additional_rows'] = ' additional rows were added'; // parses to 'n additional rows were added' $lang['admin']['private_key'] = 'Private key'; @@ -410,6 +413,15 @@ $lang['admin']['active'] = 'Active'; $lang['admin']['inactive'] = 'Inactive'; $lang['admin']['action'] = 'Action'; $lang['admin']['add_domain_admin'] = 'Add domain administrator'; +$lang['admin']['add_settings_rule'] = 'Add settings rule'; +$lang['admin']['rsetting_desc'] = 'Short description'; +$lang['admin']['rsetting_content'] = 'Rule content'; +$lang['admin']['rsetting_none'] = 'No rule available'; +$lang['admin']['rsetting_no_selection'] = 'Please select a rule'; +$lang['admin']['rsettings_preset_1'] = 'Disable all but DKIM and ratelimit for authenticated users"'; +$lang['admin']['rsettings_preset_2'] = 'Postmasters want spam'; +$lang['admin']['rsettings_insert_preset'] = 'Insert example preset "%s"'; +$lang['admin']['rsetting_add_rule'] = 'Add rule'; $lang['admin']['admin_domains'] = 'Domain assignments'; $lang['admin']['domain_admins'] = 'Domain administrators'; $lang['admin']['username'] = 'Username'; @@ -461,8 +473,8 @@ $lang['admin']['activate_api'] = "Activate API"; $lang['admin']['regen_api_key'] = "Regenerate API key"; $lang['admin']['quarantine'] = "Quarantine"; -$lang['admin']['quarantine_retention_size'] = "Retentions per mailbox:"; -$lang['admin']['quarantine_max_size'] = "Maximum size in MiB (larger elements are discarded):"; +$lang['admin']['quarantine_retention_size'] = "Retentions per mailbox
    0 indicates inactive!"; +$lang['admin']['quarantine_max_size'] = "Maximum size in MiB (larger elements are discarded)
    0 does not indicate unlimited!"; $lang['admin']['quarantine_exclude_domains'] = "Exclude domains and alias-domains:"; $lang['admin']['ui_texts'] = "UI labels and texts"; diff --git a/data/web/modals/admin.php b/data/web/modals/admin.php index 3a387540..1306b436 100644 --- a/data/web/modals/admin.php +++ b/data/web/modals/admin.php @@ -4,6 +4,49 @@ if (!isset($_SESSION['mailcow_cc_role'])) { exit(); } ?> + +