[Web] Show users last PW change, allow to select n days for last logins
parent
da20d5dc38
commit
47b57df3a2
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -126,3 +126,7 @@ border-bottom-width: 3px;
|
|||
.xmpp-logo-user {
|
||||
width:64px;
|
||||
}
|
||||
.recent-login-success {
|
||||
margin-top:2px;
|
||||
margin-right:10px;
|
||||
}
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
// Load core functions first
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>';
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue