From 47b57df3a2ada6cd3d8549ac2610bf823ca64663 Mon Sep 17 00:00:00 2001 From: andryyy Date: Wed, 9 Jun 2021 07:19:57 +0200 Subject: [PATCH] [Web] Show users last PW change, allow to select n days for last logins --- data/web/css/site/mailbox.css | 3 ++- data/web/css/site/user.css | 4 +++ data/web/inc/functions.inc.php | 10 ++++---- data/web/inc/prerequisites.inc.php | 21 ++-------------- data/web/inc/vars.inc.php | 39 ++++++++++++++---------------- data/web/js/site/mailbox.js | 7 ++++++ data/web/js/site/user.js | 12 ++++----- data/web/json_api.php | 1 + data/web/lang/lang.de.json | 3 +++ data/web/lang/lang.en.json | 3 +++ data/web/user.php | 18 +++++++++++--- 11 files changed, 65 insertions(+), 56 deletions(-) diff --git a/data/web/css/site/mailbox.css b/data/web/css/site/mailbox.css index 81e1ff3f..2467ea33 100644 --- a/data/web/css/site/mailbox.css +++ b/data/web/css/site/mailbox.css @@ -57,8 +57,9 @@ table tbody tr td input[type="checkbox"] { font-size: 8pt !important; } .label-last-login { - line-height: 2.5; + line-height: 2.2; color: #4a4a4a!important; + padding: .2em .4em .3em !important; background-color: #ececec!important; } diff --git a/data/web/css/site/user.css b/data/web/css/site/user.css index 246453c1..bfbca47c 100644 --- a/data/web/css/site/user.css +++ b/data/web/css/site/user.css @@ -125,4 +125,8 @@ border-bottom-width: 3px; } .xmpp-logo-user { width:64px; +} +.recent-login-success { + margin-top:2px; + margin-right:10px; } \ No newline at end of file diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 0beea3b6..7854acd6 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -251,21 +251,21 @@ function password_check($password1, $password2) { return true; } -function last_login($action, $username, $sasl_limit = 10) { +function last_login($action, $username, $sasl_limit_days = 7) { global $pdo; global $redis; - $sasl_limit = intval($sasl_limit); + $sasl_limit_days = intval($sasl_limit_days); switch ($action) { case 'get': if (filter_var($username, FILTER_VALIDATE_EMAIL) && hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) { $stmt = $pdo->prepare('SELECT `real_rip`, MAX(`datetime`) as `datetime`, `service`, `app_password` FROM `sasl_logs` LEFT OUTER JOIN `app_passwd` on `sasl_logs`.`app_password` = `app_passwd`.`id` WHERE `username` = :username + AND HOUR(TIMEDIFF(NOW(), `datetime`)) < :sasl_limit_days AND `success` = 1 GROUP BY `real_rip`, `service`, `app_password` - ORDER BY `datetime` DESC - LIMIT :sasl_limit;'); - $stmt->execute(array(':username' => $username, ':sasl_limit' => $sasl_limit)); + ORDER BY `datetime` DESC;'); + $stmt->execute(array(':username' => $username, ':sasl_limit_days' => ($sasl_limit_days * 24))); $sasl = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($sasl as $k => $v) { if (!filter_var($sasl[$k]['real_rip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php index 7e9a24f3..5baa81d8 100644 --- a/data/web/inc/prerequisites.inc.php +++ b/data/web/inc/prerequisites.inc.php @@ -172,29 +172,12 @@ function exception_handler($e) { set_exception_handler('exception_handler'); // TODO: Move function -function get_remote_ip($anonymize = null) { - global $ANONYMIZE_IPS; - if ($anonymize === null) { - $anonymize = $ANONYMIZE_IPS; - } - elseif ($anonymize !== true && $anonymize !== false) { - $anonymize = true; - } +function get_remote_ip() { $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; - } + return $remote; } // Load core functions first diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php index 1c3a2392..c390317f 100644 --- a/data/web/inc/vars.inc.php +++ b/data/web/inc/vars.inc.php @@ -82,24 +82,24 @@ $DEFAULT_LANG = 'en'; // https://www.iso.org/obp/ui/#search // https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes $AVAILABLE_LANGUAGES = array( - 'cs' => 'Čeština (Czech)', - 'da' => 'Danish (Dansk)', - 'de' => 'Deutsch (German)', - 'en' => 'English', - 'es' => 'Español (Spanish)', - 'fi' => 'Suomi (Finish)', - 'fr' => 'Français (French)', - 'hu' => 'Magyar (Hungarian)', - 'it' => 'Italiano (Italian)', - 'ko' => '한국어 (Korean)', - 'lv' => 'latviešu (Latvian)', - 'nl' => 'Nederlands (Dutch)', - 'pl' => 'Język Polski (Polish)', - 'pt' => 'Português (Portuguese)', - 'ro' => 'Română (Romanian)', - 'ru' => 'Pусский (Russian)', - 'sk' => 'Slovenčina (Slovak)', - 'sv' => 'Svenska (Swedish)', + 'cs' => 'Čeština (Czech)', + 'da' => 'Danish (Dansk)', + 'de' => 'Deutsch (German)', + 'en' => 'English', + 'es' => 'Español (Spanish)', + 'fi' => 'Suomi (Finish)', + 'fr' => 'Français (French)', + 'hu' => 'Magyar (Hungarian)', + 'it' => 'Italiano (Italian)', + 'ko' => '한국어 (Korean)', + 'lv' => 'latviešu (Latvian)', + 'nl' => 'Nederlands (Dutch)', + 'pl' => 'Język Polski (Polish)', + 'pt' => 'Português (Portuguese)', + 'ro' => 'Română (Romanian)', + 'ru' => 'Pусский (Russian)', + 'sk' => 'Slovenčina (Slovak)', + 'sv' => 'Svenska (Swedish)', 'zh' => '中文 (Chinese)' ); @@ -139,9 +139,6 @@ $OTP_LABEL = "mailcow UI"; // How long to wait (in s) for cURL Docker requests $DOCKER_TIMEOUT = 60; -// Anonymize IPs logged via UI -$ANONYMIZE_IPS = true; - // Split DKIM key notation (bind format) $SPLIT_DKIM_255 = false; diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js index d008b478..0a6d7ece 100644 --- a/data/web/js/site/mailbox.js +++ b/data/web/js/site/mailbox.js @@ -371,6 +371,7 @@ jQuery(function($){ '
POP3 @ ' + unix_time_format(Number(res[1])) + '

' + '
SMTP @ ' + unix_time_format(Number(res[2])) + '
'; }}, + {"name":"last_pw_change","filterable": false,"title":lang.last_pw_change,"breakpoints":"all"}, {"name":"quarantine_notification","filterable": false,"title":lang.quarantine_notification,"breakpoints":"all"}, {"name":"quarantine_category","filterable": false,"title":lang.quarantine_category,"breakpoints":"all"}, {"name":"in_use","filterable": false,"type":"html","title":lang.in_use,"sortValue": function(value){ @@ -408,6 +409,12 @@ jQuery(function($){ } */ item.chkbox = ''; + if (item.attributes.passwd_update != '0') { + var last_pw_change = new Date(item.attributes.passwd_update.replace(/-/g, "/")); + item.last_pw_change = last_pw_change.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); + } else { + item.last_pw_change = '-'; + } item.tls_enforce_in = ''; item.tls_enforce_out = ''; item.pop3_access = ''; diff --git a/data/web/js/site/user.js b/data/web/js/site/user.js index 3b3956f1..88712d57 100644 --- a/data/web/js/site/user.js +++ b/data/web/js/site/user.js @@ -72,17 +72,15 @@ jQuery(function($){ } acl_data = JSON.parse(acl); - $('.clear-last-logins').on('click', function () { - if (confirm(lang.delete_ays)) { - last_logins('reset'); - } - }) + $('.clear-last-logins').on('click', function () {if (confirm(lang.delete_ays)) {last_logins('reset');}}) + $(".login-history").on('click', function(e) {e.preventDefault(); last_logins('get', $(this).data('days'));$(this).addClass('active').siblings().removeClass('active');}); - function last_logins(action, lines = 10) { + function last_logins(action, days = 7) { if (action == 'get') { + $('.last-login').html('' + lang.waiting); $.ajax({ dataType: 'json', - url: '/api/v1/get/last-login/' + encodeURIComponent(mailcow_cc_username) + '/' + lines, + url: '/api/v1/get/last-login/' + encodeURIComponent(mailcow_cc_username) + '/' + days, jsonp: false, error: function () { console.log('error reading last logins'); diff --git a/data/web/json_api.php b/data/web/json_api.php index 3db775a4..ad4d9dbe 100644 --- a/data/web/json_api.php +++ b/data/web/json_api.php @@ -641,6 +641,7 @@ if (isset($_GET['query'])) { case "last-login": if ($object) { + // extra == days if (isset($extra) && intval($extra) >= 1) { $data = last_login('get', $object, intval($extra)); } diff --git a/data/web/lang/lang.de.json b/data/web/lang/lang.de.json index a35ecf82..4f7f6065 100644 --- a/data/web/lang/lang.de.json +++ b/data/web/lang/lang.de.json @@ -736,6 +736,7 @@ "insert_preset": "Beispiel \"%s\" laden", "kind": "Art", "last_mail_login": "Letzter Mail-Login", + "last_pw_change": "Letzte Passwortänderung", "last_run": "Letzte Ausführung", "last_run_reset": "Als nächstes ausführen", "mailbox": "Mailbox", @@ -1052,7 +1053,9 @@ "is_catch_all": "Ist Catch-All-Adresse für Domain(s)", "last_mail_login": "Letzter Mail-Login", "last_run": "Letzte Ausführung", + "last_pw_change": "Letzte Passwortänderung", "last_ui_login": "Letzte UI Anmeldung", + "login_history": "Login-Historie", "loading": "Lade...", "mailbox_details": "Mailbox-Details", "messages": "Nachrichten", diff --git a/data/web/lang/lang.en.json b/data/web/lang/lang.en.json index fc015299..a3c6e429 100644 --- a/data/web/lang/lang.en.json +++ b/data/web/lang/lang.en.json @@ -734,6 +734,7 @@ "insert_preset": "Insert example preset \"%s\"", "kind": "Kind", "last_mail_login": "Last mail login", + "last_pw_change": "Last password change", "last_run": "Last run", "last_run_reset": "Schedule next", "mailbox": "Mailbox", @@ -1050,8 +1051,10 @@ "is_catch_all": "Catch-all for domain/s", "last_mail_login": "Last mail login", "last_run": "Last run", + "last_pw_change": "Last password change", "last_ui_login": "Last UI login", "loading": "Loading...", + "login_history": "Login history", "mailbox_details": "Mailbox details", "messages": "messages", "month": "month", diff --git a/data/web/user.php b/data/web/user.php index bd7123d5..f9972fe0 100644 --- a/data/web/user.php +++ b/data/web/user.php @@ -174,9 +174,21 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '

[]

[]


-

-
- +

+ +
+
+ + +