[Web] Show users last PW change, allow to select n days for last logins

master
andryyy 2021-06-09 07:19:57 +02:00
parent da20d5dc38
commit 47b57df3a2
No known key found for this signature in database
GPG Key ID: 8EC34FF2794E25EF
11 changed files with 65 additions and 56 deletions

View File

@ -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;
}

View File

@ -126,3 +126,7 @@ border-bottom-width: 3px;
.xmpp-logo-user {
width:64px;
}
.recent-login-success {
margin-top:2px;
margin-right:10px;
}

View File

@ -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)) {

View File

@ -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

View File

@ -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;

View File

@ -371,6 +371,7 @@ jQuery(function($){
'<div class="label label-last-login">POP3 @ ' + unix_time_format(Number(res[1])) + '</div><br>' +
'<div class="label label-last-login">SMTP @ ' + unix_time_format(Number(res[2])) + '</div>';
}},
{"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 = '<input type="checkbox" data-id="mailbox" name="multi_select" value="' + encodeURIComponent(item.username) + '" />';
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 = '<i class="text-' + (item.attributes.tls_enforce_in == 1 ? 'success bi bi-lock-fill' : 'danger bi bi-unlock-fill') + '"></i>';
item.tls_enforce_out = '<i class="text-' + (item.attributes.tls_enforce_out == 1 ? 'success bi bi-lock-fill' : 'danger bi bi-unlock-fill') + '"></i>';
item.pop3_access = '<i class="text-' + (item.attributes.pop3_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.pop3_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';

View File

@ -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('<i class="bi bi-hourglass"></i>' + 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');

View File

@ -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));
}

View File

@ -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",

View File

@ -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",

View File

@ -174,9 +174,21 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
<p><a target="_blank" href="https://mailcow.github.io/mailcow-dockerized-docs/client/#<?=$clientconfigstr;?>">[<?=$lang['user']['client_configuration'];?>]</a></p>
<p><a href="#userFilterModal" data-toggle="modal">[<?=$lang['user']['show_sieve_filters'];?>]</a></p>
<hr>
<h4><?=$lang['user']['recent_successful_connections'];?></h4>
<div class="last-login"><i class="bi bi-hourglass"></i> <?=$lang['user']['waiting'];?></div>
<span class="clear-last-logins"><?=$lang['user']['clear_recent_successful_connections'];?></span>
<h4 class="recent-login-success pull-left"><?=$lang['user']['recent_successful_connections'];?></h4>
<div class="dropdown pull-left">
<button class="btn btn-default btn-xs dropdown-toggle" type="button" id="history_sasl_days" data-toggle="dropdown"><?=$lang['user']['login_history'];?> <span class="caret"></span></button>
<ul class="dropdown-menu">
<li class="login-history" data-days="1"><a href="#">1 <?=$lang['user']['day'];?></a></li>
<li class="login-history" data-days="7"><a href="#">1 <?=$lang['user']['week'];?></a></li>
<li class="login-history active" data-days="14"><a href="#">2 <?=$lang['user']['weeks'];?></a></li>
<li class="login-history" data-days="31"><a href="#">1 <?=$lang['user']['month'];?></a></li>
</ul>
</div>
<div class="clearfix"></div>
<div class="last-login"></div>
<span class="clear-last-logins">
<?=$lang['user']['clear_recent_successful_connections'];?>
</span>
</div>
</div>
<hr>