From 7f86a8067039b63e6afa7bb1724eadad9493d112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 3 Aug 2018 20:31:33 +0200 Subject: [PATCH] [Web] Fix log line handling [Web] Add mailcow UI logs [Web] Changes to _SESSION['return'] logic and logger (more to come) [Web] Show last login [Web, Postfix] Allow to disable sender check completely [Web] Many minor fixes [Web] Update some libs --- data/web/autodiscover.php | 28 +- data/web/css/debug.css | 4 + data/web/css/mailbox.css | 2 +- data/web/css/mailcow.css | 10 +- data/web/debug.php | 25 +- data/web/edit.php | 3 +- data/web/inc/ajax/log_driver.php | 12 - data/web/inc/footer.inc.php | 20 +- .../inc/functions.address_rewriting.inc.php | 113 ++- .../inc/functions.autoconfiguration.inc.php | 22 +- data/web/inc/functions.customize.inc.php | 57 +- data/web/inc/functions.dkim.inc.php | 74 +- data/web/inc/functions.docker.inc.php | 41 + data/web/inc/functions.domain_admin.inc.php | 112 ++- data/web/inc/functions.fail2ban.inc.php | 19 +- data/web/inc/functions.fwdhost.inc.php | 38 +- data/web/inc/functions.inc.php | 530 ++++++++--- data/web/inc/functions.mailbox.inc.php | 849 ++++++++++++------ data/web/inc/functions.policy.inc.php | 91 +- data/web/inc/functions.quarantine.inc.php | 63 +- data/web/inc/functions.relayhost.inc.php | 40 +- data/web/inc/functions.rsettings.inc.php | 40 +- data/web/inc/header.inc.php | 2 +- data/web/inc/init_db.inc.php | 26 +- data/web/inc/lib/composer.lock | 22 +- .../inc/lib/vendor/composer/installed.json | 24 +- .../php-mime-mail-parser/README.md | 4 +- .../src/Contracts/Middleware.php | 23 + .../php-mime-mail-parser/src/Middleware.php | 27 + .../src/MiddlewareStack.php | 89 ++ .../php-mime-mail-parser/src/MimePart.php | 115 +++ .../php-mime-mail-parser/src/Parser.php | 88 +- .../vendor/robthree/twofactorauth/.travis.yml | 13 +- .../vendor/robthree/twofactorauth/README.md | 26 +- .../twofactorauth/TwoFactorAuth.phpproj | 3 +- .../robthree/twofactorauth/composer.json | 2 +- .../lib/Providers/Rng/HashRNGProvider.php | 2 +- .../lib/Providers/Rng/MCryptRNGProvider.php | 2 +- .../ConvertUnixTimeDotComTimeProvider.php | 15 - .../lib/Providers/Time/NTPTimeProvider.php | 52 ++ .../twofactorauth/lib/TwoFactorAuth.php | 21 +- .../vendor/robthree/twofactorauth/phpunit.xml | 20 + .../twofactorauth/phpunit.xml.tmppica | 0 .../twofactorauth/tests/TwoFactorAuthTest.php | 40 +- data/web/inc/sessions.inc.php | 24 +- data/web/inc/triggers.inc.php | 7 +- data/web/inc/vars.inc.php | 2 + data/web/js/admin.js | 1 + data/web/js/debug.js | 49 +- data/web/js/edit.js | 21 + data/web/js/mailbox.js | 2 +- data/web/js/user.js | 2 + data/web/json_api.php | 25 +- data/web/lang/lang.de.php | 58 +- data/web/lang/lang.en.php | 65 +- data/web/user.php | 18 + 56 files changed, 2299 insertions(+), 784 deletions(-) delete mode 100644 data/web/inc/ajax/log_driver.php create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Contracts/Middleware.php create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Middleware.php create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/MiddlewareStack.php create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/MimePart.php delete mode 100644 data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php create mode 100644 data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php create mode 100644 data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml create mode 100644 data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml.tmppica diff --git a/data/web/autodiscover.php b/data/web/autodiscover.php index 557c887c..391b4a93 100644 --- a/data/web/autodiscover.php +++ b/data/web/autodiscover.php @@ -38,25 +38,15 @@ $login_user = strtolower(trim($_SERVER['PHP_AUTH_USER'])); $login_pass = trim(htmlspecialchars_decode($_SERVER['PHP_AUTH_PW'])); if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW'])) { - try { - $json = json_encode( - array( - "time" => time(), - "ua" => $_SERVER['HTTP_USER_AGENT'], - "user" => "none", - "service" => "Error: must be authenticated" - ) - ); - $redis->lPush('AUTODISCOVER_LOG', $json); - $redis->lTrim('AUTODISCOVER_LOG', 0, 100); - } - catch (RedisException $e) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'Redis: '.$e - ); - return false; - } + $json = json_encode( + array( + "time" => time(), + "ua" => $_SERVER['HTTP_USER_AGENT'], + "user" => "none", + "service" => "Error: must be authenticated" + ) + ); + $redis->lPush('AUTODISCOVER_LOG', $json); header('WWW-Authenticate: Basic realm="' . $_SERVER['HTTP_HOST'] . '"'); header('HTTP/1.0 401 Unauthorized'); exit(0); diff --git a/data/web/css/debug.css b/data/web/css/debug.css index 9aa53256..b127d5da 100644 --- a/data/web/css/debug.css +++ b/data/web/css/debug.css @@ -37,4 +37,8 @@ table.footable>tbody>tr.footable-empty>td { } .table-lines { vertical-align: inherit; +} +tbody { + font-size:14px; + color:#333; } \ No newline at end of file diff --git a/data/web/css/mailbox.css b/data/web/css/mailbox.css index 8a9c46d5..da2e96e3 100644 --- a/data/web/css/mailbox.css +++ b/data/web/css/mailbox.css @@ -44,4 +44,4 @@ table.footable>tbody>tr.footable-empty>td { #logText { font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace; font-size:smaller; -} \ No newline at end of file +} diff --git a/data/web/css/mailcow.css b/data/web/css/mailcow.css index 14d875fa..56d129dd 100644 --- a/data/web/css/mailcow.css +++ b/data/web/css/mailcow.css @@ -138,4 +138,12 @@ nav .glyphicon { } .bootstrap-select.btn-group .no-results { display: none; -} \ No newline at end of file +} +.dropdown-desc { + display: block; + padding: 3px 10px; + clear: both; + font-weight: bold; + color: #5a5a5a; + white-space: nowrap; +} diff --git a/data/web/debug.php b/data/web/debug.php index cd7a9756..646aaa19 100644 --- a/data/web/debug.php +++ b/data/web/debug.php @@ -13,15 +13,19 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI']; @@ -29,7 +33,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
- +
'df', 'dir' => '/var/vmail'); $vmail_df = explode(',', json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true)); @@ -114,6 +118,23 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
+
+
+
mailcow UI +
+ + + +
+
+
+
+
+
+
+
+
+
Dovecot diff --git a/data/web/edit.php b/data/web/edit.php index d32e6ea4..d605d3f4 100644 --- a/data/web/edit.php +++ b/data/web/edit.php @@ -394,7 +394,7 @@ if (isset($_SESSION['mailcow_cc_role'])) { ?>

- +
@@ -462,6 +462,7 @@ if (isset($_SESSION['mailcow_cc_role'])) { ?> +
diff --git a/data/web/inc/ajax/log_driver.php b/data/web/inc/ajax/log_driver.php deleted file mode 100644 index 319f672d..00000000 --- a/data/web/inc/ajax/log_driver.php +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/data/web/inc/footer.inc.php b/data/web/inc/footer.inc.php index b14553b4..d7b80723 100644 --- a/data/web/inc/footer.inc.php +++ b/data/web/inc/footer.inc.php @@ -1,5 +1,6 @@
@@ -23,7 +24,7 @@ function setLang(sel) { $.post( "", {lang: sel} ); window.location.href = window.location.pathname + window.location.search; } -$(window).on('load', function() { +$(window).load(function() { $(".overlay").hide(); }); $(document).ready(function() { @@ -36,17 +37,18 @@ $(document).ready(function() { } else { auto_hide = 5000; } - $.ajax({ - url: '/inc/ajax/log_driver.php', - data: {"type": type,"msg": msg}, - type: "GET" - }); $.notify({message: msg},{z_index: 20000, delay: auto_hide, type: type,placement: {from: "bottom",align: "right"},animate: {enter: 'animated fadeInUp',exit: 'animated fadeOutDown'}}); } + + mailcow_alert_box(, ); + $('[data-cached-form="true"]').formcache({key: $(this).data('id')}); - - mailcow_alert_box(, ""); - // Confirm TFA modal $('#ConfirmTFAModal').modal({ diff --git a/data/web/inc/functions.address_rewriting.inc.php b/data/web/inc/functions.address_rewriting.inc.php index 4f7f624b..ce10d676 100644 --- a/data/web/inc/functions.address_rewriting.inc.php +++ b/data/web/inc/functions.address_rewriting.inc.php @@ -10,7 +10,8 @@ function bcc($_action, $_data = null, $attr = null) { if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -21,14 +22,16 @@ function bcc($_action, $_data = null, $attr = null) { if ($type != 'sender' && $type != 'rcpt') { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Invalid BCC map type' + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'invalid_bcc_map_type' ); return false; } if (empty($bcc_dest)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'BCC destination cannot be empty' + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'bcc_empty' ); return false; } @@ -36,7 +39,8 @@ function bcc($_action, $_data = null, $attr = null) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -47,7 +51,8 @@ function bcc($_action, $_data = null, $attr = null) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -63,7 +68,8 @@ function bcc($_action, $_data = null, $attr = null) { if (!filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'BCC map must be a valid email address' + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'bcc_must_be_email' ); return false; } @@ -76,14 +82,16 @@ function bcc($_action, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'A BCC map entry "' . htmlspecialchars($local_dest_sane) . '" exists for type "' . $type . '"' + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('bcc_exists', htmlspecialchars($local_dest_sane), $type) ); return false; } @@ -101,20 +109,23 @@ function bcc($_action, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => 'BCC map entry saved' + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'bcc_saved' ); break; case 'edit': if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -130,7 +141,8 @@ function bcc($_action, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -138,14 +150,16 @@ function bcc($_action, $_data = null, $attr = null) { if (!filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'BCC map must be a valid email address' + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'bcc_must_be_email' ); return false; } if (empty($bcc_dest)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'BCC map destination cannot be empty' + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'bcc_empty' ); return false; } @@ -158,14 +172,16 @@ function bcc($_action, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if (isset($id_now) && $id_now != $id) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'A BCC map entry ' . htmlspecialchars($local_dest) . ' exists for this type' + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('bcc_exists', htmlspecialchars($local_dest), $type) ); return false; } @@ -181,14 +197,16 @@ function bcc($_action, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => 'BCC map entry edited' + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'bcc_edited' ); break; case 'details': @@ -211,7 +229,8 @@ function bcc($_action, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -232,7 +251,8 @@ function bcc($_action, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -257,7 +277,8 @@ function bcc($_action, $_data = null, $attr = null) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -267,14 +288,16 @@ function bcc($_action, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => 'Deleted BCC map id/s ' . implode(', ', $ids) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('bcc_deleted', implode(', ', $ids)) ); return true; break; @@ -304,14 +327,16 @@ function recipient_map($_action, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['invalid_recipient_map_old'], htmlspecialchars($old_dest)) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('invalid_recipient_map_old', htmlspecialchars($old_dest)) ); return false; } if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['invalid_recipient_map_new'], htmlspecialchars($new_dest)) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('invalid_recipient_map_new', htmlspecialchars($new_dest)) ); return false; } @@ -322,7 +347,8 @@ function recipient_map($_action, $_data = null, $attr = null) { if (in_array($old_dest_sane, $old_dests_existing)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['recipient_map_entry_exists'], htmlspecialchars($old_dest)) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest)) ); return false; } @@ -338,13 +364,15 @@ function recipient_map($_action, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['recipient_map_entry_saved'], htmlspecialchars($old_dest_sane)) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('recipient_map_entry_saved', htmlspecialchars($old_dest_sane)) ); break; case 'edit': @@ -362,7 +390,8 @@ function recipient_map($_action, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -375,7 +404,8 @@ function recipient_map($_action, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['invalid_recipient_map_old'], htmlspecialchars($old_dest)) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('invalid_recipient_map_old', htmlspecialchars($old_dest)) ); return false; } @@ -383,7 +413,8 @@ function recipient_map($_action, $_data = null, $attr = null) { if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['invalid_recipient_map_new'], htmlspecialchars($new_dest)) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('invalid_recipient_map_new', htmlspecialchars($new_dest)) ); return false; } @@ -395,7 +426,8 @@ function recipient_map($_action, $_data = null, $attr = null) { recipient_map('details', $id)['recipient_map_old'] != $old_dest_sane) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['recipient_map_entry_exists'], htmlspecialchars($old_dest_sane)) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest_sane)) ); return false; } @@ -415,14 +447,16 @@ function recipient_map($_action, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['recipient_map_entry_saved'], htmlspecialchars($old_dest)) + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('recipient_map_entry_saved', htmlspecialchars($old_dest)) ); break; case 'details': @@ -443,7 +477,8 @@ function recipient_map($_action, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -460,7 +495,8 @@ function recipient_map($_action, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -483,14 +519,15 @@ function recipient_map($_action, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['recipient_map_entry_deleted'], htmlspecialchars($old_dest)) + 'msg' => array('recipient_map_entry_deleted', htmlspecialchars($old_dest)) ); return true; break; diff --git a/data/web/inc/functions.autoconfiguration.inc.php b/data/web/inc/functions.autoconfiguration.inc.php index 772475c7..bd3dd10b 100644 --- a/data/web/inc/functions.autoconfiguration.inc.php +++ b/data/web/inc/functions.autoconfiguration.inc.php @@ -6,8 +6,9 @@ function autoconfiguration($_action, $_type, $_data = null) { case 'edit': if (!isset($_SESSION['acl']['eas_autoconfig']) || $_SESSION['acl']['eas_autoconfig'] != "1" ) { $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data), + 'msg' => 'access_denied' ); return false; } @@ -31,7 +32,8 @@ function autoconfiguration($_action, $_type, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data), + 'msg' => array('mysql_error', $e) ); return false; } @@ -42,7 +44,8 @@ function autoconfiguration($_action, $_type, $_data = null) { } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_modified'], htmlspecialchars(implode(', ', $objects))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data), + 'msg' => array('domain_modified', htmlspecialchars(implode(', ', $objects))) ); break; } @@ -69,7 +72,8 @@ function autoconfiguration($_action, $_type, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data), + 'msg' => array('mysql_error', $e) ); return false; } @@ -92,7 +96,8 @@ function autoconfiguration($_action, $_type, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data), + 'msg' => array('mysql_error', $e) ); return false; } @@ -112,8 +117,3 @@ function autoconfiguration($_action, $_type, $_data = null) { break; } } -$miau = "Microsoft Office/15.0 (Windows NT 5.1; macOS Outlook 16.0.4734; Pro)"; -preg_match("/^((?!.*Mac|.*emClient).)*(Outlook|Office).+1[5-9].*/i", $miau, $output_array); -if (empty($output_array)) { - echo "imap"; -} \ No newline at end of file diff --git a/data/web/inc/functions.customize.inc.php b/data/web/inc/functions.customize.inc.php index a6999f39..8fb928fa 100644 --- a/data/web/inc/functions.customize.inc.php +++ b/data/web/inc/functions.customize.inc.php @@ -7,7 +7,8 @@ function customize($_action, $_item, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'access_denied' ); return false; } @@ -18,7 +19,8 @@ function customize($_action, $_item, $_data = null) { if (file_exists($_data['main_logo']['tmp_name']) !== true) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => $lang['danger']['img_tmp_missing'] + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'img_tmp_missing' ); return false; } @@ -26,7 +28,8 @@ function customize($_action, $_item, $_data = null) { if ($image->valid() !== true) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => $lang['danger']['img_invalid'] + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'img_invalid' ); return false; } @@ -35,7 +38,8 @@ function customize($_action, $_item, $_data = null) { catch (ImagickException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => $lang['danger']['img_invalid'] + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'img_invalid' ); return false; } @@ -43,7 +47,8 @@ function customize($_action, $_item, $_data = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => $lang['danger']['invalid_mime_type'] + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'invalid_mime_type' ); return false; } @@ -53,13 +58,15 @@ function customize($_action, $_item, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => array('redis_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => $lang['success']['upload_success'] + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'upload_success' ); break; } @@ -68,7 +75,8 @@ function customize($_action, $_item, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'access_denied' ); return false; } @@ -87,14 +95,16 @@ function customize($_action, $_item, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => array('redis_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => $lang['success']['app_links'] + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'app_links' ); break; case 'ui_texts': @@ -111,13 +121,15 @@ function customize($_action, $_item, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => array('redis_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => $lang['success']['ui_texts'] + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'ui_texts' ); break; } @@ -126,7 +138,8 @@ function customize($_action, $_item, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'access_denied' ); return false; } @@ -136,7 +149,8 @@ function customize($_action, $_item, $_data = null) { if ($redis->del('MAIN_LOGO')) { $_SESSION['return'] = array( 'type' => 'success', - 'msg' => $lang['success']['reset_main_logo'] + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'reset_main_logo' ); return true; } @@ -144,7 +158,8 @@ function customize($_action, $_item, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => array('redis_error', $e) ); return false; } @@ -160,7 +175,8 @@ function customize($_action, $_item, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => array('redis_error', $e) ); return false; } @@ -173,7 +189,8 @@ function customize($_action, $_item, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => array('redis_error', $e) ); return false; } @@ -189,7 +206,8 @@ function customize($_action, $_item, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => array('redis_error', $e) ); return false; } @@ -206,7 +224,8 @@ function customize($_action, $_item, $_data = null) { catch (ImagickException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => $lang['danger']['imagick_exception'] + 'log' => array(__FUNCTION__, $_action, $_item, $_data), + 'msg' => 'imagick_exception' ); return false; } diff --git a/data/web/inc/functions.dkim.inc.php b/data/web/inc/functions.dkim.inc.php index c1730157..8099d2f8 100644 --- a/data/web/inc/functions.dkim.inc.php +++ b/data/web/inc/functions.dkim.inc.php @@ -8,7 +8,8 @@ function dkim($_action, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'access_denied' ); return false; } @@ -18,21 +19,24 @@ function dkim($_action, $_data = null) { if (!is_valid_domain_name($domain) || !is_numeric($key_length)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'dkim_domain_or_sel_invalid' ); return false; } if ($redis->hGet('DKIM_PUB_KEYS', $domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'dkim_domain_or_sel_invalid' ); return false; } if (!ctype_alnum($dkim_selector)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'dkim_domain_or_sel_invalid' ); return false; } @@ -56,7 +60,8 @@ function dkim($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => array('redis_error', $e) ); return false; } @@ -69,21 +74,24 @@ function dkim($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => array('redis_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['dkim_added']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'dkim_added' ); return true; } else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'dkim_domain_or_sel_invalid' ); return false; } @@ -92,7 +100,8 @@ function dkim($_action, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'access_denied' ); return false; } @@ -102,7 +111,8 @@ function dkim($_action, $_data = null) { if ($ssl_error = openssl_error_string()) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Private key error: ' . $ssl_error + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => array('private_key_error', $ssl_error) ); return false; } @@ -118,21 +128,24 @@ function dkim($_action, $_data = null) { if (!is_valid_domain_name($domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'dkim_domain_or_sel_invalid' ); return false; } if ($redis->hGet('DKIM_PUB_KEYS', $domain)) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid']) - ); - return false; + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'dkim_domain_or_sel_invalid' + ); + return false; } if (!ctype_alnum($dkim_selector)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'dkim_domain_or_sel_invalid' ); return false; } @@ -144,7 +157,8 @@ function dkim($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => array('redis_error', $e) ); return false; } @@ -156,13 +170,15 @@ function dkim($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => array('redis_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['dkim_added']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'dkim_added' ); return true; break; @@ -194,12 +210,16 @@ function dkim($_action, $_data = null) { else { $dkimdata['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.'); } - } return $dkimdata; break; case 'blind': if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'access_denied' + ); return false; } $blinddkim = array(); @@ -213,7 +233,8 @@ function dkim($_action, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'access_denied' ); return false; } @@ -221,7 +242,8 @@ function dkim($_action, $_data = null) { if (!is_valid_domain_name($domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => 'dkim_domain_or_sel_invalid' ); return false; } @@ -234,14 +256,16 @@ function dkim($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => array('redis_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['dkim_removed'], htmlspecialchars(implode(', ', $domains))) + 'log' => array(__FUNCTION__, $_action, $_data), + 'msg' => array('dkim_removed', htmlspecialchars(implode(', ', $domains))) ); break; } diff --git a/data/web/inc/functions.docker.inc.php b/data/web/inc/functions.docker.inc.php index e7a0a4f4..cac2db78 100644 --- a/data/web/inc/functions.docker.inc.php +++ b/data/web/inc/functions.docker.inc.php @@ -13,10 +13,19 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex if ($response === false) { $err = curl_error($curl); curl_close($curl); + // logger(array('return' => array( + // 'type' => 'danger', + // 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), + // 'msg' => $err, + // ))); return $err; } else { curl_close($curl); + // logger(array('return' => array( + // 'type' => 'success', + // 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), + // ))); $containers = json_decode($response, true); if (!empty($containers)) { foreach ($containers as $container) { @@ -37,10 +46,19 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex if ($response === false) { $err = curl_error($curl); curl_close($curl); + // logger(array('return' => array( + // 'type' => 'danger', + // 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), + // 'msg' => $err, + // ))); return $err; } else { curl_close($curl); + // logger(array('return' => array( + // 'type' => 'success', + // 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), + // ))); $containers = json_decode($response, true); if (!empty($containers)) { foreach ($containers as $container) { @@ -67,6 +85,11 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/' . $container_id . '/json'); } else { + // logger(array('return' => array( + // 'type' => 'danger', + // 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), + // 'msg' => 'invalid_container_id' + // ))); return false; } } @@ -77,10 +100,19 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex if ($response === false) { $err = curl_error($curl); curl_close($curl); + // logger(array('return' => array( + // 'type' => 'danger', + // 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), + // 'msg' => $err, + // ))); return $err; } else { curl_close($curl); + // logger(array('return' => array( + // 'type' => 'success', + // 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), + // ))); $decoded_response = json_decode($response, true); if (!empty($decoded_response)) { if (empty($service_name)) { @@ -126,10 +158,19 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex if ($response === false) { $err = curl_error($curl); curl_close($curl); + logger(array('return' => array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), + 'msg' => $err, + ))); return $err; } else { curl_close($curl); + logger(array('return' => array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers), + ))); if (empty($response)) { return true; } diff --git a/data/web/inc/functions.domain_admin.inc.php b/data/web/inc/functions.domain_admin.inc.php index 5da8b25b..3c631d08 100644 --- a/data/web/inc/functions.domain_admin.inc.php +++ b/data/web/inc/functions.domain_admin.inc.php @@ -3,6 +3,9 @@ function domain_admin($_action, $_data = null) { global $pdo; global $lang; + $_data_log = $_data; + !isset($_data_log['password']) ?: $_data_log['password'] = '*'; + !isset($_data_log['password2']) ?: $_data_log['password2'] = '*'; switch ($_action) { case 'add': $username = strtolower(trim($_data['username'])); @@ -10,25 +13,27 @@ function domain_admin($_action, $_data = null) { $password2 = $_data['password2']; $domains = (array)$_data['domains']; $active = intval($_data['active']); - if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } if (empty($domains)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'domain_invalid' ); return false; } if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username)) || empty ($username)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['username_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'username_invalid' ); return false; } @@ -51,7 +56,8 @@ function domain_admin($_action, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -59,7 +65,8 @@ function domain_admin($_action, $_data = null) { if ($num_results_each != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['object_exists'], htmlspecialchars($username)) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('object_exists', htmlspecialchars($username)) ); return false; } @@ -68,14 +75,16 @@ function domain_admin($_action, $_data = null) { if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_complexity']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'password_complexity' ); return false; } if ($password != $password2) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_mismatch']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'password_mismatch' ); return false; } @@ -84,7 +93,8 @@ function domain_admin($_action, $_data = null) { if (!is_valid_domain_name($domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'domain_invalid' ); return false; } @@ -102,7 +112,8 @@ function domain_admin($_action, $_data = null) { domain_admin('delete', $username); $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -119,7 +130,8 @@ function domain_admin($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -127,20 +139,23 @@ function domain_admin($_action, $_data = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_empty']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'password_empty' ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_admin_added'], htmlspecialchars($username)) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('domain_admin_added', htmlspecialchars($username)) ); break; case 'edit': if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -164,7 +179,8 @@ function domain_admin($_action, $_data = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -176,7 +192,8 @@ function domain_admin($_action, $_data = null) { if (!is_valid_domain_name($domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'domain_invalid' ); return false; } @@ -185,7 +202,8 @@ function domain_admin($_action, $_data = null) { if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username_new))) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['username_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'username_invalid' ); return false; } @@ -193,7 +211,8 @@ function domain_admin($_action, $_data = null) { if (!empty(domain_admin('details', $username_new)['username'])) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['username_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'username_invalid' ); return false; } @@ -207,7 +226,8 @@ function domain_admin($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -227,7 +247,8 @@ function domain_admin($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -238,14 +259,16 @@ function domain_admin($_action, $_data = null) { if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_complexity']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'password_complexity' ); return false; } if ($password != $password2) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_mismatch']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'password_mismatch' ); return false; } @@ -270,7 +293,8 @@ function domain_admin($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -295,7 +319,8 @@ function domain_admin($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -303,7 +328,8 @@ function domain_admin($_action, $_data = null) { } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_admin_modified'], htmlspecialchars(implode(', ', $usernames))) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('domain_admin_modified', htmlspecialchars(implode(', ', $usernames))) ); } // Domain administrator @@ -321,7 +347,8 @@ function domain_admin($_action, $_data = null) { if (!verify_hash($row['password'], $password_old)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -330,14 +357,16 @@ function domain_admin($_action, $_data = null) { if ($password_new2 != $password_new) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_mismatch']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'password_mismatch' ); return false; } if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password_new)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_complexity']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'password_complexity' ); return false; } @@ -352,7 +381,8 @@ function domain_admin($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -360,7 +390,8 @@ function domain_admin($_action, $_data = null) { $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_admin_modified'], htmlspecialchars($username)) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('domain_admin_modified', htmlspecialchars($username)) ); } break; @@ -368,7 +399,8 @@ function domain_admin($_action, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -377,7 +409,8 @@ function domain_admin($_action, $_data = null) { if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username))) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['username_invalid']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'username_invalid' ); return false; } @@ -394,14 +427,16 @@ function domain_admin($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_admin_removed'], htmlspecialchars(implode(', ', $usernames))) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('domain_admin_removed', htmlspecialchars(implode(', ', $usernames))) ); break; case 'get': @@ -409,7 +444,8 @@ function domain_admin($_action, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -429,7 +465,8 @@ function domain_admin($_action, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); } return $domainadmins; @@ -498,7 +535,8 @@ function domain_admin($_action, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); } return $domainadmindata; diff --git a/data/web/inc/functions.fail2ban.inc.php b/data/web/inc/functions.fail2ban.inc.php index cf6c6252..668e41cb 100644 --- a/data/web/inc/functions.fail2ban.inc.php +++ b/data/web/inc/functions.fail2ban.inc.php @@ -12,6 +12,7 @@ function valid_network($network) { function fail2ban($_action, $_data = null) { global $redis; global $lang; + $_data_log = $_data; switch ($_action) { case 'get': $f2b_options = array(); @@ -81,7 +82,8 @@ function fail2ban($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('redis_error', $e) ); return false; } @@ -91,7 +93,8 @@ function fail2ban($_action, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -118,7 +121,8 @@ function fail2ban($_action, $_data = null) { } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars(implode(', ', $networks))) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('object_modified', htmlspecialchars(implode(', ', $networks))) ); return true; } @@ -135,7 +139,8 @@ function fail2ban($_action, $_data = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -175,13 +180,15 @@ function fail2ban($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('redis_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['f2b_modified']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'f2b_modified' ); break; } diff --git a/data/web/inc/functions.fwdhost.inc.php b/data/web/inc/functions.fwdhost.inc.php index 6f3e8022..f16834ea 100644 --- a/data/web/inc/functions.fwdhost.inc.php +++ b/data/web/inc/functions.fwdhost.inc.php @@ -1,16 +1,17 @@ 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -29,7 +30,8 @@ function fwdhost($_action, $_data = null) { if (empty($hosts)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Invalid host specified: '. htmlspecialchars($host) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('invalid_host', htmlspecialchars($host)) ); return false; } @@ -46,14 +48,16 @@ function fwdhost($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('redis_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['forwarding_host_added'], htmlspecialchars(implode(', ', $hosts))) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('forwarding_host_added', htmlspecialchars(implode(', ', $hosts))) ); break; case 'edit': @@ -61,7 +65,8 @@ function fwdhost($_action, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -74,7 +79,8 @@ function fwdhost($_action, $_data = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -89,14 +95,16 @@ function fwdhost($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('redis_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars(implode(', ', $fwdhosts))) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('object_modified', htmlspecialchars(implode(', ', $fwdhosts))) ); break; case 'delete': @@ -109,14 +117,16 @@ function fwdhost($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('redis_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['forwarding_host_removed'], htmlspecialchars(implode(', ', $hosts))) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('forwarding_host_removed', htmlspecialchars(implode(', ', $hosts))) ); break; case 'get': @@ -140,7 +150,8 @@ function fwdhost($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('redis_error', $e) ); return false; } @@ -161,7 +172,8 @@ function fwdhost($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('redis_error', $e) ); return false; } diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 74af5062..3ca51b45 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -3,6 +3,109 @@ function hash_password($password) { $salt_str = bin2hex(openssl_random_pseudo_bytes(8)); return "{SSHA256}".base64_encode(hash('sha256', $password . $salt_str, true) . $salt_str); } +function get_remote_ip($anonymize = null) { + global $ANONYMIZE_IPS; + if ($anonymize === null) { + $anonymize = $ANONYMIZE_IPS; + } + elseif ($anonymize !== true && $anonymize !== false) { + $anonymize = true; + } + $remote = ''; + if ($_SERVER['HTTP_CLIENT_IP']) { + $remote = $_SERVER['HTTP_CLIENT_IP']; + } + elseif ($_SERVER['HTTP_X_FORWARDED_FOR']) { + $remote = $_SERVER['HTTP_X_FORWARDED_FOR']; + } + elseif ($_SERVER['HTTP_X_FORWARDED']) { + $remote = $_SERVER['HTTP_X_FORWARDED']; + } + elseif ($_SERVER['HTTP_FORWARDED_FOR']) { + $remote = $_SERVER['HTTP_FORWARDED_FOR']; + } + elseif ($_SERVER['HTTP_FORWARDED']) { + $remote = $_SERVER['HTTP_FORWARDED']; + } + elseif ($_SERVER['REMOTE_ADDR']) { + $remote = $_SERVER['REMOTE_ADDR']; + } + if (filter_var($remote, FILTER_VALIDATE_IP) === false) { + return '0.0.0.0'; + } + if ($anonymize) { + if (strlen(inet_pton($remote)) == 4) { + return inet_ntop(inet_pton($remote) & inet_pton("255.255.255.0")); + } + elseif (strlen(inet_pton($remote)) == 16) { + return inet_ntop(inet_pton($remote) & inet_pton('ffff:ffff:ffff:ffff:0000:0000:0000:0000')); + } + } + else { + return $remote; + } +} +function last_login($user) { + global $pdo; + try { + $stmt = $pdo->prepare('SELECT `remote`, `time` FROM `logs` + WHERE JSON_EXTRACT(`call`, "$[0]") = "check_login" + AND JSON_EXTRACT(`call`, "$[1]") = :user + AND `type` = "success" ORDER BY `time` DESC LIMIT 1'); + $stmt->execute(array(':user' => $user)); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (!empty($row)) { + return $row; + } + else { + return false; + } + } + catch(PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $username, $role, $domain), + 'msg' => array('mysql_error', $e) + ); + return false; + } +} +function logger($_data = false) { + global $pdo; + if (!$_data) { + $_data = $_SESSION; + } + if (!empty($_data['return'])) { + $type = $_data['return']['type']; + $msg = json_encode($_data['return']['msg'], JSON_UNESCAPED_UNICODE); + $call = json_encode($_data['return']['log'], JSON_UNESCAPED_UNICODE); + if (!empty($_SESSION["dual-login"]["username"])) { + $user = $_SESSION["dual-login"]["username"] . ' => ' . $_SESSION['mailcow_cc_username']; + $role = $_SESSION["dual-login"]["role"] . ' => ' . $_SESSION['mailcow_cc_role']; + } + elseif (!empty($_SESSION['mailcow_cc_username'])) { + $user = $_SESSION['mailcow_cc_username']; + $role = $_SESSION['mailcow_cc_role']; + } + else { + $user = 'unauthenticated'; + $role = 'unauthenticated'; + } + } + else { + return true; + } + $stmt = $pdo->prepare("INSERT INTO `logs` (`type`, `msg`, `call`, `user`, `role`, `remote`, `time`) VALUES + (:type, :msg, :call, :user, :role, :remote, UNIX_TIMESTAMP())"); + $stmt->execute(array( + ':type' => $type, + ':call' => $call, + ':msg' => $msg, + ':user' => $user, + ':role' => $role, + ':remote' => get_remote_ip() + )); +} function hasDomainAccess($username, $role, $domain) { global $pdo; if (!filter_var($username, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $username))) { @@ -28,7 +131,8 @@ function hasDomainAccess($username, $role, $domain) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $username, $role, $domain), + 'msg' => array('mysql_error', $e) ); return false; } @@ -128,7 +232,31 @@ function generate_tlsa_digest($hostname, $port, $starttls = null) { return 'Error: Cannot read peer certificate'; } } -//function verify_hash($hash, $password) { +function alertbox_log_parser($_data){ + global $lang; + if (isset($_data['return'])) { + // Get type + $type = $_data['return']['type']; + // If a lang[type][msg] string exists, use it as message + if (is_string($lang[$_data['return']['type']][$_data['return']['msg']])) { + $msg = $lang[$_data['return']['type']][$_data['return']['msg']]; + } + // If msg is an array, use first element as language string and run printf on it with remaining array elements + elseif (is_array($_data['return']['msg'])) { + $msg = array_shift($_data['return']['msg']); + $msg = vsprintf( + $lang[$_data['return']['type']][$msg], + $_data['return']['msg'] + ); + } + // If none applies, use msg as returned message + else { + $msg = $_data['return']['msg']; + } + return array('msg' => json_encode($msg), 'type' => json_encode($type)); + } + return false; +} function verify_hash($hash, $password) { if (preg_match('/^{SSHA256}/i', $hash)) { // Remove tag if any @@ -174,6 +302,11 @@ function check_login($user, $pass) { global $pdo; global $redis; if (!filter_var($user, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $user))) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $user, '*'), + 'msg' => 'malformed_username' + ); return false; } $user = strtolower(trim($user)); @@ -189,10 +322,20 @@ function check_login($user, $pass) { $_SESSION['pending_mailcow_cc_role'] = "admin"; $_SESSION['pending_tfa_method'] = get_tfa($user)['name']; unset($_SESSION['ldelay']); + $_SESSION['return'] = array( + 'type' => 'info', + 'log' => array(__FUNCTION__, $user, '*'), + 'msg' => 'awaiting_tfa_confirmation' + ); return "pending"; } else { unset($_SESSION['ldelay']); + $_SESSION['return'] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $user, '*'), + 'msg' => array('logged_in_as', $user) + ); return "admin"; } } @@ -210,12 +353,23 @@ function check_login($user, $pass) { $_SESSION['pending_mailcow_cc_role'] = "domainadmin"; $_SESSION['pending_tfa_method'] = get_tfa($user)['name']; unset($_SESSION['ldelay']); + $_SESSION['return'] = array( + 'type' => 'info', + 'log' => array(__FUNCTION__, $user, '*'), + 'msg' => 'awaiting_tfa_confirmation' + ); return "pending"; } else { unset($_SESSION['ldelay']); + // Reactivate TFA if it was set to "deactivate TFA for next login" $stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user"); $stmt->execute(array(':user' => $user)); + $_SESSION['return'] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $user, '*'), + 'msg' => array('logged_in_as', $user) + ); return "domainadmin"; } } @@ -229,6 +383,11 @@ function check_login($user, $pass) { foreach ($rows as $row) { if (verify_hash($row['password'], $pass) !== false) { unset($_SESSION['ldelay']); + $_SESSION['return'] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $user, '*'), + 'msg' => array('logged_in_as', $user) + ); return "user"; } } @@ -242,7 +401,13 @@ function check_login($user, $pass) { $redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']); error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']); } + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $user, '*'), + 'msg' => 'login_failed' + ); sleep($_SESSION['ldelay']); + return false; } function set_acl() { global $pdo; @@ -267,6 +432,11 @@ function set_acl() { $_SESSION = array_merge($_SESSION, $acl); } else { + $_SESSION['return'] = array( + 'type' => 'info', + 'log' => array(__FUNCTION__), + 'msg' => 'set_acl_failed' + ); return false; } } @@ -298,24 +468,29 @@ function formatBytes($size, $precision = 2) { } return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)]; } -function edit_admin_account($postarray) { +function edit_admin_account($_data) { global $lang; global $pdo; + $_data_log = $_data; + !isset($_data_log['admin_pass']) ?: $_data_log['admin_pass'] = '*'; + !isset($_data_log['admin_pass2']) ?: $_data_log['admin_pass2'] = '*'; if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'access_denied' ); return false; } $username_now = $_SESSION['mailcow_cc_username']; - $username = $postarray['admin_user']; - $password = $postarray['admin_pass']; - $password2 = $postarray['admin_pass2']; + $username = $_data['admin_user']; + $password = $_data['admin_pass']; + $password2 = $_data['admin_pass2']; if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username)) || empty ($username)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['username_invalid']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'username_invalid' ); return false; } @@ -323,14 +498,16 @@ function edit_admin_account($postarray) { if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_complexity']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'password_complexity' ); return false; } if ($password != $password2) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_mismatch']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'password_mismatch' ); return false; } @@ -349,7 +526,8 @@ function edit_admin_account($postarray) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -367,7 +545,8 @@ function edit_admin_account($postarray) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -381,14 +560,16 @@ function edit_admin_account($postarray) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['mailcow_cc_username'] = $username; $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['admin_modified']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'admin_modified' ); } function update_sogo_static_view() { @@ -402,22 +583,27 @@ function update_sogo_static_view() { $stmt = $pdo->query("DELETE FROM _sogo_static_view WHERE `c_uid` NOT IN (SELECT `username` FROM `mailbox` WHERE `active` = '1');"); } } -function edit_user_account($postarray) { +function edit_user_account($_data) { global $lang; global $pdo; + $_data_log = $_data; + !isset($_data_log['user_new_pass']) ?: $_data_log['user_new_pass'] = '*'; + !isset($_data_log['user_new_pass2']) ?: $_data_log['user_new_pass2'] = '*'; + !isset($_data_log['user_old_pass']) ?: $_data_log['user_old_pass'] = '*'; $username = $_SESSION['mailcow_cc_username']; $role = $_SESSION['mailcow_cc_role']; - $password_old = $postarray['user_old_pass']; + $password_old = $_data['user_old_pass']; if (filter_var($username, FILTER_VALIDATE_EMAIL === false) || $role != 'user') { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'access_denied' ); return false; } - if (isset($postarray['user_new_pass']) && isset($postarray['user_new_pass2'])) { - $password_new = $postarray['user_new_pass']; - $password_new2 = $postarray['user_new_pass2']; + if (isset($_data['user_new_pass']) && isset($_data['user_new_pass2'])) { + $password_new = $_data['user_new_pass']; + $password_new2 = $_data['user_new_pass2']; } $stmt = $pdo->prepare("SELECT `password` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' @@ -427,7 +613,8 @@ function edit_user_account($postarray) { if (!verify_hash($row['password'], $password_old)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -436,14 +623,16 @@ function edit_user_account($postarray) { if ($password_new2 != $password_new) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_mismatch']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'password_mismatch' ); return false; } if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password_new)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_complexity']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'password_complexity' ); return false; } @@ -458,7 +647,8 @@ function edit_user_account($postarray) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -467,7 +657,8 @@ function edit_user_account($postarray) { update_sogo_static_view(); $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], htmlspecialchars($username)) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('mailbox_modified', htmlspecialchars($username)) ); } function user_get_alias_details($username) { @@ -541,7 +732,8 @@ function user_get_alias_details($username) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $username), + 'msg' => array('mysql_error', $e) ); return false; } @@ -555,65 +747,71 @@ function is_valid_domain_name($domain_name) { && preg_match("/^.{1,253}$/", $domain_name) && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name)); } -function set_tfa($postarray) { +function set_tfa($_data) { global $lang; global $pdo; global $yubi; global $u2f; global $tfa; + $_data_log = $_data; + !isset($_data_log['confirm_password']) ?: $_data_log['confirm_password'] = '*'; + $username = $_SESSION['mailcow_cc_username']; if ($_SESSION['mailcow_cc_role'] != "domainadmin" && $_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'access_denied' ); return false; } - $username = $_SESSION['mailcow_cc_username']; - $stmt = $pdo->prepare("SELECT `password` FROM `admin` WHERE `username` = :user"); $stmt->execute(array(':user' => $username)); $row = $stmt->fetch(PDO::FETCH_ASSOC); - if (!verify_hash($row['password'], $postarray["confirm_password"])) { + if (!verify_hash($row['password'], $_data["confirm_password"])) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'access_denied' ); return false; } - switch ($postarray["tfa_method"]) { + switch ($_data["tfa_method"]) { case "yubi_otp": - $key_id = (!isset($postarray["key_id"])) ? 'unidentified' : $postarray["key_id"]; - $yubico_id = $postarray['yubico_id']; - $yubico_key = $postarray['yubico_key']; + $key_id = (!isset($_data["key_id"])) ? 'unidentified' : $_data["key_id"]; + $yubico_id = $_data['yubico_id']; + $yubico_key = $_data['yubico_key']; $yubi = new Auth_Yubico($yubico_id, $yubico_key); if (!$yubi) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'access_denied' ); return false; } - if (!ctype_alnum($postarray["otp_token"]) || strlen($postarray["otp_token"]) != 44) { + if (!ctype_alnum($_data["otp_token"]) || strlen($_data["otp_token"]) != 44) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['tfa_token_invalid']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'tfa_token_invalid' ); return false; } - $yauth = $yubi->verify($postarray["otp_token"]); + $yauth = $yubi->verify($_data["otp_token"]); if (PEAR::isError($yauth)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Yubico API: ' . $yauth->getMessage() + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('yotp_verification_failed', $yauth->getMessage()) ); return false; } try { // We could also do a modhex translation here - $yubico_modhex_id = substr($postarray["otp_token"], 0, 12); + $yubico_modhex_id = substr($_data["otp_token"], 0, 12); $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND (`authmech` != 'yubi_otp') @@ -626,40 +824,44 @@ function set_tfa($postarray) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars($username)) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('object_modified', htmlspecialchars($username)) ); break; case "u2f": - $key_id = (!isset($postarray["key_id"])) ? 'unidentified' : $postarray["key_id"]; + $key_id = (!isset($_data["key_id"])) ? 'unidentified' : $_data["key_id"]; try { - $reg = $u2f->doRegister(json_decode($_SESSION['regReq']), json_decode($postarray['token'])); + $reg = $u2f->doRegister(json_decode($_SESSION['regReq']), json_decode($_data['token'])); $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `authmech` != 'u2f'"); $stmt->execute(array(':username' => $username)); $stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `key_id`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`, `active`) VALUES (?, ?, 'u2f', ?, ?, ?, ?, '1')"); $stmt->execute(array($username, $key_id, $reg->keyHandle, $reg->publicKey, $reg->certificate, $reg->counter)); $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['object_modified'], $username) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('object_modified', $username) ); $_SESSION['regReq'] = null; } catch (Exception $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => "U2F: " . $e->getMessage() + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('u2f_verification_failed', $e->getMessage()) ); $_SESSION['regReq'] = null; return false; } break; case "totp": - $key_id = (!isset($postarray["key_id"])) ? 'unidentified' : $postarray["key_id"]; + $key_id = (!isset($_data["key_id"])) ? 'unidentified' : $_data["key_id"]; if ($tfa->verifyCode($_POST['totp_secret'], $_POST['totp_confirm_token']) === true) { try { $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username"); @@ -670,19 +872,22 @@ function set_tfa($postarray) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['object_modified'], $username) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('object_modified', $username) ); } else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'TOTP verification failed' + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'totp_verification_failed' ); } break; @@ -694,37 +899,42 @@ function set_tfa($postarray) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars($username)) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('object_modified', htmlspecialchars($username)) ); break; } } -function unset_tfa_key($postarray) { +function unset_tfa_key($_data) { // Can only unset own keys // Needs at least one key left global $pdo; global $lang; - $id = intval($postarray['unset_tfa_key']); + $_data_log = $_data; + $id = intval($_data['unset_tfa_key']); + $username = $_SESSION['mailcow_cc_username']; if ($_SESSION['mailcow_cc_role'] != "domainadmin" && $_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'access_denied' ); return false; } - $username = $_SESSION['mailcow_cc_username']; try { if (!is_numeric($id)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -735,7 +945,8 @@ function unset_tfa_key($postarray) { if ($row['keys'] == "1") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['last_key']) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => 'last_key' ); return false; } @@ -743,13 +954,15 @@ function unset_tfa_key($postarray) { $stmt->execute(array(':username' => $username, ':id' => $id)); $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['object_modified'], $username) + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('object_modified', $username) ); } catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -833,6 +1046,11 @@ function verify_tfa_login($username, $token) { switch ($row["authmech"]) { case "yubi_otp": if (!ctype_alnum($token) || strlen($token) != 44) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $username, '*'), + 'msg' => array('yotp_verification_failed', 'token length error') + ); return false; } $yubico_modhex_id = substr($token, 0, 12); @@ -849,14 +1067,25 @@ function verify_tfa_login($username, $token) { if (PEAR::isError($yauth)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Yubico Authentication error: ' . $yauth->getMessage() + 'log' => array(__FUNCTION__, $username, '*'), + 'msg' => array('yotp_verification_failed', $yauth->getMessage()) ); return false; } else { $_SESSION['tfa_id'] = $row['id']; + $_SESSION['return'] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $username, '*'), + 'msg' => 'verified_yotp_login' + ); return true; } + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $username, '*'), + 'msg' => array('yotp_verification_failed', 'unknown') + ); return false; break; case "u2f": @@ -866,16 +1095,27 @@ function verify_tfa_login($username, $token) { $stmt->execute(array($reg->counter, $reg->id)); $_SESSION['tfa_id'] = $reg->id; $_SESSION['authReq'] = null; + $_SESSION['return'] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $username, '*'), + 'msg' => 'verified_u2f_login' + ); return true; } catch (Exception $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => "U2F: " . $e->getMessage() + 'log' => array(__FUNCTION__, $username, '*'), + 'msg' => array('u2f_verification_failed', $e->getMessage()) ); $_SESSION['regReq'] = null; return false; } + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $username, '*'), + 'msg' => array('u2f_verification_failed', 'unknown') + ); return false; break; case "hotp": @@ -891,20 +1131,36 @@ function verify_tfa_login($username, $token) { $row = $stmt->fetch(PDO::FETCH_ASSOC); if ($tfa->verifyCode($row['secret'], $_POST['token']) === true) { $_SESSION['tfa_id'] = $row['id']; + $_SESSION['return'] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $username, '*'), + 'msg' => 'verified_totp_login' + ); return true; } + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $username, '*'), + 'msg' => 'totp_verification_failed' + ); return false; } catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $username, '*'), + 'msg' => array('mysql_error', $e) ); return false; } break; default: - return false; + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $username, '*'), + 'msg' => 'unknown_tfa_method' + ); + return false; break; } return false; @@ -915,7 +1171,8 @@ function admin_api($action, $data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__), + 'msg' => 'access_denied' ); return false; } @@ -934,7 +1191,8 @@ function admin_api($action, $data = null) { if (empty($allow_from)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'List of allowed IPs cannot be empty' + 'log' => array(__FUNCTION__, $data), + 'msg' => 'ip_list_empty' ); return false; } @@ -973,7 +1231,8 @@ function admin_api($action, $data = null) { } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['admin_modified']) + 'log' => array(__FUNCTION__, $data), + 'msg' => 'admin_modified' ); } function rspamd_ui($action, $data = null) { @@ -981,7 +1240,8 @@ function rspamd_ui($action, $data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__), + 'msg' => 'access_denied' ); return false; } @@ -992,21 +1252,24 @@ function rspamd_ui($action, $data = null) { if (empty($rspamd_ui_pass) || empty($rspamd_ui_pass2)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Password cannot be empty' + 'log' => array(__FUNCTION__, '*', '*'), + 'msg' => 'password_empty' ); return false; } if ($rspamd_ui_pass != $rspamd_ui_pass2) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Passwords do not match' + 'log' => array(__FUNCTION__, '*', '*'), + 'msg' => 'password_mismatch' ); return false; } if (strlen($rspamd_ui_pass) < 6) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Please use at least 6 characters for your password' + 'log' => array(__FUNCTION__, '*', '*'), + 'msg' => 'rspamd_ui_pw_length' ); return false; } @@ -1015,13 +1278,15 @@ function rspamd_ui($action, $data = null) { if ($docker_return_array['type'] == 'success') { $_SESSION['return'] = array( 'type' => 'success', - 'msg' => 'Rspamd UI password set successfully' + 'log' => array(__FUNCTION__, '*', '*'), + 'msg' => 'rspamd_ui_pw_set' ); return true; } else { $_SESSION['return'] = array( 'type' => $docker_return_array['type'], + 'log' => array(__FUNCTION__, '*', '*'), 'msg' => $docker_return_array['msg'] ); return false; @@ -1030,13 +1295,13 @@ function rspamd_ui($action, $data = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Unknown error' + 'log' => array(__FUNCTION__, '*', '*'), + 'msg' => 'unknown' ); return false; } break; } - } function get_admin_details() { // No parameter to be given, only one admin should exist @@ -1056,7 +1321,8 @@ function get_admin_details() { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__), + 'msg' => array('mysql_error', $e) ); } return $data; @@ -1070,19 +1336,68 @@ function get_u2f_registrations($username) { function get_logs($container, $lines = false) { if ($lines === false) { $lines = $GLOBALS['LOG_LINES'] - 1; + } + elseif(is_numeric($lines) && $lines >= 1) { + $lines = abs(intval($lines) - 1); + } + else { + list ($from, $to) = explode('-', $lines); + $from = intval($from); + $to = intval($to); + if ($from < 1 || $to < $from) { return false; } } global $lang; global $redis; + global $pdo; if ($_SESSION['mailcow_cc_role'] != "admin") { return false; } - if ($container == "dovecot-mailcow") { - if (!is_numeric($lines)) { - list ($from, $to) = explode('-', $lines); - $data = $redis->lRange('DOVECOT_MAILLOG', intval($from), intval($to)); + // SQL + if ($container == "mailcow-ui") { + if (isset($from) && isset($to)) { + try { + $stmt = $pdo->prepare("SELECT * FROM `logs` ORDER BY `id` DESC LIMIT :from, :to"); + $stmt->execute(array( + ':from' => $from - 1, + ':to' => $to + )); + $data = $stmt->fetchAll(PDO::FETCH_ASSOC); + } + catch(PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__), + 'msg' => array('mysql_error', $e) + ); + } } else { - $data = $redis->lRange('DOVECOT_MAILLOG', 0, intval($lines)); + try { + $stmt = $pdo->prepare("SELECT * FROM `logs` ORDER BY `id` DESC LIMIT :lines"); + $stmt->execute(array( + ':lines' => $lines + 1, + )); + $data = $stmt->fetchAll(PDO::FETCH_ASSOC); + } + catch(PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__), + 'msg' => array('mysql_error', $e) + ); + } + } + if (is_array($data)) { + return $data; + } + } + // Redis + if ($container == "dovecot-mailcow") { + if (isset($from) && isset($to)) { + $data = $redis->lRange('DOVECOT_MAILLOG', $from - 1, $to - 1); + } + else { + $data = $redis->lRange('DOVECOT_MAILLOG', 0, $lines); } if ($data) { foreach ($data as $json_line) { @@ -1092,12 +1407,11 @@ function get_logs($container, $lines = false) { } } if ($container == "postfix-mailcow") { - if (!is_numeric($lines)) { - list ($from, $to) = explode('-', $lines); - $data = $redis->lRange('POSTFIX_MAILLOG', intval($from), intval($to)); + if (isset($from) && isset($to)) { + $data = $redis->lRange('POSTFIX_MAILLOG', $from - 1, $to - 1); } else { - $data = $redis->lRange('POSTFIX_MAILLOG', 0, intval($lines)); + $data = $redis->lRange('POSTFIX_MAILLOG', 0, $lines); } if ($data) { foreach ($data as $json_line) { @@ -1107,12 +1421,11 @@ function get_logs($container, $lines = false) { } } if ($container == "sogo-mailcow") { - if (!is_numeric($lines)) { - list ($from, $to) = explode('-', $lines); - $data = $redis->lRange('SOGO_LOG', intval($from), intval($to)); + if (isset($from) && isset($to)) { + $data = $redis->lRange('SOGO_LOG', $from - 1, $to - 1); } else { - $data = $redis->lRange('SOGO_LOG', 0, intval($lines)); + $data = $redis->lRange('SOGO_LOG', 0, $lines); } if ($data) { foreach ($data as $json_line) { @@ -1122,12 +1435,11 @@ function get_logs($container, $lines = false) { } } if ($container == "watchdog-mailcow") { - if (!is_numeric($lines)) { - list ($from, $to) = explode('-', $lines); - $data = $redis->lRange('WATCHDOG_LOG', intval($from), intval($to)); + if (isset($from) && isset($to)) { + $data = $redis->lRange('WATCHDOG_LOG', $from - 1, $to - 1); } else { - $data = $redis->lRange('WATCHDOG_LOG', 0, intval($lines)); + $data = $redis->lRange('WATCHDOG_LOG', 0, $lines); } if ($data) { foreach ($data as $json_line) { @@ -1137,12 +1449,11 @@ function get_logs($container, $lines = false) { } } if ($container == "acme-mailcow") { - if (!is_numeric($lines)) { - list ($from, $to) = explode('-', $lines); - $data = $redis->lRange('ACME_LOG', intval($from), intval($to)); + if (isset($from) && isset($to)) { + $data = $redis->lRange('ACME_LOG', $from - 1, $to - 1); } else { - $data = $redis->lRange('ACME_LOG', 0, intval($lines)); + $data = $redis->lRange('ACME_LOG', 0, $lines); } if ($data) { foreach ($data as $json_line) { @@ -1152,12 +1463,11 @@ function get_logs($container, $lines = false) { } } if ($container == "api-mailcow") { - if (!is_numeric($lines)) { - list ($from, $to) = explode('-', $lines); - $data = $redis->lRange('API_LOG', intval($from), intval($to)); + if (isset($from) && isset($to)) { + $data = $redis->lRange('API_LOG', $from - 1, $to - 1); } else { - $data = $redis->lRange('API_LOG', 0, intval($lines)); + $data = $redis->lRange('API_LOG', 0, $lines); } if ($data) { foreach ($data as $json_line) { @@ -1167,12 +1477,11 @@ function get_logs($container, $lines = false) { } } if ($container == "netfilter-mailcow") { - if (!is_numeric($lines)) { - list ($from, $to) = explode('-', $lines); - $data = $redis->lRange('NETFILTER_LOG', intval($from), intval($to)); + if (isset($from) && isset($to)) { + $data = $redis->lRange('NETFILTER_LOG', $from - 1, $to - 1); } else { - $data = $redis->lRange('NETFILTER_LOG', 0, intval($lines)); + $data = $redis->lRange('NETFILTER_LOG', 0, $lines); } if ($data) { foreach ($data as $json_line) { @@ -1182,12 +1491,11 @@ function get_logs($container, $lines = false) { } } if ($container == "autodiscover-mailcow") { - if (!is_numeric($lines)) { - list ($from, $to) = explode('-', $lines); - $data = $redis->lRange('AUTODISCOVER_LOG', intval($from), intval($to)); + if (isset($from) && isset($to)) { + $data = $redis->lRange('AUTODISCOVER_LOG', $from - 1, $to - 1); } else { - $data = $redis->lRange('AUTODISCOVER_LOG', 0, intval($lines)); + $data = $redis->lRange('AUTODISCOVER_LOG', 0, $lines); } if ($data) { foreach ($data as $json_line) { diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index fbd1917d..d0d1cd1a 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -1,8 +1,11 @@ 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -18,7 +22,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -32,7 +37,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!is_numeric($_data["validity"]) || $_data["validity"] > 672) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['validity_missing']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'validity_missing' ); return false; } @@ -44,7 +50,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -63,13 +70,15 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], htmlspecialchars($usernames)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_modified', htmlspecialchars($_SESSION['mailcow_cc_username'])) ); break; case 'filter': @@ -77,7 +86,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -85,7 +95,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -99,7 +110,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'No user defined' + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'no_user_defined' ); return false; } @@ -110,7 +122,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (empty($script_data)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Script cannot be empty' + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'script_empty' ); return false; } @@ -120,21 +133,24 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (Exception $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Sieve parser error: ' . $e->getMessage() + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('sieve_error', $e->getMessage()) ); return false; } if (empty($script_data) || empty($script_desc)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Please define values for all fields' + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'value_missing' ); return false; } if ($filter_type != 'postfilter' && $filter_type != 'prefilter') { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Wrong filter type' + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'filter_type' ); return false; } @@ -144,13 +160,15 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { $stmt = $pdo->prepare("UPDATE `sieve_filters` SET `script_name` = 'inactive' WHERE `username` = :username AND `filter_type` = :filter_type"); $stmt->execute(array( ':username' => $username, + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), ':filter_type' => $filter_type )); } catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -172,20 +190,23 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], $username) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_modified', $username) ); break; case 'syncjob': if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -193,7 +214,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -207,7 +229,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'No user defined' + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'no_user_defined' ); return false; } @@ -249,35 +272,40 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 3600)))) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if (!is_valid_domain_name($host1)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if (@preg_match("/" . $exclude . "/", null) === false) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -290,14 +318,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['object_exists'], htmlspecialchars($host1 . ' / ' . $user1)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('object_exists', htmlspecialchars($host1 . ' / ' . $user1)) ); return false; } @@ -332,20 +362,23 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], $username) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_modified', $username) ); break; case 'domain': if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -359,14 +392,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($maxquota > $quota) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['mailbox_quota_exceeds_domain_quota']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'mailbox_quota_exceeds_domain_quota' ); return false; } if ($maxquota == "0" || empty($maxquota)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['maxquota_empty']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'maxquota_empty' ); return false; } @@ -377,7 +412,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!is_valid_domain_name($domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'domain_invalid' ); return false; } @@ -385,7 +421,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!is_numeric($data)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['object_is_not_numeric'], htmlspecialchars($data)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('object_is_not_numeric', htmlspecialchars($data)) ); return false; } @@ -403,21 +440,24 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_exists'], htmlspecialchars($domain)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('domain_exists', htmlspecialchars($domain)) ); return false; } if ($domain == getenv('MAILCOW_HOSTNAME')) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Domain cannot match hostname' + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'domain_cannot_match_hostname' ); return false; } @@ -441,7 +481,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) ); return false; } @@ -450,13 +491,15 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($restart_reponse['type'] == "success") { $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_added'], htmlspecialchars($domain)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('domain_added', htmlspecialchars($domain)) ); } else { $_SESSION['return'] = array( 'type' => 'warning', - 'msg' => 'Added domain but failed to restart SOGo, please check your server logs.' + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'domain_added_sogo_failed' ); } } @@ -465,7 +508,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { mailbox('delete', 'domain', array('domain' => $domain)); $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -480,14 +524,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (empty($addresses[0])) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['alias_empty']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'alias_empty' ); return false; } if (empty($gotos[0]) && ($goto_null + $goto_spam + $goto_ham == 0)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['goto_empty']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'goto_empty' ); return false; } @@ -516,14 +562,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['goto_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'goto_invalid' ); return false; } if (!filter_var($goto, FILTER_VALIDATE_EMAIL) === true) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['goto_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'goto_invalid' ); return false; } @@ -556,7 +604,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['is_alias_or_mailbox'], htmlspecialchars($address)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('is_alias_or_mailbox', htmlspecialchars($address)) ); return false; } @@ -564,7 +613,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (is_array($domaindata) && $domaindata['aliases_left'] == "0") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['max_alias_exceeded']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'max_alias_exceeded' ); return false; } @@ -576,7 +626,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results == 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_not_found'], htmlspecialchars($domain)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('domain_not_found', htmlspecialchars($domain)) ); return false; } @@ -587,7 +638,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['is_alias_or_mailbox'], htmlspecialchars($address)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('is_alias_or_mailbox', htmlspecialchars($address)) ); return false; } @@ -598,7 +650,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['is_spam_alias'], htmlspecialchars($address)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('is_spam_alias', htmlspecialchars($address)) ); return false; } @@ -606,21 +659,24 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['alias_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'alias_invalid' ); return false; } if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -645,21 +701,24 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['alias_added']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'alias_added' ); } catch (PDOException $e) { mailbox('delete', 'alias', array('address' => $address)); $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['alias_added']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'alias_added' ); break; case 'alias_domain': @@ -669,14 +728,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!is_valid_domain_name($target_domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['target_domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'target_domain_invalid' ); return false; } if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -685,14 +746,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!is_valid_domain_name($alias_domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['alias_domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'alias_domain_invalid' ); return false; } if ($alias_domain == $target_domain) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['aliasd_targetd_identical']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'aliasd_targetd_identical' ); return false; } @@ -704,7 +767,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results == 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['targetd_not_found']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'targetd_not_found' ); return false; } @@ -716,7 +780,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['alias_domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'alias_domain_invalid' ); return false; } @@ -724,7 +789,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -741,7 +807,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { mailbox('delete', 'alias_domain', array('alias_domain' => $alias_domain)); $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -751,14 +818,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['aliasd_added'], htmlspecialchars(implode(', ', $alias_domains))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('aliasd_added', htmlspecialchars(implode(', ', $alias_domains))) ); break; case 'mailbox': @@ -768,14 +837,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!filter_var($username, FILTER_VALIDATE_EMAIL)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['mailbox_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'mailbox_invalid' ); return false; } if (empty($_data['local_part'])) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['mailbox_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'mailbox_invalid' ); return false; } @@ -792,14 +863,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!is_valid_domain_name($domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'domain_invalid' ); return false; } if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -822,7 +895,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['object_exists'], htmlspecialchars($username)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('object_exists', htmlspecialchars($username)) ); return false; } @@ -832,7 +906,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['is_alias'], htmlspecialchars($username)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('is_alias', htmlspecialchars($username)) ); return false; } @@ -842,7 +917,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['is_spam_alias'], htmlspecialchars($username)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('is_spam_alias', htmlspecialchars($username)) ); return false; } @@ -852,7 +928,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results == 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_not_found'], htmlspecialchars($domain)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('domain_not_found', htmlspecialchars($domain)) ); return false; } @@ -860,14 +937,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if (!is_numeric($quota_m) || $quota_m == "0") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['quota_not_0_not_numeric']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'quota_not_0_not_numeric' ); return false; } @@ -875,14 +954,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_complexity']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'password_complexity' ); return false; } if ($password != $password2) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_mismatch']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'password_mismatch' ); return false; } @@ -891,21 +972,24 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_empty']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'password_empty' ); return false; } if ($MailboxData['count'] >= $DomainData['mailboxes']) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['max_mailbox_exceeded'], $MailboxData['count'], $DomainData['mailboxes']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('max_mailbox_exceeded', $MailboxData['count'], $DomainData['mailboxes']) ); return false; } if ($quota_m > $DomainData['maxquota']) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['mailbox_quota_exceeded'], $DomainData['maxquota']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_quota_exceeded', $DomainData['maxquota']) ); return false; } @@ -913,7 +997,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { $quota_left_m = ($DomainData['quota'] - $MailboxData['quota']); $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['mailbox_quota_left_exceeded'], $quota_left_m) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_quota_left_exceeded', $quota_left_m) ); return false; } @@ -947,14 +1032,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { )); $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_added'], htmlspecialchars($username)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_added', htmlspecialchars($username)) ); } catch (PDOException $e) { mailbox('delete', 'mailbox', array('username' => $username)); $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -970,14 +1057,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!filter_var($name, FILTER_VALIDATE_EMAIL)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['resource_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'resource_invalid' ); return false; } if (empty($description)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['description_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'description_invalid' ); return false; } @@ -987,21 +1076,24 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($kind != 'location' && $kind != 'group' && $kind != 'thing') { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['resource_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'resource_invalid' ); return false; } if (!is_valid_domain_name($domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'domain_invalid' ); return false; } if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1012,7 +1104,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['object_exists'], htmlspecialchars($name)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('object_exists', htmlspecialchars($name)) ); return false; } @@ -1022,7 +1115,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['is_alias'], htmlspecialchars($name)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('is_alias', htmlspecialchars($name)) ); return false; } @@ -1032,7 +1126,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['is_spam_alias'], htmlspecialchars($name)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('is_spam_alias', htmlspecialchars($name)) ); return false; } @@ -1042,7 +1137,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($num_results == 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_not_found'], htmlspecialchars($domain)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('domain_not_found', htmlspecialchars($domain)) ); return false; } @@ -1050,7 +1146,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -1068,14 +1165,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { )); $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['resource_added'], htmlspecialchars($name)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('resource_added', htmlspecialchars($name)) ); } catch (PDOException $e) { mailbox('delete', 'resource', array('name' => $name)); $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -1096,28 +1195,32 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['alias_domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'alias_domain_invalid' ); return false; } if (!is_valid_domain_name($target_domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['target_domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'target_domain_invalid' ); return false; } if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if (empty(mailbox('get', 'domain_details', $target_domain)) || !empty(mailbox('get', 'alias_domain_details', $target_domain))) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['target_domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'target_domain_invalid' ); return false; } @@ -1135,14 +1238,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['aliasd_modified'], htmlspecialchars(implode(', ', $alias_domains))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('aliasd_modified', htmlspecialchars(implode(', ', $alias_domains))) ); break; case 'tls_policy': @@ -1156,7 +1261,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!isset($_SESSION['acl']['tls_policy']) || $_SESSION['acl']['tls_policy'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1164,7 +1270,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1176,7 +1283,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1191,14 +1299,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], implode(', ', $usernames)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_modified', implode(', ', $usernames)) ); break; case 'spam_score': @@ -1212,7 +1322,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!isset($_SESSION['acl']['spam_score']) || $_SESSION['acl']['spam_score'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1222,7 +1333,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!is_numeric($lowspamlevel) || !is_numeric($highspamlevel)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1253,21 +1365,24 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { )); $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], implode(', ', $usernames)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_modified', implode(', ', $usernames)) ); break; case 'time_limited_alias': if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1287,14 +1402,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1310,14 +1427,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], htmlspecialchars(implode(', ', $usernames))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_modified', htmlspecialchars(implode(', ', $usernames))) ); break; case 'delimiter_action': @@ -1331,7 +1450,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!isset($_SESSION['acl']['delimiter_action']) || $_SESSION['acl']['delimiter_action'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1339,7 +1459,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1351,7 +1472,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) ); return false; } @@ -1364,7 +1486,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) ); return false; } @@ -1377,7 +1500,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) ); return false; } @@ -1385,7 +1509,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], implode(', ', $usernames)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_modified', implode(', ', $usernames)) ); break; case 'ratelimit': @@ -1394,7 +1519,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!in_array($rl_frame, array('s', 'm', 'h'))) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Ratelimit time frame is incorrect' + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'rl_timeframe' ); return false; } @@ -1410,7 +1536,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1419,7 +1546,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1434,7 +1562,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) ); return false; } @@ -1446,7 +1575,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) ); return false; } @@ -1454,7 +1584,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_modified'], implode(', ', $objects)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('domain_modified', implode(', ', $objects)) ); break; case 'syncjob': @@ -1468,7 +1599,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1501,7 +1633,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1523,35 +1656,40 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 3600)))) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if (!is_valid_domain_name($host1)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if (@preg_match("/" . $exclude . "/", null) === false) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1606,14 +1744,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], $username) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_modified', $username) ); break; case 'filter': @@ -1628,7 +1768,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1644,7 +1785,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -1654,14 +1796,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (Exception $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Sieve parser error: ' . $e->getMessage() + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('sieve_error', $e->getMessage()) ); return false; } if ($filter_type != 'postfilter' && $filter_type != 'prefilter') { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Wrong filter type' + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'filter_type' ); return false; } @@ -1677,7 +1821,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -1699,14 +1844,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], $username) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_modified', $username) ); break; case 'alias': @@ -1729,7 +1876,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['alias_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'alias_invalid' ); return false; } @@ -1751,14 +1899,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!filter_var($goto, FILTER_VALIDATE_EMAIL)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' =>sprintf($lang['danger']['goto_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' =>'goto_invalid' ); return false; } if ($goto == $address) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['alias_goto_identical']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'alias_goto_identical' ); return false; } @@ -1771,14 +1921,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['alias_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'alias_invalid' ); return false; } @@ -1807,14 +1959,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['alias_modified'], htmlspecialchars(implode(', ', $addresses))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('alias_modified', htmlspecialchars(implode(', ', $addresses))) ); break; case 'domain': @@ -1830,7 +1984,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!is_valid_domain_name($domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'domain_invalid' ); return false; } @@ -1848,13 +2003,15 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { )); $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_modified'], htmlspecialchars($domain)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('domain_modified', htmlspecialchars($domain)) ); } catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -1876,7 +2033,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'domain_invalid' ); return false; } @@ -1903,49 +2061,56 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if ($maxquota > $quota) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['mailbox_quota_exceeds_domain_quota']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'mailbox_quota_exceeds_domain_quota' ); return false; } if ($maxquota == "0" || empty($maxquota)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['maxquota_empty']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'maxquota_empty' ); return false; } if ($MailboxData['biggest_mailbox'] > $maxquota) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['max_quota_in_use'], $MailboxData['biggest_mailbox']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('max_quota_in_use', $MailboxData['biggest_mailbox']) ); return false; } if ($MailboxData['quota_all'] > $quota) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_quota_m_in_use'], $MailboxData['quota_all']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('domain_quota_m_in_use', $MailboxData['quota_all']) ); return false; } if ($MailboxData['count'] > $mailboxes) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['mailboxes_in_use'], $MailboxData['count']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailboxes_in_use', $MailboxData['count']) ); return false; } if ($AliasData['count'] > $aliases) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['aliases_in_use'], $AliasData['count']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('aliases_in_use', $AliasData['count']) ); return false; } @@ -1977,7 +2142,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -1985,7 +2151,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_modified'], htmlspecialchars(implode(', ', $domains))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('domain_modified', htmlspecialchars(implode(', ', $domains))) ); break; case 'mailbox': @@ -2000,7 +2167,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!filter_var($username, FILTER_VALIDATE_EMAIL)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['username_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'username_invalid' ); return false; } @@ -2018,7 +2186,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -2032,35 +2201,40 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if (!is_numeric($quota_m) || $quota_m == "0") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['quota_not_0_not_numeric'], htmlspecialchars($quota_m)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('quota_not_0_not_numeric', htmlspecialchars($quota_m)) ); return false; } if ($quota_m > $DomainData['maxquota']) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['mailbox_quota_exceeded'], $DomainData['maxquota']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_quota_exceeded', $DomainData['maxquota']) ); return false; } if (((($is_now['quota_used'] / 1048576) - $quota_m) + $quota_m) > $DomainData['quota']) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['mailbox_quota_left_exceeded'], ($is_now['max_new_quota'] / 1048576)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_quota_left_exceeded', ($is_now['max_new_quota'] / 1048576)) ); return false; } @@ -2071,27 +2245,65 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { mailbox('get', 'sender_acl_handles', $username)['sender_acl_addresses']['ro'] ); // Get sender_acl items from POST array - $sender_acl_domain_admin = ($_data['sender_acl'] == "0") ? array() : (array)$_data['sender_acl']; + // Set sender_acl_domain_admin to empty array if sender_acl contains "default" to trigger a reset + // Delete records from sender_acl if sender_acl contains "*" and set to array("*") + $_data['sender_acl'] = (array)$_data['sender_acl']; + if (in_array("*", $_data['sender_acl'])) { + $sender_acl_domain_admin = array('*'); + } + elseif (array("default") === $_data['sender_acl']) { + $sender_acl_domain_admin = array(); + } + else { + if (array_search('default', $_data['sender_acl']) !== false){ + unset($_data['sender_acl'][array_search('defaaault', $_data['sender_acl'])]); + } + $sender_acl_domain_admin = $_data['sender_acl']; + } if (!empty($sender_acl_domain_admin) || !empty($sender_acl_admin)) { // Check items in POST array and skip invalid foreach ($sender_acl_domain_admin as $key => $val) { - if (!filter_var($val, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name(ltrim($val, '@'))) { + // Check for invalid domain or email format or not * + if (!filter_var($val, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name(ltrim($val, '@')) && $val != '*') { unset($sender_acl_domain_admin[$key]); + continue; } - if (is_valid_domain_name(ltrim($val, '@'))) { - if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], ltrim($val, '@'))) { + // Check if user has domain access (if object is domain) + $domain = ltrim($sender_acl, '@'); + if (is_valid_domain_name($domain)) { + // Check for- and skip non-mailcow domains + $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')); + if (!empty($domains)) { + if (!in_array($domain, $domains)) { + unset($sender_acl_domain_admin[$key]); + continue; + } + } + if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['sender_acl_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'sender_acl_invalid' ); return false; } } + // Wildcard can only be used if role == admin + if ($val == '*' && $_SESSION['mailcow_cc_role'] != 'admin') { + $_SESSION['return'] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'sender_acl_invalid' + ); + return false; + } + // Check if user has mailbox access (if object is email) if (filter_var($val, FILTER_VALIDATE_EMAIL)) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $val)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['sender_acl_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'sender_acl_invalid' ); return false; } @@ -2099,6 +2311,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { } // Merge both arrays $sender_acl_merged = array_merge($sender_acl_domain_admin, $sender_acl_admin); + // If merged array still contains "*", set it as only value + !in_array('*', $sender_acl_merged) ?: $sender_acl_merged = array('*'); try { $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` = :username"); $stmt->execute(array( @@ -2108,7 +2322,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2128,7 +2343,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2144,7 +2360,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2154,14 +2371,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_complexity']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'password_complexity' ); return false; } if ($password != $password2) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_mismatch']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'password_mismatch' ); return false; } @@ -2178,7 +2397,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2208,14 +2428,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], implode(', ', $usernames)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_modified', implode(', ', $usernames)) ); break; case 'resource': @@ -2237,14 +2459,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['resource_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'resource_invalid' ); return false; } if (!filter_var($name, FILTER_VALIDATE_EMAIL)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['resource_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'resource_invalid' ); return false; } @@ -2254,21 +2478,24 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (empty($description)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['description_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'description_invalid' ); return false; } if ($kind != 'location' && $kind != 'group' && $kind != 'thing') { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['resource_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'resource_invalid' ); return false; } if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -2290,14 +2517,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['resource_modified'], implode(', ', $names)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('resource_modified', implode(', ', $names)) ); break; } @@ -2335,7 +2564,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { } // Return array $data['sender_acl_domains/addresses']['ro'] with read-only objects // Return array $data['sender_acl_domains/addresses']['rw'] with read-write objects (can be deleted) - $stmt = $pdo->prepare("SELECT REPLACE(`send_as`, '@', '') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `send_as` LIKE '@%'"); + $stmt = $pdo->prepare("SELECT REPLACE(`send_as`, '@', '') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND (`send_as` LIKE '@%' OR `send_as` = '*')"); $stmt->execute(array(':logged_in_as' => $_data)); $domain_rows = $stmt->fetchAll(PDO::FETCH_ASSOC); while ($domain_row = array_shift($domain_rows)) { @@ -2347,8 +2576,14 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { $data['sender_acl_domains']['rw'][] = $domain_row['send_as']; continue; } + if ($domain_row['send_as'] == '*' && $_SESSION['mailcow_cc_role'] != 'admin') { + $data['sender_acl_domains']['ro'][] = $domain_row['send_as']; + } + if ($domain_row['send_as'] == '*' && $_SESSION['mailcow_cc_role'] == 'admin') { + $data['sender_acl_domains']['rw'][] = $domain_row['send_as']; + } } - $stmt = $pdo->prepare("SELECT `send_as` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `send_as` NOT LIKE '@%'"); + $stmt = $pdo->prepare("SELECT `send_as` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND (`send_as` NOT LIKE '@%' AND `send_as` != '*')"); $stmt->execute(array(':logged_in_as' => $_data)); $address_rows = $stmt->fetchAll(PDO::FETCH_ASSOC); while ($address_row = array_shift($address_rows)) { @@ -2364,15 +2599,27 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { $stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain` NOT IN ( SELECT REPLACE(`send_as`, '@', '') FROM `sender_acl` - WHERE `logged_in_as` = :logged_in_as - AND `send_as` LIKE '@%')"); + WHERE `logged_in_as` = :logged_in_as1 + AND `send_as` LIKE '@%') + UNION + SELECT '*' FROM `domain` + WHERE '*' NOT IN ( + SELECT `send_as` FROM `sender_acl` + WHERE `logged_in_as` = :logged_in_as2 + )"); $stmt->execute(array( - ':logged_in_as' => $_data, + ':logged_in_as1' => $_data, + ':logged_in_as2' => $_data )); $rows_domain = $stmt->fetchAll(PDO::FETCH_ASSOC); while ($row_domain = array_shift($rows_domain)) { if (is_valid_domain_name($row_domain['domain']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row_domain['domain'])) { $data['sender_acl_domains']['selectable'][] = $row_domain['domain']; + continue; + } + if ($row_domain['domain'] == '*' && $_SESSION['mailcow_cc_role'] == 'admin') { + $data['sender_acl_domains']['selectable'][] = $row_domain['domain']; + continue; } } $stmt = $pdo->prepare("SELECT `address` FROM `alias` @@ -2395,7 +2642,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2420,7 +2668,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2440,7 +2689,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2465,7 +2715,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2496,7 +2747,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); } return $filters; @@ -2522,7 +2774,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2566,7 +2819,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { return false; } try { - if (isset($attr) && in_array('no_log', $attr)) { + if (isset($_extra) && in_array('no_log', $_extra)) { $field_query = $pdo->query('SHOW FIELDS FROM `imapsync` WHERE FIELD NOT IN ("returned_text", "password1")'); $fields = $field_query->fetchAll(PDO::FETCH_ASSOC); while($field = array_shift($fields)) { @@ -2577,7 +2830,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active` FROM `imapsync` WHERE id = :id"); } - elseif (isset($attr) && in_array('with_password', $attr)) { + elseif (isset($_extra) && in_array('with_password', $_extra)) { $stmt = $pdo->prepare("SELECT *, `active` AS `active_int`, CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active` @@ -2607,7 +2860,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); } if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $syncjobdetails['user2'])) { @@ -2636,7 +2890,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); } return $syncjobdata; @@ -2661,7 +2916,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2683,7 +2939,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2712,7 +2969,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); } return $tladata; @@ -2741,7 +2999,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) ); return false; } @@ -2765,7 +3024,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2785,7 +3045,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2811,7 +3072,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2831,7 +3093,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2856,7 +3119,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2867,7 +3131,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -2876,7 +3141,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -2898,7 +3164,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) ); return false; } @@ -2947,7 +3214,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -2979,7 +3247,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -3013,7 +3282,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -3099,7 +3369,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -3166,7 +3437,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -3204,7 +3476,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -3229,7 +3502,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3244,7 +3518,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $user2)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3254,14 +3529,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => 'Deleted syncjob id/s ' . implode(', ', $ids) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('deleted_syncjobs', implode(', ', $ids)) ); break; case 'filter': @@ -3275,7 +3552,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3290,7 +3568,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $usr)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3300,14 +3579,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => 'Deleted filter id/s ' . implode(', ', $ids) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('delete_filters', implode(', ', $ids)) ); break; case 'time_limited_alias': @@ -3321,7 +3602,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3334,14 +3616,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3355,14 +3639,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], htmlspecialchars($usernames)) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_modified', htmlspecialchars($usernames)) ); break; case 'eas_cache': @@ -3376,7 +3662,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!isset($_SESSION['acl']['eas_reset']) || $_SESSION['acl']['eas_reset'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3384,7 +3671,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3397,14 +3685,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['eas_reset'], htmlspecialchars(implode(', ', $usernames))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('eas_reset', htmlspecialchars(implode(', ', $usernames))) ); break; case 'domain': @@ -3418,7 +3708,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3426,7 +3717,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!is_valid_domain_name($domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'domain_invalid' ); return false; } @@ -3440,14 +3732,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if ($num_results != 0 || !empty($num_results)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_not_empty']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'domain_not_empty' ); return false; } @@ -3496,7 +3790,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -3506,14 +3801,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_removed'], htmlspecialchars(implode(', ', $domains))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('domain_removed', htmlspecialchars(implode(', ', $domains))) ); break; case 'alias': @@ -3535,7 +3832,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -3543,7 +3841,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3556,14 +3855,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['alias_removed'], htmlspecialchars(implode(', ', $addresses))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('alias_removed', htmlspecialchars(implode(', ', $addresses))) ); break; case 'alias_domain': @@ -3578,7 +3879,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!is_valid_domain_name($alias_domain)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'domain_invalid' ); return false; } @@ -3591,14 +3893,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $DomainData['target_domain'])) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3619,7 +3923,8 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } @@ -3629,14 +3934,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('redis_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['alias_domain_removed'], htmlspecialchars(implode(', ', $alias_domains))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('alias_domain_removed', htmlspecialchars(implode(', ', $alias_domains))) ); break; case 'mailbox': @@ -3651,14 +3958,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!filter_var($username, FILTER_VALIDATE_EMAIL)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3745,14 +4054,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_removed'], htmlspecialchars(implode(', ', $usernames))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mailbox_removed', htmlspecialchars(implode(', ', $usernames))) ); break; case 'resource': @@ -3767,14 +4078,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { if (!filter_var($name, FILTER_VALIDATE_EMAIL)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' ); return false; } @@ -3815,14 +4128,16 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['resource_removed'], htmlspecialchars(implode(', ', $names))) + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('resource_removed', htmlspecialchars(implode(', ', $names))) ); break; } diff --git a/data/web/inc/functions.policy.inc.php b/data/web/inc/functions.policy.inc.php index 63f178c1..6bc2f780 100644 --- a/data/web/inc/functions.policy.inc.php +++ b/data/web/inc/functions.policy.inc.php @@ -3,6 +3,7 @@ function policy($_action, $_scope, $_data = null) { global $pdo; global $redis; global $lang; + $_data_log = $_data; switch ($_action) { case 'add': switch ($_scope) { @@ -12,7 +13,8 @@ function policy($_action, $_scope, $_data = null) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -21,7 +23,8 @@ function policy($_action, $_scope, $_data = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -35,14 +38,16 @@ function policy($_action, $_scope, $_data = null) { if (!ctype_alnum(str_replace(array('@', '_', '.', '-', '*'), '', $object_from))) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['policy_list_from_invalid']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'policy_list_from_invalid' ); return false; } if ($object_list != "blacklist_from" && $object_list != "whitelist_from") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -56,7 +61,8 @@ function policy($_action, $_scope, $_data = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['policy_list_from_exists']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'policy_list_from_exists' ); return false; } @@ -64,7 +70,8 @@ function policy($_action, $_scope, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -80,13 +87,15 @@ function policy($_action, $_scope, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_modified'], $object) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('domain_modified', $object) ); break; case 'mailbox': @@ -94,14 +103,16 @@ function policy($_action, $_scope, $_data = null) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => $object + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } if (!isset($_SESSION['acl']['spam_policy']) || $_SESSION['acl']['spam_policy'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -115,14 +126,16 @@ function policy($_action, $_scope, $_data = null) { if (!ctype_alnum(str_replace(array('@', '_', '.', '-', '*'), '', $object_from))) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['policy_list_from_invalid']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'policy_list_from_invalid' ); return false; } if ($object_list != "blacklist_from" && $object_list != "whitelist_from") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -136,7 +149,8 @@ function policy($_action, $_scope, $_data = null) { if ($num_results != 0) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['policy_list_from_exists']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'policy_list_from_exists' ); return false; } @@ -144,7 +158,8 @@ function policy($_action, $_scope, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -160,13 +175,15 @@ function policy($_action, $_scope, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['mailbox_modified'], $object) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('mailbox_modified', $object) ); break; } @@ -179,7 +196,8 @@ function policy($_action, $_scope, $_data = null) { if (!is_numeric($prefid)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -191,14 +209,16 @@ function policy($_action, $_scope, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('mysql_error', $e) ); } if (is_valid_domain_name($object)) { if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -207,7 +227,8 @@ function policy($_action, $_scope, $_data = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -221,14 +242,16 @@ function policy($_action, $_scope, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['items_deleted'], implode(', ', $prefids)) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('items_deleted', implode(', ', $prefids)) ); break; case 'mailbox': @@ -242,7 +265,8 @@ function policy($_action, $_scope, $_data = null) { if (!isset($_SESSION['acl']['spam_policy']) || $_SESSION['acl']['spam_policy'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -250,7 +274,8 @@ function policy($_action, $_scope, $_data = null) { if (!is_numeric($prefid)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -262,13 +287,15 @@ function policy($_action, $_scope, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('mysql_error', $e) ); } if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -282,14 +309,16 @@ function policy($_action, $_scope, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['items_deleted'], implode(', ', $prefids)) + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('items_deleted', implode(', ', $prefids)) ); break; } @@ -319,7 +348,8 @@ function policy($_action, $_scope, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('mysql_error', $e) ); } return $rows; @@ -350,7 +380,8 @@ function policy($_action, $_scope, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log), + 'msg' => array('mysql_error', $e) ); } return $rows; diff --git a/data/web/inc/functions.quarantine.inc.php b/data/web/inc/functions.quarantine.inc.php index 057ebb57..865a0f08 100644 --- a/data/web/inc/functions.quarantine.inc.php +++ b/data/web/inc/functions.quarantine.inc.php @@ -3,6 +3,7 @@ function quarantine($_action, $_data = null) { global $pdo; global $redis; global $lang; + $_data_log = $_data; switch ($_action) { case 'delete': if (!is_array($_data['id'])) { @@ -15,7 +16,8 @@ function quarantine($_action, $_data = null) { if (!isset($_SESSION['acl']['quarantine']) || $_SESSION['acl']['quarantine'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -23,7 +25,8 @@ function quarantine($_action, $_data = null) { if (!is_numeric($id)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -41,7 +44,8 @@ function quarantine($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } @@ -49,7 +53,8 @@ function quarantine($_action, $_data = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -57,20 +62,23 @@ function quarantine($_action, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['items_deleted'], implode(', ', $ids)) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('items_deleted', implode(', ', $ids)) ); break; case 'edit': if (!isset($_SESSION['acl']['quarantine']) || $_SESSION['acl']['quarantine'] != "1" ) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -79,7 +87,8 @@ function quarantine($_action, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -94,13 +103,15 @@ function quarantine($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('redis_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => 'Saved settings' + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'saved_settings' ); } // Release item @@ -116,7 +127,8 @@ function quarantine($_action, $_data = null) { if (!is_numeric($id)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -127,7 +139,7 @@ function quarantine($_action, $_data = null) { if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['rcpt'])) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'msg' => 'access_denied' ); return false; } @@ -135,7 +147,8 @@ function quarantine($_action, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); } $sender = (isset($row['sender'])) ? $row['sender'] : 'sender-unknown@rspamd'; @@ -159,7 +172,8 @@ function quarantine($_action, $_data = null) { else { $_SESSION['return'] = array( 'type' => 'warning', - 'msg' => sprintf($lang['danger']['release_send_failed'], 'Cannot determine Postfix host') + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('release_send_failed', 'Cannot determine Postfix host') ); return false; } @@ -181,7 +195,8 @@ function quarantine($_action, $_data = null) { unlink($msg_tmpf); $_SESSION['return'] = array( 'type' => 'warning', - 'msg' => sprintf($lang['danger']['release_send_failed'], $e->errorMessage()) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('release_send_failed', $e->errorMessage()) ); return false; } @@ -194,14 +209,16 @@ function quarantine($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => $lang['success']['items_released'] + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'items_released' ); } return true; @@ -238,7 +255,8 @@ function quarantine($_action, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); } return $q_meta; @@ -247,7 +265,8 @@ function quarantine($_action, $_data = null) { if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -259,7 +278,8 @@ function quarantine($_action, $_data = null) { catch (RedisException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Redis: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('redis_error', $e) ); return false; } @@ -281,7 +301,8 @@ function quarantine($_action, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); } return false; diff --git a/data/web/inc/functions.relayhost.inc.php b/data/web/inc/functions.relayhost.inc.php index e6722258..8faad80a 100644 --- a/data/web/inc/functions.relayhost.inc.php +++ b/data/web/inc/functions.relayhost.inc.php @@ -2,12 +2,14 @@ function relayhost($_action, $_data = null) { global $pdo; global $lang; + $_data_log = $_data; switch ($_action) { case 'add': if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -17,7 +19,8 @@ function relayhost($_action, $_data = null) { if (empty($hostname)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Invalid host specified: '. htmlspecialchars($host) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('invalid_host', htmlspecialchars($host)) ); return false; } @@ -34,20 +37,23 @@ function relayhost($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['relayhost_added'], htmlspecialchars(implode(', ', $hosts))) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('relayhost_added', htmlspecialchars(implode(', ', $hosts))) ); break; case 'edit': if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -63,7 +69,8 @@ function relayhost($_action, $_data = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Relayhost invalid' + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'relayhost_invalid' ); return false; } @@ -85,21 +92,24 @@ function relayhost($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars(implode(', ', $hostnames))) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('object_modified', htmlspecialchars(implode(', ', $hostnames))) ); break; case 'delete': if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -114,14 +124,16 @@ function relayhost($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['relayhost_removed'], htmlspecialchars(implode(', ', $hostnames))) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('relayhost_removed', htmlspecialchars(implode(', ', $hostnames))) ); break; case 'get': @@ -136,7 +148,8 @@ function relayhost($_action, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); } return $relayhosts; @@ -170,7 +183,8 @@ function relayhost($_action, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); } return $relayhostdata; diff --git a/data/web/inc/functions.rsettings.inc.php b/data/web/inc/functions.rsettings.inc.php index aac8631c..9f13a4c3 100644 --- a/data/web/inc/functions.rsettings.inc.php +++ b/data/web/inc/functions.rsettings.inc.php @@ -2,12 +2,14 @@ function rsettings($_action, $_data = null) { global $pdo; global $lang; + $_data_log = $_data; switch ($_action) { case 'add': if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -17,7 +19,8 @@ function rsettings($_action, $_data = null) { if (empty($content)) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Content cannot be empty' + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'map_content_empty' ); return false; } @@ -33,20 +36,23 @@ function rsettings($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => 'Added settings map entry' + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'settings_map_added' ); break; case 'edit': if ($_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -61,7 +67,8 @@ function rsettings($_action, $_data = null) { else { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Settings map invalid' + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'settings_map_invalid' ); return false; } @@ -82,21 +89,24 @@ function rsettings($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars(implode(', ', $ids))) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('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']) + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => 'access_denied' ); return false; } @@ -109,14 +119,16 @@ function rsettings($_action, $_data = null) { catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); return false; } } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => 'Removed settings map ID' + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('settings_map_removed', htmlspecialchars(implode(', ', $ids))) ); break; case 'get': @@ -131,7 +143,8 @@ function rsettings($_action, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); } return $settingsmaps; @@ -155,7 +168,8 @@ function rsettings($_action, $_data = null) { catch(PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'MySQL: '.$e + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('mysql_error', $e) ); } return $settingsmapdata; diff --git a/data/web/inc/header.inc.php b/data/web/inc/header.inc.php index 396f0a97..46384b7b 100644 --- a/data/web/inc/header.inc.php +++ b/data/web/inc/header.inc.php @@ -1,4 +1,4 @@ - + diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php index 9be8b57e..a3b67283 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 = "25072018_1129"; + $db_version = "31072018_2319"; $stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); @@ -363,6 +363,24 @@ function init_db_schema() { ), "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" ), + "logs" => array( + "cols" => array( + "id" => "INT NOT NULL AUTO_INCREMENT", + "type" => "VARCHAR(32) DEFAULT ''", + "msg" => "TEXT", + "call" => "TEXT", + "user" => "VARCHAR(64) NOT NULL", + "role" => "VARCHAR(32) NOT NULL", + "remote" => "VARCHAR(32) NOT NULL", + "time" => "INT(11) NOT NULL" + ), + "keys" => array( + "primary" => array( + "" => array("id") + ) + ), + "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" + ), "quota2" => array( "cols" => array( "username" => "VARCHAR(255) NOT NULL", @@ -917,7 +935,8 @@ DELIMITER ;'; } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => 'Database initialisation completed' + 'log' => array(__FUNCTION__), + 'msg' => 'db_init_complete' ); // Fix user_acl @@ -926,7 +945,8 @@ DELIMITER ;'; catch (PDOException $e) { $_SESSION['return'] = array( 'type' => 'danger', - 'msg' => 'Database initialisation failed: ' . $e->getMessage() + 'log' => array(__FUNCTION__), + 'msg' => array('mysql_error', $e) ); } } diff --git a/data/web/inc/lib/composer.lock b/data/web/inc/lib/composer.lock index 9ea003e9..841f2e93 100644 --- a/data/web/inc/lib/composer.lock +++ b/data/web/inc/lib/composer.lock @@ -1,23 +1,23 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], "content-hash": "3edeec2e3fa875d4f9d5e7f22a8179be", "packages": [ { "name": "php-mime-mail-parser/php-mime-mail-parser", - "version": "2.9.5", + "version": "2.11.1", "source": { "type": "git", "url": "https://github.com/php-mime-mail-parser/php-mime-mail-parser.git", - "reference": "fbb424e77de2837dc6d8a110656d3c10f2fc9353" + "reference": "4769e942ed0dbbdd7882fc390b119d625463c8af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/fbb424e77de2837dc6d8a110656d3c10f2fc9353", - "reference": "fbb424e77de2837dc6d8a110656d3c10f2fc9353", + "url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/4769e942ed0dbbdd7882fc390b119d625463c8af", + "reference": "4769e942ed0dbbdd7882fc390b119d625463c8af", "shasum": "" }, "require": { @@ -84,7 +84,7 @@ "mailparse", "mime" ], - "time": "2018-01-16T18:38:20+00:00" + "time": "2018-04-30T05:55:59+00:00" }, { "name": "phpmailer/phpmailer", @@ -165,16 +165,16 @@ }, { "name": "robthree/twofactorauth", - "version": "1.6.1", + "version": "1.6.5", "source": { "type": "git", "url": "https://github.com/RobThree/TwoFactorAuth.git", - "reference": "a77e7d822343bb88112baef808839cfae7bc5abb" + "reference": "f5f58a4c62d0336a0e6175856894a51f3565dad2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/a77e7d822343bb88112baef808839cfae7bc5abb", - "reference": "a77e7d822343bb88112baef808839cfae7bc5abb", + "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/f5f58a4c62d0336a0e6175856894a51f3565dad2", + "reference": "f5f58a4c62d0336a0e6175856894a51f3565dad2", "shasum": "" }, "require": { @@ -212,7 +212,7 @@ "php", "tfa" ], - "time": "2017-11-06T17:55:56+00:00" + "time": "2018-06-09T10:09:59+00:00" }, { "name": "soundasleep/html2text", diff --git a/data/web/inc/lib/vendor/composer/installed.json b/data/web/inc/lib/vendor/composer/installed.json index f12b75c1..bd1deb85 100644 --- a/data/web/inc/lib/vendor/composer/installed.json +++ b/data/web/inc/lib/vendor/composer/installed.json @@ -1,17 +1,17 @@ [ { "name": "php-mime-mail-parser/php-mime-mail-parser", - "version": "2.9.5", - "version_normalized": "2.9.5.0", + "version": "2.11.1", + "version_normalized": "2.11.1.0", "source": { "type": "git", "url": "https://github.com/php-mime-mail-parser/php-mime-mail-parser.git", - "reference": "fbb424e77de2837dc6d8a110656d3c10f2fc9353" + "reference": "4769e942ed0dbbdd7882fc390b119d625463c8af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/fbb424e77de2837dc6d8a110656d3c10f2fc9353", - "reference": "fbb424e77de2837dc6d8a110656d3c10f2fc9353", + "url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/4769e942ed0dbbdd7882fc390b119d625463c8af", + "reference": "4769e942ed0dbbdd7882fc390b119d625463c8af", "shasum": "" }, "require": { @@ -28,7 +28,7 @@ "satooshi/php-coveralls": "0.*", "squizlabs/php_codesniffer": "2.*" }, - "time": "2018-01-16T18:38:20+00:00", + "time": "2018-04-30T05:55:59+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -162,17 +162,17 @@ }, { "name": "robthree/twofactorauth", - "version": "1.6.1", - "version_normalized": "1.6.1.0", + "version": "1.6.5", + "version_normalized": "1.6.5.0", "source": { "type": "git", "url": "https://github.com/RobThree/TwoFactorAuth.git", - "reference": "a77e7d822343bb88112baef808839cfae7bc5abb" + "reference": "f5f58a4c62d0336a0e6175856894a51f3565dad2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/a77e7d822343bb88112baef808839cfae7bc5abb", - "reference": "a77e7d822343bb88112baef808839cfae7bc5abb", + "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/f5f58a4c62d0336a0e6175856894a51f3565dad2", + "reference": "f5f58a4c62d0336a0e6175856894a51f3565dad2", "shasum": "" }, "require": { @@ -181,7 +181,7 @@ "require-dev": { "phpunit/phpunit": "@stable" }, - "time": "2017-11-06T17:55:56+00:00", + "time": "2018-06-09T10:09:59+00:00", "type": "library", "installation-source": "dist", "autoload": { diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/README.md b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/README.md index 7f996284..0b0502fc 100644 --- a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/README.md +++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/README.md @@ -98,10 +98,10 @@ $Parser->setStream(fopen("php://stdin", "r")); // Once we've indicated where to find the mail, we can parse out the data $to = $Parser->getHeader('to'); // "test" , "test2" -$addressesTo = $Parser->getAddresses('to'); //Return an array : [[test, test@example.com, false],[test2, test2@example.com, false]] +$addressesTo = $Parser->getAddresses('to'); //Return an array : [["display"=>"test", "address"=>"test@example.com", false],["display"=>"test2", "address"=>"test2@example.com", false]] $from = $Parser->getHeader('from'); // "test" -$addressesFrom = $Parser->getAddresses('from'); //Return an array : test, test@example.com, false +$addressesFrom = $Parser->getAddresses('from'); //Return an array : [["display"=>"test", "address"=>"test@example.com", "is_group"=>false]] $subject = $Parser->getHeader('subject'); diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Contracts/Middleware.php b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Contracts/Middleware.php new file mode 100644 index 00000000..69aed4f3 --- /dev/null +++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Contracts/Middleware.php @@ -0,0 +1,23 @@ +parser = $fn; + } + + /** + * Process a mime part, optionally delegating parsing to the $next MiddlewareStack + */ + public function parse(MimePart $part, MiddlewareStack $next) + { + return call_user_func($this->parser, $part, $next); + } +} diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/MiddlewareStack.php b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/MiddlewareStack.php new file mode 100644 index 00000000..967783a4 --- /dev/null +++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/MiddlewareStack.php @@ -0,0 +1,89 @@ +add($Middleware) + * + * @param Middleware $middleware + */ + public function __construct(Middleware $middleware = null) + { + $this->middleware = $middleware; + } + + /** + * Creates a chained middleware in MiddlewareStack + * + * @param Middleware $middleware + * @return MiddlewareStack Immutable MiddlewareStack + */ + public function add(Middleware $middleware) + { + $stack = new static($middleware); + $stack->next = $this; + return $stack; + } + + /** + * Parses the MimePart by passing it through the Middleware + * @param MimePart $part + * @return MimePart + */ + public function parse(MimePart $part) + { + if (!$this->middleware) { + return $part; + } + $part = call_user_func(array($this->middleware, 'parse'), $part, $this->next); + return $part; + } + + /** + * Creates a MiddlewareStack based on an array of middleware + * + * @param Middleware[] $middlewares + * @return MiddlewareStack + */ + public static function factory(array $middlewares = array()) + { + $stack = new static; + foreach ($middlewares as $middleware) { + $stack = $stack->add($middleware); + } + return $stack; + } + + /** + * Allow calling MiddlewareStack instance directly to invoke parse() + * + * @param MimePart $part + * @return MimePart + */ + public function __invoke(MimePart $part) + { + return $this->parse($part); + } +} diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/MimePart.php b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/MimePart.php new file mode 100644 index 00000000..a42728fb --- /dev/null +++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/MimePart.php @@ -0,0 +1,115 @@ +getPart(); + * $part['headers']['from'] = 'modified@example.com'; + * $MimePart->setPart($part); + */ +class MimePart implements \ArrayAccess +{ + /** + * Internal mime part + * + * @var array + */ + protected $part = array(); + + /** + * Immutable Part Id + * + * @var string + */ + private $id; + + /** + * Create a mime part + * + * @param array $part + * @param string $id + */ + public function __construct($id, array $part) + { + $this->part = $part; + $this->id = $id; + } + + /** + * Retrieve the part Id + * + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * Retrieve the part data + * + * @return array + */ + public function getPart() + { + return $this->part; + } + + /** + * Set the mime part data + * + * @param array $part + * @return void + */ + public function setPart(array $part) + { + $this->part = $part; + } + + /** + * ArrayAccess + */ + public function offsetSet($offset, $value) + { + if (is_null($offset)) { + $this->part[] = $value; + } else { + $this->part[$offset] = $value; + } + } + + /** + * ArrayAccess + */ + public function offsetExists($offset) + { + return isset($this->part[$offset]); + } + + /** + * ArrayAccess + */ + public function offsetUnset($offset) + { + unset($this->part[$offset]); + } + + /** + * ArrayAccess + */ + public function offsetGet($offset) + { + return isset($this->part[$offset]) ? $this->part[$offset] : null; + } +} diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Parser.php b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Parser.php index c9af9842..3a641d48 100644 --- a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Parser.php +++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Parser.php @@ -62,6 +62,13 @@ class Parser 'x+b', 'c+b', 'rt', 'r+t', 'w+t', 'a+t', 'x+t', 'c+t' ]; + /** + * Stack of middleware registered to process data + * + * @var MiddlewareStack + */ + protected $middlewareStack; + /** * Parser constructor. * @@ -74,6 +81,7 @@ class Parser } $this->charset = $charset; + $this->middlewareStack = new MiddlewareStack(); } /** @@ -185,7 +193,10 @@ class Parser $this->parts = []; foreach ($structure as $part_id) { $part = mailparse_msg_get_part($this->resource, $part_id); - $this->parts[$part_id] = mailparse_msg_get_part_data($part); + $part_data = mailparse_msg_get_part_data($part); + $mimePart = new MimePart($part_id, $part_data); + // let each middleware parse the part before saving + $this->parts[$part_id] = $this->middlewareStack->parse($mimePart)->getPart(); } } @@ -302,7 +313,7 @@ class Parser $start = $part['starting-pos']; $end = $part['starting-pos-body']; fseek($this->stream, $start, SEEK_SET); - $header = fread($this->stream, $end-$start); + $header = fread($this->stream, $end - $start); return $header; } @@ -316,7 +327,7 @@ class Parser { $start = $part['starting-pos']; $end = $part['starting-pos-body']; - $header = substr($this->data, $start, $end-$start); + $header = substr($this->data, $start, $end - $start); return $header; } @@ -357,12 +368,11 @@ class Parser * * @param string $type text, html or htmlEmbedded * - * @return false|string Body or False if not found + * @return string Body * @throws Exception */ public function getMessageBody($type = 'text') { - $body = false; $mime_types = [ 'text' => 'text/plain', 'html' => 'text/html', @@ -370,7 +380,7 @@ class Parser ]; if (in_array($type, array_keys($mime_types))) { - $part_type = $type === 'htmlEmbedded' ? 'html' : $type; + $part_type = $type === 'htmlEmbedded' ? 'html' : $type; $inline_parts = $this->getInlineParts($part_type); $body = empty($inline_parts) ? '' : $inline_parts[0]; } else { @@ -425,9 +435,13 @@ class Parser */ public function getAddresses($name) { - $value = $this->getHeader($name); - - return mailparse_rfc822_parse_addresses($value); + $value = $this->getRawHeader($name); + $value = (is_array($value)) ? $value[0] : $value; + $addresses = mailparse_rfc822_parse_addresses($value); + foreach ($addresses as $i => $item) { + $addresses[$i]['display'] = $this->decodeHeader($item['display']); + } + return $addresses; } /** @@ -438,7 +452,6 @@ class Parser public function getInlineParts($type = 'text') { $inline_parts = []; - $dispositions = ['inline']; $mime_types = [ 'text' => 'text/plain', 'html' => 'text/html', @@ -456,9 +469,6 @@ class Parser $headers = $this->getPart('headers', $part); $encodingType = array_key_exists('content-transfer-encoding', $headers) ? $headers['content-transfer-encoding'] : ''; - if (is_array($encodingType)) { - $encodingType = $encodingType[0]; - } $undecoded_body = $this->decodeContentTransfer($this->getPartBody($part), $encodingType); $inline_parts[] = $this->charset->decodeCharset($undecoded_body, $this->getPartCharset($part)); } @@ -475,9 +485,7 @@ class Parser public function getAttachments($include_inline = true) { $attachments = []; - $dispositions = $include_inline ? - ['attachment', 'inline'] : - ['attachment']; + $dispositions = $include_inline ? ['attachment', 'inline'] : ['attachment']; $non_attachment_types = ['text/plain', 'text/html']; $nonameIter = 0; @@ -504,6 +512,9 @@ class Parser // if we cannot get it by getMessageBody(), we assume it is an attachment $disposition = 'attachment'; } + if (in_array($disposition, ['attachment', 'inline']) === false && !empty($disposition)) { + $disposition = 'attachment'; + } if (in_array($disposition, $dispositions) === true) { if ($filename == 'noname') { @@ -514,12 +525,13 @@ class Parser $headersAttachments = $this->getPart('headers', $part); $contentidAttachments = $this->getPart('content-id', $part); + $attachmentStream = $this->getAttachmentStream($part); $mimePartStr = $this->getPartComplete($part); $attachments[] = new Attachment( $filename, $this->getPart('content-type', $part), - $this->getAttachmentStream($part), + $attachmentStream, $disposition, $contentidAttachments, $headersAttachments, @@ -564,7 +576,7 @@ class Parser break; case self::ATTACHMENT_DUPLICATE_THROW: case self::ATTACHMENT_DUPLICATE_SUFFIX: - $attachment_path = $attach_dir . $attachment->getFilename(); + $attachment_path = $attach_dir.$attachment->getFilename(); break; default: throw new Exception('Invalid filename strategy argument provided.'); @@ -622,8 +634,8 @@ class Parser $written = 0; while ($written < $len) { $write = $len; - $part = fread($this->stream, $write); - fwrite($temp_fp, $this->decodeContentTransfer($part, $encodingType)); + $data = fread($this->stream, $write); + fwrite($temp_fp, $this->decodeContentTransfer($data, $encodingType)); $written += $write; } } elseif ($this->data) { @@ -650,13 +662,17 @@ class Parser */ protected function decodeContentTransfer($encodedString, $encodingType) { + if (is_array($encodingType)) { + $encodingType = $encodingType[0]; + } + $encodingType = strtolower($encodingType); if ($encodingType == 'base64') { return base64_decode($encodedString); } elseif ($encodingType == 'quoted-printable') { return quoted_printable_decode($encodedString); } else { - return $encodedString; //8bit, 7bit, binary + return $encodedString; } } @@ -709,7 +725,7 @@ class Parser } $text = $this->charset->decodeCharset($text, $this->charset->getCharsetAlias($charset)); - $input = str_replace($encoded . $space, $text, $input); + $input = str_replace($encoded.$space, $text, $input); } return $input; @@ -720,14 +736,14 @@ class Parser * * @param array $part * - * @return string|false + * @return string */ protected function getPartCharset($part) { if (isset($part['charset'])) { return $this->charset->getCharsetAlias($part['charset']); } else { - return false; + return 'us-ascii'; } } @@ -901,4 +917,28 @@ class Parser { return $this->charset; } + + /** + * Add a middleware to the parser MiddlewareStack + * Each middleware is invoked when: + * a MimePart is retrieved by mailparse_msg_get_part_data() during $this->parse() + * The middleware will receive MimePart $part and the next MiddlewareStack $next + * + * Eg: + * + * $Parser->addMiddleware(function(MimePart $part, MiddlewareStack $next) { + * // do something with the $part + * return $next($part); + * }); + * + * @param callable $middleware Plain Function or Middleware Instance to execute + * @return void + */ + public function addMiddleware(callable $middleware) + { + if (!$middleware instanceof Middleware) { + $middleware = new Middleware($middleware); + } + $this->middlewareStack = $this->middlewareStack->add($middleware); + } } diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/.travis.yml b/data/web/inc/lib/vendor/robthree/twofactorauth/.travis.yml index 204dc63a..bdd2e2f4 100644 --- a/data/web/inc/lib/vendor/robthree/twofactorauth/.travis.yml +++ b/data/web/inc/lib/vendor/robthree/twofactorauth/.travis.yml @@ -1,18 +1,15 @@ language: php -dist: trusty -matrix: - include: - - php: 5.3 - dist: precise - php: - 5.4 - 5.5 - 5.6 - 7.0 - 7.1 - - hhvm + - 7.2 + +before_script: + - composer install script: - - if [[ "$TRAVIS_PHP_VERSION" == '5.6' ]]; then phpunit --coverage-text tests ; fi \ No newline at end of file + - vendor/bin/phpunit --coverage-text tests \ No newline at end of file diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/README.md b/data/web/inc/lib/vendor/robthree/twofactorauth/README.md index ba6cfeab..595e1df5 100644 --- a/data/web/inc/lib/vendor/robthree/twofactorauth/README.md +++ b/data/web/inc/lib/vendor/robthree/twofactorauth/README.md @@ -1,6 +1,6 @@ # ![Logo](https://raw.githubusercontent.com/RobThree/TwoFactorAuth/master/logo.png) PHP library for Two Factor Authentication -[![Build status](https://img.shields.io/travis/RobThree/TwoFactorAuth.svg?style=flat-square)](https://travis-ci.org/RobThree/TwoFactorAuth/) [![Latest Stable Version](https://img.shields.io/packagist/v/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![License](https://img.shields.io/packagist/l/robthree/twofactorauth.svg?style=flat-square)](LICENSE) [![Downloads](https://img.shields.io/packagist/dt/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![HHVM Status](https://img.shields.io/hhvm/RobThree/TwoFactorAuth.svg?style=flat-square)](http://hhvm.h4cc.de/package/robthree/twofactorauth) [![Code Climate](https://img.shields.io/codeclimate/github/RobThree/TwoFactorAuth.svg?style=flat-square)](https://codeclimate.com/github/RobThree/TwoFactorAuth) [![PayPal donate button](http://img.shields.io/badge/paypal-donate-orange.svg?style=flat-square)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6MB5M2SQLP636 "Keep me off the streets") +[![Build status](https://img.shields.io/travis/RobThree/TwoFactorAuth.svg?style=flat-square)](https://travis-ci.org/RobThree/TwoFactorAuth/) [![Latest Stable Version](https://img.shields.io/packagist/v/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![License](https://img.shields.io/packagist/l/robthree/twofactorauth.svg?style=flat-square)](LICENSE) [![Downloads](https://img.shields.io/packagist/dt/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![Code Climate](https://img.shields.io/codeclimate/github/RobThree/TwoFactorAuth.svg?style=flat-square)](https://codeclimate.com/github/RobThree/TwoFactorAuth) [![PayPal donate button](http://img.shields.io/badge/paypal-donate-orange.svg?style=flat-square)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6MB5M2SQLP636 "Keep me off the streets") PHP library for [two-factor (or multi-factor) authentication](http://en.wikipedia.org/wiki/Multi-factor_authentication) using [TOTP](http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) and [QR-codes](http://en.wikipedia.org/wiki/QR_code). Inspired by, based on but most importantly an *improvement* on '[PHPGangsta/GoogleAuthenticator](https://github.com/PHPGangsta/GoogleAuthenticator)'. There's a [.Net implementation](https://github.com/RobThree/TwoFactorAuth.Net) of this library as well. @@ -10,7 +10,7 @@ PHP library for [two-factor (or multi-factor) authentication](http://en.wikipedi ## Requirements -* Tested on PHP 5.3, 5.4, 5.5 and 5.6, 7.0, 7.1 and HHVM +* Tested on PHP 5.4 up to 7.2 * [cURL](http://php.net/manual/en/book.curl.php) when using the provided `GoogleQRCodeProvider` (default), `QRServerProvider` or `QRicketProvider` but you can also provide your own QR-code provider. * [random_bytes()](http://php.net/manual/en/function.random-bytes.php), [MCrypt](http://php.net/manual/en/book.mcrypt.php), [OpenSSL](http://php.net/manual/en/book.openssl.php) or [Hash](http://php.net/manual/en/book.hash.php) depending on which built-in RNG you use (TwoFactorAuth will try to 'autodetect' and use the best available); however: feel free to provide your own (CS)RNG. @@ -33,9 +33,9 @@ Here are some code snippets that should help you get started... $tfa = new RobThree\Auth\TwoFactorAuth('My Company'); ```` -The TwoFactorAuth class constructor accepts 7 parameters (all optional): +The TwoFactorAuth class constructor accepts 7 arguments (all optional): -Parameter | Default value | Use +Argument | Default value | Use ------------------|---------------|-------------------------------------------------- `$issuer` | `null` | Will be displayed in the app as issuer name `$digits` | `6` | The number of digits the resulting codes will be @@ -45,7 +45,7 @@ Parameter | Default value | Use `$rngprovider` | `null` | Random Number Generator provider (more on this later) `$timeprovider` | `null` | Time provider (more on this later) -These parameters are all '`write once`'; the class will, for it's lifetime, use these values when generating / calculating codes. The number of digits, the period and algorithm are all set to values Google's Authticator app uses (and supports). You may specify `8` digits, a period of `45` seconds and the `sha256` algorithm but the authenticator app (be it Google's implementation, Authy or any other app) may or may not support these values. Your mileage may vary; keep it on the safe side if you don't control which app your audience uses. +These arguments are all '`write once`'; the class will, for it's lifetime, use these values when generating / calculating codes. The number of digits, the period and algorithm are all set to values Google's Authticator app uses (and supports). You may specify `8` digits, a period of `45` seconds and the `sha256` algorithm but the authenticator app (be it Google's implementation, Authy or any other app) may or may not support these values. Your mileage may vary; keep it on the safe side if you don't control which app your audience uses. ### Step 1: Set up secret shared key @@ -89,9 +89,11 @@ When the shared secret is added to the app, the app will be ready to start gener $result = $tfa->verifyCode($_SESSION['secret'], $_POST['verification']); ```` -`verifyCode()` will return either `true` (the code was valid) or `false` (the code was invalid; no points for you!). You may need to store `$secret` in a `$_SESSION` or other persistent storage between requests. The `verifyCode()` accepts, aside from `$secret` and `$code`, two more parameters. The first being `$discrepancy`. Since TOTP codes are based on time("slices") it is very important that the server (but also client) have a correct date/time. But because the two *may* differ a bit we usually allow a certain amount of leeway. Because generated codes are valid for a specific period (remember the `$period` parameter in the `TwoFactorAuth`'s constructor?) we usually check the period directly before and the period directly after the current time when validating codes. So when the current time is `14:34:21`, which results in a 'current timeslice' of `14:34:00` to `14:34:30` we also calculate/verify the codes for `14:33:30` to `14:34:00` and for `14:34:30` to `14:35:00`. This gives us a 'window' of `14:33:30` to `14:35:00`. The `$discrepancy` parameter specifies how many periods (or: timeslices) we check in either direction of the current time. The default `$discrepancy` of `1` results in (max.) 3 period checks: -1, current and +1 period. A `$discrepancy` of `4` would result in a larger window (or: bigger time difference between client and server) of -4, -3, -2, -1, current, +1, +2, +3 and +4 periods. +`verifyCode()` will return either `true` (the code was valid) or `false` (the code was invalid; no points for you!). You may need to store `$secret` in a `$_SESSION` or other persistent storage between requests. The `verifyCode()` accepts, aside from `$secret` and `$code`, three more arguments. The first being `$discrepancy`. Since TOTP codes are based on time("slices") it is very important that the server (but also client) have a correct date/time. But because the two *may* differ a bit we usually allow a certain amount of leeway. Because generated codes are valid for a specific period (remember the `$period` argument in the `TwoFactorAuth`'s constructor?) we usually check the period directly before and the period directly after the current time when validating codes. So when the current time is `14:34:21`, which results in a 'current timeslice' of `14:34:00` to `14:34:30` we also calculate/verify the codes for `14:33:30` to `14:34:00` and for `14:34:30` to `14:35:00`. This gives us a 'window' of `14:33:30` to `14:35:00`. The `$discrepancy` argument specifies how many periods (or: timeslices) we check in either direction of the current time. The default `$discrepancy` of `1` results in (max.) 3 period checks: -1, current and +1 period. A `$discrepancy` of `4` would result in a larger window (or: bigger time difference between client and server) of -4, -3, -2, -1, current, +1, +2, +3 and +4 periods. -The second parameter `$time` allows you to check a code for a specific point in time. This parameter has no real practical use but can be handy for unittesting etc. The default value, `null`, means: use the current time. +The second, `$time`, allows you to check a code for a specific point in time. This argument has no real practical use but can be handy for unittesting etc. The default value, `null`, means: use the current time. + +The third, `$timeslice`, is an out-argument; the value returned in `$timeslice` is the value of the timeslice that matched the code (if any). This value will be 0 when the code doesn't match and non-zero when the code matches. This value can be stored with the user and can be used to prevent replay-attacks. All you need to do is, on successful login, make sure `$timeslice` is greater than the previously stored timeslice. ### Step 3: Store `$secret` with user and we're done! @@ -117,7 +119,7 @@ public function verifyCode($secret, $code, $discrepancy = 1, $time = null): bool ### QR-code providers -As mentioned before, this library comes with three 'built-in' QR-code providers. This chapter will touch the subject a bit but most of it should be self-explanatory. The `TwoFactorAuth`-class accepts a `$qrcodeprovider` parameter which lets you specify a built-in or custom QR-code provider. All three built-in providers do a simple HTTP request to retrieve an image using cURL and implement the [`IQRCodeProvider`](lib/Providers/Qr/IQRCodeProvider.php) interface which is all you need to implement to write your own QR-code provider. +As mentioned before, this library comes with three 'built-in' QR-code providers. This chapter will touch the subject a bit but most of it should be self-explanatory. The `TwoFactorAuth`-class accepts a `$qrcodeprovider` argument which lets you specify a built-in or custom QR-code provider. All three built-in providers do a simple HTTP request to retrieve an image using cURL and implement the [`IQRCodeProvider`](lib/Providers/Qr/IQRCodeProvider.php) interface which is all you need to implement to write your own QR-code provider. The default provider is the [`GoogleQRCodeProvider`](lib/Providers/Qr/GoogleQRCodeProvider.php) which uses the [Google Chart Tools](https://developers.google.com/chart/infographics/docs/qr_codes) to render QR-codes. Then we have the [`QRServerProvider`](lib/Providers/Qr/QRServerProvider.php) which uses the [goqr.me API](http://goqr.me/api/doc/create-qr-code/) and finally we have the [`QRicketProvider`](lib/Providers/Qr/QRicketProvider.php) which uses the [QRickit API](http://qrickit.com/qrickit_apps/qrickit_api.php). All three inherit from a common (abstract) baseclass named [`BaseHTTPQRCodeProvider`](lib/Providers/Qr/BaseHTTPQRCodeProvider.php) because all three share the same functionality: retrieve an image from a 3rd party over HTTP. All three classes have constructors that allow you to tweak some settings and most, if not all, arguments should speak for themselves. If you're not sure which values are supported, click the links in this paragraph for documentation on the API's that are utilized by these classes. @@ -132,7 +134,7 @@ The `getMimeType()` method should return the [MIME type](http://en.wikipedia.org `otpauth://totp/LABEL:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=ISSUER` -All you need to do is return the QR-code as binary image data and you're done. All parts of the `$qrtext` have been escaped for you (but note: you *may* need to escape the entire `$qrtext` just once more when passing the data to another server as GET-parameter). +All you need to do is return the QR-code as binary image data and you're done. All parts of the `$qrtext` have been escaped for you (but note: you *may* need to escape the entire `$qrtext` just once more when passing the data to another server as GET-argument). Let's see if we can use [PHP QR Code](http://phpqrcode.sourceforge.net/) to implement our own, custom, no-3rd-parties-allowed-here, provider. We start with downloading the [required (single) file](https://github.com/t0k4rt/phpqrcode/blob/master/phpqrcode.php) and putting it in the directory where `TwoFactorAuth.php` is located as well. Now let's implement the provider: create another file named `myprovider.php` in the `Providers\Qr` directory and paste in this content: @@ -176,15 +178,15 @@ Voilà. Couldn't make it any simpler. This library also comes with three 'built-in' RNG providers ([Random Number Generator](https://en.wikipedia.org/wiki/Random_number_generation)). The RNG provider generates a number of random bytes and returns these bytes as a string. These values are then used to create the secret. By default (no RNG provider specified) TwoFactorAuth will try to determine the best available RNG provider to use. It will, by default, try to use the [`CSRNGProvider`](lib/Providers/Rng/CSRNGProvider.php) for PHP7+ or the [`MCryptRNGProvider`](lib/Providers/Rng/MCryptRNGProvider.php); if this is not available/supported for any reason it will try to use the [`OpenSSLRNGProvider`](lib/Providers/Rng/OpenSSLRNGProvider.php) and if that is also not available/supported it will try to use the final RNG provider: [`HashRNGProvider`](lib/Providers/Rng/HashRNGProvider.php). Each of these providers use their own method of generating a random sequence of bytes. The first three (`CSRNGProvider`, `OpenSSLRNGProvider` and `MCryptRNGProvider`) return a [cryptographically secure](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) sequence of random bytes whereas the `HashRNGProvider` returns a **non-cryptographically secure** sequence. -You can easily implement your own `RNGProvider` by simply implementing the `IRNGProvider` interface. Each of the 'built-in' RNG providers have some constructor parameters that allow you to 'tweak' some of the settings to use when creating the random bytes such as which source to use (`MCryptRNGProvider`) or which hashing algorithm (`HashRNGProvider`). I encourage you to have a look at some of the ['built-in' RNG providers](lib/Providers/Rng) for details and the [`IRNGProvider` interface](lib/Providers/Rng/IRNGProvider.php). +You can easily implement your own `RNGProvider` by simply implementing the `IRNGProvider` interface. Each of the 'built-in' RNG providers have some constructor arguments that allow you to 'tweak' some of the settings to use when creating the random bytes such as which source to use (`MCryptRNGProvider`) or which hashing algorithm (`HashRNGProvider`). I encourage you to have a look at some of the ['built-in' RNG providers](lib/Providers/Rng) for details and the [`IRNGProvider` interface](lib/Providers/Rng/IRNGProvider.php). ### Time providers -Another set of providers in this library are the Time Providers; this library provides three 'built-in' ones. The default Time Provider used is the [`LocalMachineTimeProvider`](lib/Providers/Time/LocalMachineTimeProvider.php); this provider simply returns the output of `Time()` and is *highly recommended* as default provider. The [`HttpTimeProvider`](lib/Providers/Time/HttpTimeProvider.php) executes a `HEAD` request against a given webserver (default: google.com) and tries to extract the `Date:`-HTTP header and returns it's date. Other url's/domains can be used by specifying the url in the constructor. The final Time Provider is the [`ConvertUnixTimeDotComTimeProvider`](lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php) which does a HTTP request to `convert-unix-time.com/api` and decodes the `JSON` result to retrieve the time. +Another set of providers in this library are the Time Providers; this library provides three 'built-in' ones. The default Time Provider used is the [`LocalMachineTimeProvider`](lib/Providers/Time/LocalMachineTimeProvider.php); this provider simply returns the output of `Time()` and is *highly recommended* as default provider. The [`HttpTimeProvider`](lib/Providers/Time/HttpTimeProvider.php) executes a `HEAD` request against a given webserver (default: google.com) and tries to extract the `Date:`-HTTP header and returns it's date. Other url's/domains can be used by specifying the url in the constructor. The final Time Provider is the [`NTPTimeProvider`](lib/Providers/Time/NTPTimeProvider.php) which does an NTP request to a specified NTP server. You can easily implement your own `TimeProvider` by simply implementing the `ITimeProvider` interface. -As to *why* these Time Providers are implemented: it allows the TwoFactorAuth library to ensure the hosts time is correct (or rather: within a margin). You can use the `ensureCorrectTime()` method to ensure the hosts time is correct. By default this method will compare the hosts time (returned by calling `time()` on the `LocalMachineTimeProvider`) to Google's and convert-unix-time.com's current time. You can pass an array of `ITimeProvider`s and specify the `leniency` (second argument) allowed (default: 5 seconds). The method will throw when the TwoFactorAuth's timeprovider (which can be any `ITimeProvider`, see constructor) differs more than the given amount of seconds from any of the given `ITimeProviders`. We advise to call this method sparingly when relying on 3rd parties (which both the `HttpTimeProvider` and `ConvertUnixTimeDotComTimeProvider` do) or, if you need to ensure time is correct on a (very) regular basis to implement an `ITimeProvider` that is more efficient than the 'built-in' ones (like use a GPS signal). The `ensureCorrectTime()` method is mostly to be used to make sure the server is configured correctly. +As to *why* these Time Providers are implemented: it allows the TwoFactorAuth library to ensure the hosts time is correct (or rather: within a margin). You can use the `ensureCorrectTime()` method to ensure the hosts time is correct. By default this method will compare the hosts time (returned by calling `time()` on the `LocalMachineTimeProvider`) to Google's and convert-unix-time.com's current time. You can pass an array of `ITimeProvider`s and specify the `leniency` (second argument) allowed (default: 5 seconds). The method will throw when the TwoFactorAuth's timeprovider (which can be any `ITimeProvider`, see constructor) differs more than the given amount of seconds from any of the given `ITimeProviders`. We advise to call this method sparingly when relying on 3rd parties (which both the `HttpTimeProvider` and `NTPTimeProvider` do) or, if you need to ensure time is correct on a (very) regular basis to implement an `ITimeProvider` that is more efficient than the 'built-in' ones (like use a GPS signal). The `ensureCorrectTime()` method is mostly to be used to make sure the server is configured correctly. ## Integrations diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj b/data/web/inc/lib/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj index 7fa2a58e..995e964e 100644 --- a/data/web/inc/lib/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj +++ b/data/web/inc/lib/vendor/robthree/twofactorauth/TwoFactorAuth.phpproj @@ -38,10 +38,10 @@ - + @@ -65,5 +65,6 @@ + \ No newline at end of file diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json b/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json index 1ea66ab0..0bbf8b35 100644 --- a/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json +++ b/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json @@ -1,7 +1,7 @@ { "name": "robthree/twofactorauth", "description": "Two Factor Authentication", - "version": "1.6.1", + "version": "1.6.5", "type": "library", "keywords": [ "Authentication", "Two Factor Authentication", "Multi Factor Authentication", "TFA", "MFA", "PHP", "Authenticator", "Authy" ], "homepage": "https://github.com/RobThree/TwoFactorAuth", diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php index ca6e8593..eb425778 100644 --- a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php +++ b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/HashRNGProvider.php @@ -17,7 +17,7 @@ class HashRNGProvider implements IRNGProvider $hash = mt_rand(); for ($i = 0; $i < $bytecount; $i++) { $hash = hash($this->algorithm, $hash.mt_rand(), true); - $result .= $hash[mt_rand(0, sizeof($hash))]; + $result .= $hash[mt_rand(0, strlen($hash)-1)]; } return $result; } diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php index 1f55fa36..0eeab2c1 100644 --- a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php +++ b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Rng/MCryptRNGProvider.php @@ -11,7 +11,7 @@ class MCryptRNGProvider implements IRNGProvider } public function getRandomBytes($bytecount) { - $result = mcrypt_create_iv($bytecount, $this->source); + $result = @mcrypt_create_iv($bytecount, $this->source); if ($result === false) throw new \RNGException('mcrypt_create_iv returned an invalid value'); return $result; diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php deleted file mode 100644 index 9a775fc8..00000000 --- a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php +++ /dev/null @@ -1,15 +0,0 @@ -timestamp)) - throw new \TimeException('Unable to retrieve time from convert-unix-time.com'); - return $json->timestamp; - } -} \ No newline at end of file diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php new file mode 100644 index 00000000..862de792 --- /dev/null +++ b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/NTPTimeProvider.php @@ -0,0 +1,52 @@ +host = $host; + + if (!is_int($port) || $port <= 0 || $port > 65535) + throw new \TimeException('Port must be 0 < port < 65535'); + $this->port = $port; + + if (!is_int($timeout) || $timeout < 0) + throw new \TimeException('Timeout must be >= 0'); + $this->timeout = $timeout; + } + + public function getTime() { + try { + /* Create a socket and connect to NTP server */ + $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); + socket_connect($sock, $this->host, $this->port); + + /* Send request */ + $msg = "\010" . str_repeat("\0", 47); + socket_send($sock, $msg, strlen($msg), 0); + + /* Receive response and close socket */ + socket_recv($sock, $recv, 48, MSG_WAITALL); + socket_close($sock); + + /* Interpret response */ + $data = unpack('N12', $recv); + $timestamp = sprintf('%u', $data[9]); + + /* NTP is number of seconds since 0000 UT on 1 January 1900 Unix time is seconds since 0000 UT on 1 January 1970 */ + return $timestamp - 2208988800; + } + catch (Exception $ex) { + throw new \TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->host, $ex->getMessage())); + } + } +} \ No newline at end of file diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php index e6a1fa92..3e615030 100644 --- a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php +++ b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/TwoFactorAuth.php @@ -79,16 +79,23 @@ class TwoFactorAuth /** * Check if the code is correct. This will accept codes starting from ($discrepancy * $period) sec ago to ($discrepancy * period) sec from now */ - public function verifyCode($secret, $code, $discrepancy = 1, $time = null) + public function verifyCode($secret, $code, $discrepancy = 1, $time = null, &$timeslice = 0) { - $result = false; $timetamp = $this->getTime($time); - // To keep safe from timing-attachs we iterate *all* possible codes even though we already may have verified a code is correct - for ($i = -$discrepancy; $i <= $discrepancy; $i++) - $result |= $this->codeEquals($this->getCode($secret, $timetamp + ($i * $this->period)), $code); + $timeslice = 0; - return (bool)$result; + // To keep safe from timing-attacks we iterate *all* possible codes even though we already may have + // verified a code is correct. We use the timeslice variable to hold either 0 (no match) or the timeslice + // of the match. Each iteration we either set the timeslice variable to the timeslice of the match + // or set the value to itself. This is an effort to maintain constant execution time for the code. + for ($i = -$discrepancy; $i <= $discrepancy; $i++) { + $ts = $timetamp + ($i * $this->period); + $slice = $this->getTimeSlice($ts); + $timeslice = $this->codeEquals($this->getCode($secret, $ts), $code) ? $slice : $timeslice; + } + + return $timeslice > 0; } /** @@ -134,7 +141,7 @@ class TwoFactorAuth if ($timeproviders == null) $timeproviders = array( - new Providers\Time\ConvertUnixTimeDotComTimeProvider(), + new Providers\Time\NTPTimeProvider(), new Providers\Time\HttpTimeProvider() ); diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml b/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml new file mode 100644 index 00000000..92c3a273 --- /dev/null +++ b/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml @@ -0,0 +1,20 @@ + + + + + ./tests + + + + + ./lib + + + \ No newline at end of file diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml.tmppica b/data/web/inc/lib/vendor/robthree/twofactorauth/phpunit.xml.tmppica new file mode 100644 index 00000000..e69de29b diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php b/data/web/inc/lib/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php index 587b19b8..accfd5d7 100644 --- a/data/web/inc/lib/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php +++ b/data/web/inc/lib/vendor/robthree/twofactorauth/tests/TwoFactorAuthTest.php @@ -18,7 +18,7 @@ require_once 'lib/Providers/Rng/RNGException.php'; require_once 'lib/Providers/Time/ITimeProvider.php'; require_once 'lib/Providers/Time/LocalMachineTimeProvider.php'; require_once 'lib/Providers/Time/HttpTimeProvider.php'; -require_once 'lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php'; +require_once 'lib/Providers/Time/NTPTimeProvider.php'; require_once 'lib/Providers/Time/TimeException.php'; use RobThree\Auth\TwoFactorAuth; @@ -124,7 +124,8 @@ class TwoFactorAuthTest extends PHPUnit_Framework_TestCase public function testEnsureAllTimeProvidersReturnCorrectTime() { $tfa = new TwoFactorAuth('Test', 6, 30, 'sha1'); $tfa->ensureCorrectTime(array( - new RobThree\Auth\Providers\Time\ConvertUnixTimeDotComTimeProvider(), + new RobThree\Auth\Providers\Time\NTPTimeProvider(), // Uses pool.ntp.org by default + //new RobThree\Auth\Providers\Time\NTPTimeProvider('time.google.com'), // Somehow time.google.com and time.windows.com make travis timeout?? new RobThree\Auth\Providers\Time\HttpTimeProvider(), // Uses google.com by default new RobThree\Auth\Providers\Time\HttpTimeProvider('https://github.com'), new RobThree\Auth\Providers\Time\HttpTimeProvider('https://yahoo.com'), @@ -150,6 +151,31 @@ class TwoFactorAuthTest extends PHPUnit_Framework_TestCase $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 - 65)); //Test discrepancy } + public function testVerifyCorrectTimeSliceIsReturned() { + $tfa = new TwoFactorAuth('Test', 6, 30); + + // We test with discrepancy 3 (so total of 7 codes: c-3, c-2, c-1, c, c+1, c+2, c+3 + // Ensure each corresponding timeslice is returned correctly + $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '534113', 3, 1426847190, $timeslice1)); + $this->assertEquals(47561570, $timeslice1); + $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '819652', 3, 1426847190, $timeslice2)); + $this->assertEquals(47561571, $timeslice2); + $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '915954', 3, 1426847190, $timeslice3)); + $this->assertEquals(47561572, $timeslice3); + $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 3, 1426847190, $timeslice4)); + $this->assertEquals(47561573, $timeslice4); + $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '348401', 3, 1426847190, $timeslice5)); + $this->assertEquals(47561574, $timeslice5); + $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '648525', 3, 1426847190, $timeslice6)); + $this->assertEquals(47561575, $timeslice6); + $this->assertEquals(true, $tfa->verifyCode('VMR466AB62ZBOKHE', '170645', 3, 1426847190, $timeslice7)); + $this->assertEquals(47561576, $timeslice7); + + // Incorrect code should return false and a 0 timeslice + $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '111111', 3, 1426847190, $timeslice8)); + $this->assertEquals(0, $timeslice8); + } + public function testTotpUriIsCorrect() { $qr = new TestQrProvider(); @@ -295,10 +321,12 @@ class TwoFactorAuthTest extends PHPUnit_Framework_TestCase * @requires function mcrypt_create_iv */ public function testMCryptRNGProvidersReturnExpectedNumberOfBytes() { - $rng = new \RobThree\Auth\Providers\Rng\MCryptRNGProvider(); - foreach ($this->getRngTestLengths() as $l) - $this->assertEquals($l, strlen($rng->getRandomBytes($l))); - $this->assertEquals(true, $rng->isCryptographicallySecure()); + if (function_exists('mcrypt_create_iv')) { + $rng = new \RobThree\Auth\Providers\Rng\MCryptRNGProvider(); + foreach ($this->getRngTestLengths() as $l) + $this->assertEquals($l, strlen($rng->getRandomBytes($l))); + $this->assertEquals(true, $rng->isCryptographicallySecure()); + } } /** diff --git a/data/web/inc/sessions.inc.php b/data/web/inc/sessions.inc.php index f5a2184f..fe1cdfa2 100644 --- a/data/web/inc/sessions.inc.php +++ b/data/web/inc/sessions.inc.php @@ -30,11 +30,13 @@ if (!isset($_SESSION['SESS_REMOTE_UA'])) { if (!empty($_SERVER['HTTP_X_API_KEY'])) { $stmt = $pdo->prepare("SELECT `username`, `allow_from` FROM `api` WHERE `api_key` = :api_key AND `active` = '1';"); $stmt->execute(array( - ':api_key' => preg_replace('/[^A-Z0-9-]/', '', $_SERVER['HTTP_X_API_KEY']) + ':api_key' => preg_replace('/[^A-Z0-9-]/i', '', $_SERVER['HTTP_X_API_KEY']) )); $api_return = $stmt->fetch(PDO::FETCH_ASSOC); if (!empty($api_return['username'])) { - if (in_array($_SERVER['REMOTE_ADDR'], explode(',', $api_return['allow_from']))) { + $remote = get_remote_ip(false); + $allow_from = array_map('trim', preg_split( "/( |,|;|\n)/", $api_return['allow_from'])); + if (in_array($remote, $allow_from)) { $_SESSION['mailcow_cc_username'] = $api_return['username']; $_SESSION['mailcow_cc_role'] = 'admin'; $_SESSION['mailcow_cc_api'] = true; @@ -49,16 +51,22 @@ function session_check() { if ($_SESSION['mailcow_cc_api'] === true) { return true; } - if (!isset($_SESSION['SESS_REMOTE_UA'])) { - return false; - } - if ($_SESSION['SESS_REMOTE_UA'] != $_SERVER['HTTP_USER_AGENT']) { + if (!isset($_SESSION['SESS_REMOTE_UA']) || ($_SESSION['SESS_REMOTE_UA'] != $_SERVER['HTTP_USER_AGENT'])) { + $_SESSION['return'] = array( + 'type' => 'warning', + 'msg' => 'session_ua' + ); return false; } if (!empty($_POST)) { if ($_SESSION['CSRF']['TOKEN'] != $_POST['csrf_token']) { + $_SESSION['return'] = array( + 'type' => 'warning', + 'msg' => 'session_token' + ); return false; } + unset($_POST['csrf_token']); $_SESSION['CSRF']['TOKEN'] = bin2hex(random_bytes(32)); $_SESSION['CSRF']['TIME'] = time(); } @@ -66,10 +74,6 @@ function session_check() { } if (isset($_SESSION['mailcow_cc_role']) && session_check() === false) { - $_SESSION['return'] = array( - 'type' => 'warning', - 'msg' => 'Form token invalid or timed out' - ); $_POST = array(); $_FILES = array(); } diff --git a/data/web/inc/triggers.inc.php b/data/web/inc/triggers.inc.php index daf1a9a7..892d79fb 100644 --- a/data/web/inc/triggers.inc.php +++ b/data/web/inc/triggers.inc.php @@ -16,16 +16,19 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) { if ($as == "admin") { $_SESSION['mailcow_cc_username'] = $login_user; $_SESSION['mailcow_cc_role'] = "admin"; + $_SESSION['mailcow_cc_last_login'] = last_login($login_user); header("Location: /admin.php"); } elseif ($as == "domainadmin") { $_SESSION['mailcow_cc_username'] = $login_user; $_SESSION['mailcow_cc_role'] = "domainadmin"; + $_SESSION['mailcow_cc_last_login'] = last_login($login_user); header("Location: /mailbox.php"); } elseif ($as == "user") { $_SESSION['mailcow_cc_username'] = $login_user; $_SESSION['mailcow_cc_role'] = "user"; + $_SESSION['mailcow_cc_last_login'] = last_login($login_user); header("Location: /user.php"); } elseif ($as != "pending") { @@ -34,10 +37,6 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) { unset($_SESSION['pending_tfa_method']); unset($_SESSION['mailcow_cc_username']); unset($_SESSION['mailcow_cc_role']); - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => $lang['danger']['login_failed'] - ); } } diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php index 5e3ca0d3..4ac0df47 100644 --- a/data/web/inc/vars.inc.php +++ b/data/web/inc/vars.inc.php @@ -120,3 +120,5 @@ $RELAY_TO = "null@hosted.mailcow.de"; // How long to wait (in s) for cURL Docker requests $DOCKER_TIMEOUT = 60; +// Anonymize IPs logged via UI +$ANONYMIZE_IPS = true; diff --git a/data/web/js/admin.js b/data/web/js/admin.js index a8948e7d..f9f2867f 100644 --- a/data/web/js/admin.js +++ b/data/web/js/admin.js @@ -125,6 +125,7 @@ jQuery(function($){ }); } else if (table == 'domainadminstable') { $.each(data, function (i, item) { + item.selected_domains = escapeHtml(item.selected_domains.toString().replace(/,/g, " ")); item.chkbox = ''; item.action = '
' + ' ' + lang.edit + '' + diff --git a/data/web/js/debug.js b/data/web/js/debug.js index 23cf826e..1a208628 100644 --- a/data/web/js/debug.js +++ b/data/web/js/debug.js @@ -135,7 +135,7 @@ jQuery(function($){ {"name":"uri","title":"URI","style":{"width":"310px"}}, {"name":"method","title":"Method","style":{"width":"80px"}}, {"name":"remote","title":"IP","style":{"width":"80px"}}, - {"name":"data","title":"Data","style":{"word-break":"break-all"}}, + {"name":"data","title":"Data","breakpoints": "all","style":{"word-break":"break-all"}}, ], "rows": $.ajax({ dataType: 'json', @@ -162,6 +162,42 @@ jQuery(function($){ } }); } + function draw_ui_logs() { + ft_api_logs = FooTable.init('#ui_logs', { + "columns": [ + {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}}, + {"name":"type","title":"Type"}, + {"name":"user","title":"User"}, + {"name":"role","title":"Role"}, + {"name":"remote","title":"IP"}, + {"name":"msg","title":lang.message}, + {"name":"call","title":"Call","breakpoints": "all"}, + ], + "rows": $.ajax({ + dataType: 'json', + url: '/api/v1/get/logs/ui', + jsonp: false, + error: function () { + console.log('Cannot draw ui log table'); + }, + success: function (data) { + return process_table_data(data, 'mailcow_ui'); + } + }), + "empty": lang.empty, + "paging": {"enabled": true,"limit": 5,"size": log_pagination_size}, + "filtering": {"enabled": true,"delay": 1,"position": "left","connectors": false,"placeholder": lang.filter_table}, + "sorting": {"enabled": true}, + "on": { + "ready.ft.table": function(e, ft){ + table_log_ready(ft, 'ui_logs'); + }, + "after.ft.paging": function(e, ft){ + table_log_paging(ft, 'ui_logs'); + } + } + }); + } function draw_acme_logs() { ft_acme_logs = FooTable.init('#acme_log', { "columns": [ @@ -466,6 +502,12 @@ jQuery(function($){ item.service = ''; } }); + } else if (table == 'mailcow_ui') { + $.each(data, function (i, item) { + if (item === null) { return true; } + item.user = escapeHtml(item.user); + item.type = '' + item.type + ''; + }); } else if (table == 'general_syslog') { $.each(data, function (i, item) { if (item === null) { return true; } @@ -496,7 +538,7 @@ jQuery(function($){ $('.add_log_lines').on('click', function (e) { e.preventDefault(); var log_table= $(this).data("table") - var new_nrows = ($(this).data("nrows") - 1) + var new_nrows = $(this).data("nrows") var post_process = $(this).data("post-process") var log_url = $(this).data("log-url") if (log_table === undefined || new_nrows === undefined || post_process === undefined || log_url === undefined) { @@ -506,7 +548,7 @@ jQuery(function($){ if (ft = FooTable.get($('#' + log_table))) { var heading = ft.$el.parents('.tab-pane').find('.panel-heading') var ft_paging = ft.use(FooTable.Paging) - var load_rows = ft_paging.totalRows + '-' + (ft_paging.totalRows + new_nrows) + var load_rows = (ft_paging.totalRows + 1) + '-' + (ft_paging.totalRows + new_nrows) $.get('/api/v1/get/logs/' + log_url + '/' + load_rows).then(function(data){ if (data.length === undefined) { mailcow_alert_box(lang.no_new_rows, "info"); return; } var rows = process_table_data(data, post_process); @@ -525,6 +567,7 @@ jQuery(function($){ draw_watchdog_logs(); draw_acme_logs(); draw_api_logs(); + draw_ui_logs(); draw_netfilter_logs(); draw_rspamd_history(); $(window).resize(function () { diff --git a/data/web/js/edit.js b/data/web/js/edit.js index 6f82c545..2322fa9b 100644 --- a/data/web/js/edit.js +++ b/data/web/js/edit.js @@ -8,6 +8,16 @@ $(document).ready(function() { $("#textarea_alias_goto").removeAttr('disabled'); } }); + $("#disable_sender_check").click(function( event ) { + if ($("form[data-id='editmailbox'] #disable_sender_check:checked").length > 0) { + $('#sender_acl').prop('disabled', true); + $('#sender_acl').selectpicker('refresh'); + } + else { + $('#sender_acl').prop('disabled', false); + $('#sender_acl').selectpicker('refresh'); + } + }); if ($("form[data-id='editalias'] .goto_checkbox:checked").length > 0) { $('#textarea_alias_goto').prop('disabled', true); } @@ -26,6 +36,17 @@ $("#multiple_bookings_select").change(function() { $("#multiple_bookings_custom_div").hide(); } }); +if ($("#sender_acl option[value='\*']:selected").length > 0){ + $("#sender_acl_disabled").show(); +} +$('#sender_acl').change(function() { + if ($("#sender_acl option[value='\*']:selected").length > 0){ + $("#sender_acl_disabled").show(); + } + else { + $("#sender_acl_disabled").hide(); + } +}); $("#multiple_bookings_custom").bind("change keypress keyup blur", function() { $("#multiple_bookings").val($("#multiple_bookings_custom").val()); }); diff --git a/data/web/js/mailbox.js b/data/web/js/mailbox.js index 11b8a182..7d25c3f1 100644 --- a/data/web/js/mailbox.js +++ b/data/web/js/mailbox.js @@ -343,7 +343,7 @@ jQuery(function($){ }, {"name":"messages","filterable": false,"title":lang.msg_num,"breakpoints":"xs sm md"}, {"name":"active","filterable": false,"title":lang.active}, - {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right"},"type":"html","title":lang.action,"breakpoints":"xs sm md"} + {"name":"action","filterable": false,"sortable": false,"style":{"min-width":"250px","text-align":"right"},"type":"html","title":lang.action,"breakpoints":"xs sm md"} ], "empty": lang.empty, "rows": $.ajax({ diff --git a/data/web/js/user.js b/data/web/js/user.js index 29825769..226d039a 100644 --- a/data/web/js/user.js +++ b/data/web/js/user.js @@ -41,6 +41,8 @@ jQuery(function($){ return date.toLocaleString(); } acl_data = JSON.parse(acl); + var last_login = $('.last_login_date').data('time'); + $('.last_login_date').text(unix_time_format(last_login)); function draw_tla_table() { ft_tla_table = FooTable.init('#tla_table', { diff --git a/data/web/json_api.php b/data/web/json_api.php index 4df8433f..c05e2b2c 100644 --- a/data/web/json_api.php +++ b/data/web/json_api.php @@ -16,10 +16,10 @@ header('Content-Type: application/json'); require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php'; error_reporting(0); -function api_log($postarray) { +function api_log($_data) { global $redis; $data_var = array(); - foreach ($postarray as $data => &$value) { + foreach ($_data as $data => &$value) { if ($data == 'csrf_token') { continue; } @@ -27,7 +27,7 @@ function api_log($postarray) { unset($value["csrf_token"]); foreach ($value as $key => &$val) { if(preg_match("/pass/i", $key)) { - $val = '********'; + $val = '*'; } } $value = json_encode($value); @@ -39,7 +39,7 @@ function api_log($postarray) { 'time' => time(), 'uri' => $_SERVER['REQUEST_URI'], 'method' => $_SERVER['REQUEST_METHOD'], - 'remote' => $_SERVER['REMOTE_ADDR'], + 'remote' => get_remote_ip(), 'data' => implode(', ', $data_var) ); $redis->lPush('API_LOG', json_encode($log_line)); @@ -93,6 +93,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u } else { $attr = (array)json_decode($_POST['attr'], true); + unset($attr['csrf_token']); } switch ($category) { case "time_limited_alias": @@ -167,9 +168,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u if ($data) { $return = array(); $stats_array = json_decode($data, true)['actions']; - if (!empty($stats_array['soft reject']) || !empty($stats_array['greylist'])) { - $stats_array['soft reject'] = $stats_array['soft reject'] + $stats_array['greylist']; - } + $stats_array['soft reject'] = $stats_array['soft reject'] + $stats_array['greylist']; unset($stats_array['greylist']); foreach ($stats_array as $action => $count) { $return[] = array($action, $count); @@ -347,6 +346,17 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u } echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}'; break; + case "ui": + // 0 is first record, so empty is fine + if (isset($extra)) { + $extra = preg_replace('/[^\d\-]/i', '', $extra); + $logs = get_logs('mailcow-ui', $extra); + } + else { + $logs = get_logs('mailcow-ui'); + } + echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}'; + break; case "watchdog": // 0 is first record, so empty is fine if (isset($extra)) { @@ -903,6 +913,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u } else { $attr = (array)json_decode($_POST['attr'], true); + unset($attr['csrf_token']); $items = isset($_POST['items']) ? (array)json_decode($_POST['items'], true) : null; } switch ($category) { diff --git a/data/web/lang/lang.de.php b/data/web/lang/lang.de.php index f015bd26..fc582cb5 100644 --- a/data/web/lang/lang.de.php +++ b/data/web/lang/lang.de.php @@ -9,13 +9,57 @@ $lang['header']['restart_netfilter'] = 'Netfilter neustarten'; $lang['footer']['restart_container'] = 'Container neustarten'; $lang['footer']['restart_now'] = 'Jetzt neustarten'; $lang['footer']['restarting_container'] = 'Container wird neugestartet, bitte warten...'; -$lang['footer']['restart_container_info'] = 'Wichtig: Der Neustart eines Containers kann eine Weile in Anspruch nehmen, bitte warten Sie, bis der Prozess vollständig beendet wurde.
Die Website wird neugeladen, wenn der Vorgang erfolgreich ist.'; +$lang['footer']['restart_container_info'] = 'Wichtig: Der Neustart eines Containers kann eine Weile in Anspruch nehmen.'; $lang['footer']['confirm_delete'] = 'Löschen bestätigen'; $lang['footer']['delete_these_items'] = 'Sind Sie sicher, dass die Änderungen an Elementen mit folgender ID durchgeführt werden sollen?'; $lang['footer']['delete_now'] = 'Jetzt löschen'; $lang['footer']['cancel'] = 'Abbrechen'; +$lang['danger']['mysql_error'] = "MySQL Fehler: %s"; +$lang['danger']['redis_error'] = "Redis Fehler: %s"; +$lang['danger']['unknown_tfa_method'] = "Unbekannte TFA Methode"; +$lang['danger']['totp_verification_failed'] = "TOTP Verifizierung fehlgeschlagen"; +$lang['success']['verified_totp_login'] = "TOTP Anmeldung verifiziert"; +$lang['danger']['u2f_verification_failed'] = "U2F Verifizierung fehlgeschlagen: %s"; +$lang['success']['verified_u2f_login'] = "U2F Anmeldung verifiziert"; +$lang['success']['verified_yotp_login'] = "Yubico OTP Anmeldung verifiziert"; +$lang['danger']['yotp_verification_failed'] = "Yubico OTP Verifizierung fehlgeschlagen: %s"; +$lang['danger']['ip_list_empty'] = "Liste erlaubter IPs darf nicht leer sein"; +$lang['danger']['rspamd_ui_pw_length'] = "Rspamd UI Passwort muss mindestens 6 Zeichen lang sein"; +$lang['success']['rspamd_ui_pw_set'] = "Rspamd UI Passwort wurde gesetzt"; +$lang['danger']['unknown'] = "Ein unbekannter Fehler trat auf"; +$lang['danger']['malformed_username'] = "Benutzername hat falsches Format"; +$lang['info']['awaiting_tfa_confirmation'] = "Warte auf TFA Verifizierung"; +$lang['success']['logged_in_as'] = "Eingeloggt als %s"; +$lang['danger']['login_failed'] = "Anmeldung fehlgeschlagen"; +$lang['danger']['set_acl_failed'] = "ACL konnte nicht gesetzt werden"; +$lang['danger']['no_user_defined'] = "Kein Benutzer definiert"; +$lang['danger']['script_empty'] = "Script darf nicht leer sein"; +$lang['danger']['sieve_error'] = "Sieve Parser: %s"; +$lang['danger']['value_missing'] = "Bitte alle Felder ausfüllen"; +$lang['danger']['filter_type'] = "Falscher Filtertyp"; +$lang['danger']['domain_cannot_match_hostname'] = "Domain darf nicht dem Hostnamen entsprechen"; +$lang['warning']['domain_added_sogo_failed'] = "Domain wurde hinzugefügt; SOGo konnte nicht neugestartet werden"; +$lang['danger']['rl_timeframe'] = "Ratelimit Zeitraum ist inkorrekt"; +$lang['success']['deleted_syncjobs'] = "Syncjobs gelöscht: %s"; +$lang['success']['delete_filters'] = "Filter gelöscht: %s"; +$lang['danger']['invalid_bcc_map_type'] = "Ungültiger BCC Map-Typ"; +$lang['danger']['bcc_empty'] = "BCC Ziel darf nicht leer sein"; +$lang['danger']['bcc_must_be_email'] = "BCC Map muss eine gültige E-Mail-Adresse sein"; +$lang['danger']['bcc_exists'] = "Ein BCC Map Eintrag %s existiert bereits als Typ %s"; +$lang['success']['bcc_saved'] = "BCC Map Eintrag wurde gespeichert"; +$lang['success']['bcc_edited'] = "BCC Map Eintrag wurde editiert"; +$lang['success']['bcc_deleted'] = "BCC Map Einträge gelöscht: %s"; +$lang['danger']['private_key_error'] = "Schlüsselfehler: %s"; +$lang['danger']['map_content_empty'] = "Inhalt darf nicht leer sein"; +$lang['success']['settings_map_added'] = "Regel wurde gespeichert"; +$lang['danger']['settings_map_invalid'] = "Regel ist ungültig"; +$lang['danger']['settings_map_removed'] = "Regeln wurden entfernt: %s"; +$lang['danger']['invalid_host'] = "Ungültiger Host: %s"; +$lang['danger']['relayhost_invalid'] = "Relayhost ist ungültig"; +$lang['success']['saved_settings'] = "Regel wurde gespeichert"; + $lang['danger']['dkim_domain_or_sel_invalid'] = 'DKIM-Domain oder -Selector nicht korrekt'; $lang['success']['dkim_removed'] = 'DKIM-Key wurde entfernt'; $lang['success']['dkim_added'] = 'DKIM-Key wurde hinzugefügt'; @@ -416,7 +460,7 @@ $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']['add_settings_rule'] = 'Rspamd Regel hinzufügen'; $lang['admin']['rsetting_desc'] = 'Kurze Beschreibung'; $lang['admin']['rsetting_content'] = 'Regelinhalt'; $lang['admin']['rsetting_none'] = 'Keine Regel hinterlegt'; @@ -542,6 +586,16 @@ $lang['quarantine']['atts'] = "Anhänge"; $lang['header']['quarantine'] = "Quarantäne"; $lang['header']['debug'] = "Debugging"; +$lang['debug']['log_info'] = '

mailcow in-memory Logs werden in Redis Listen gespeichert, die maximale Anzahl der Einträge pro Anwendung richtet sich nach LOG_LINES (%d). +
In-memory Logs sind vergänglich und nicht zur ständigen Aufbewahrung bestimmt. Alle Anwendungen, die in-memory protokollieren, schreiben ebenso in den Docker Daemon. +
Das in-memory Protokoll versteht sich als schnelle Übersicht zum Debugging eines Containers, für komplexere Protokolle sollte der Docker Daemon konsultiert werden.

+

Externe Logs werden via API externer Applikationen bezogen.

+

Statische Logs sind weitesgehend Aktivitätsprotokolle, die nicht in den Docker Daemon geschrieben werden, jedoch permanent verfügbar sein müssen (ausgeschloßen API Logs).

'; + +$lang['debug']['in_memory_logs'] = 'In-memory Logs'; +$lang['debug']['external_logs'] = 'Externe Logs'; +$lang['debug']['static_logs'] = 'Statische Logs'; + $lang['quarantine']['release_body'] = "Die ursprüngliche Nachricht wurde als EML-Datei im Anhang hinterlegt."; $lang['danger']['release_send_failed'] = "Die Nachricht konnte nicht versendet werden: %s"; $lang['quarantine']['release_subject'] = "Potentiell schädliche Nachricht aus Quarantäne: %s"; diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php index dd0da489..df4049c7 100644 --- a/data/web/lang/lang.en.php +++ b/data/web/lang/lang.en.php @@ -9,13 +9,61 @@ $lang['header']['restart_netfilter'] = 'Restart netfilter'; $lang['footer']['restart_container'] = 'Restart container'; $lang['footer']['restart_now'] = 'Restart now'; $lang['footer']['restarting_container'] = 'Restarting container, this may take a while...'; -$lang['footer']['restart_container_info'] = 'Important: A graceful restart may take a while to complete, please wait for it to finish.
This website will reload if the process succeeded.'; +$lang['footer']['restart_container_info'] = 'Important: A graceful restart may take a while to complete, please wait for it to finish.'; $lang['footer']['confirm_delete'] = 'Confirm deletion'; $lang['footer']['delete_these_items'] = 'Please confirm your changes to the following object id:'; $lang['footer']['delete_now'] = 'Delete now'; $lang['footer']['cancel'] = 'Cancel'; +$lang['danger']['mysql_error'] = "MySQL error: %s"; +$lang['danger']['redis_error'] = "Redis error: %s"; +$lang['danger']['unknown_tfa_method'] = "Unknown TFA method"; +$lang['danger']['totp_verification_failed'] = "TOTP verification failed"; +$lang['success']['verified_totp_login'] = "Verified TOTP login"; +$lang['danger']['u2f_verification_failed'] = "U2F verification failed: %s"; +$lang['success']['verified_u2f_login'] = "Verified U2F login"; +$lang['success']['verified_yotp_login'] = "Verified Yubico OTP login"; +$lang['danger']['yotp_verification_failed'] = "Yubico OTP verification failed: %s"; +$lang['danger']['ip_list_empty'] = "List of allowed IPs cannot be empty"; +$lang['danger']['rspamd_ui_pw_length'] = "Rspamd UI password should be at least 6 chars long"; +$lang['success']['rspamd_ui_pw_set'] = "Rspamd UI password successfully set"; +$lang['danger']['unknown'] = "An unknown error occured"; +$lang['danger']['malformed_username'] = "Malformed username"; +$lang['info']['awaiting_tfa_confirmation'] = "Awaiting TFA confirmation"; +$lang['success']['logged_in_as'] = "Logged in as %s"; +$lang['danger']['login_failed'] = "Login failed"; +$lang['danger']['set_acl_failed'] = "Failed to set ACL"; +$lang['danger']['no_user_defined'] = "No user defined"; +$lang['danger']['script_empty'] = "Script cannot be empty"; +$lang['danger']['sieve_error'] = "Sieve parser error: %s"; +$lang['danger']['value_missing'] = "Please provide all values"; +$lang['danger']['filter_type'] = "Wrong filter type"; +$lang['danger']['domain_cannot_match_hostname'] = "Domain cannot match hostname"; +$lang['warning']['domain_added_sogo_failed'] = "Added domain but failed to restart SOGo, please check your server logs."; +$lang['danger']['rl_timeframe'] = "Ratelimit time frame is incorrect"; +$lang['success']['deleted_syncjobs'] = "Deleted syncjobs: %s"; +$lang['success']['delete_filters'] = "Deleted filters: %s"; +$lang['danger']['invalid_bcc_map_type'] = "Invalid BCC map type"; +$lang['danger']['bcc_empty'] = "BCC destination cannot be empty"; +$lang['danger']['bcc_must_be_email'] = "BCC map must be a valid email address"; +$lang['danger']['bcc_exists'] = "A BCC map %s exists for type %s"; +$lang['success']['bcc_saved'] = "BCC map entry saved"; +$lang['success']['bcc_edited'] = "BCC map entry edited"; +$lang['success']['bcc_deleted'] = "BCC map entries deleted: %s"; +$lang['danger']['private_key_error'] = "Private key error: %s"; +$lang['danger']['map_content_empty'] = "Map content cannot be empty"; +$lang['success']['settings_map_added'] = "Added settings map entry"; +$lang['danger']['settings_map_invalid'] = "Settings map invalid"; +$lang['danger']['settings_map_removed'] = "Removed settings map deleted: %s"; +$lang['danger']['invalid_host'] = "Invalid host specified: %s"; +$lang['danger']['relayhost_invalid'] = "Relayhost is invalid"; +$lang['success']['saved_settings'] = "Saved settings"; +$lang['success']['db_init_complete'] = "Database initialization completed"; + +$lang['warning']['session_ua'] = "Form token invalid: User-Agent validation error"; +$lang['warning']['session_token'] = "Form token invalid: Token mismatch"; + $lang['danger']['dkim_domain_or_sel_invalid'] = "DKIM domain or selector invalid"; $lang['success']['dkim_removed'] = "DKIM key %s has been removed"; $lang['success']['dkim_added'] = "DKIM key has been saved"; @@ -53,7 +101,7 @@ $lang['success']['domain_admin_modified'] = "Changes to domain administrator %s $lang['success']['domain_admin_added'] = "Domain administrator %s has been added"; $lang['success']['admin_modified'] = "Changes to administrator have been saved"; $lang['danger']['username_invalid'] = "Username cannot be used"; -$lang['danger']['password_mismatch'] = "Confirmation password is not identical"; +$lang['danger']['password_mismatch'] = "Confirmation password does not match"; $lang['danger']['password_complexity'] = "Password does not meet the policy"; $lang['danger']['password_empty'] = "Password must not be empty"; $lang['danger']['login_failed'] = "Login failed"; @@ -287,9 +335,10 @@ $lang['edit']['relay_all_info'] = 'If you choose not to relay all $lang['edit']['full_name'] = 'Full name'; $lang['edit']['quota_mb'] = 'Quota (MiB)'; $lang['edit']['sender_acl'] = 'Allow to send as'; +$lang['edit']['sender_acl_disabled'] = '↳ Sender check is disabled'; $lang['edit']['previous'] = 'Previous page'; $lang['edit']['unchanged_if_empty'] = 'If unchanged leave blank'; -$lang['edit']['dont_check_sender_acl'] = "Disable sender check for domain %s + alias domains"; +$lang['edit']['dont_check_sender_acl'] = "Disable sender check for domain %s (+ alias domains)"; $lang['edit']['multiple_bookings'] = 'Multiple bookings'; $lang['edit']['kind'] = 'Kind'; $lang['edit']['resource'] = 'Resource'; @@ -549,6 +598,16 @@ $lang['quarantine']['atts'] = "Attachments"; $lang['header']['quarantine'] = "Quarantine"; $lang['header']['debug'] = "Debug"; +$lang['debug']['log_info'] = '

mailcow in-memory logs are collected in Redis lists and trimmed to LOG_LINES (%d) every minute to reduce hammering. +
In-memory logs are not meant to be persistent. All applications that log in-memory, also log to the Docker daemon and therefore to the default logging driver. +
The in-memory log type should be used for debugging minor issues with containers.

+

External logs are collected via API of the given application.

+

Static logs are mostly activity logs, that are not logged to the Dockerd but still need to be persistent (except for API logs).

'; + +$lang['debug']['in_memory_logs'] = 'In-memory logs'; +$lang['debug']['external_logs'] = 'External logs'; +$lang['debug']['static_logs'] = 'Static logs'; + $lang['quarantine']['release_body'] = "We have attached your message as eml file to this message."; $lang['danger']['release_send_failed'] = "Message could not be released: %s"; $lang['quarantine']['release_subject'] = "Potentially damaging quarantine item %s"; diff --git a/data/web/user.php b/data/web/user.php index a7b06806..07e28616 100644 --- a/data/web/user.php +++ b/data/web/user.php @@ -19,6 +19,15 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'doma

[]

+

+ + () + +


@@ -94,6 +103,15 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '

[]

[]

+

+ + () + +