diff --git a/data/web/css/site/user.css b/data/web/css/site/user.css index b1ade575..806dea11 100644 --- a/data/web/css/site/user.css +++ b/data/web/css/site/user.css @@ -119,4 +119,11 @@ border-bottom-width: 3px; font-style: italic; color: #158cba; user-select:none; +} +.ip-location-flag { + border-radius: 4px; + top: 3px; +} +.xmpp-logo-user { + width:64px; } \ No newline at end of file diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index c6a7e6c8..8a605b03 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -251,8 +251,10 @@ function password_check($password1, $password2) { return true; } -function last_login($action, $username) { +function last_login($action, $username, $sasl_limit = 10) { global $pdo; + global $redis; + $sasl_limit = intval($sasl_limit); switch ($action) { case 'get': if (filter_var($username, FILTER_VALIDATE_EMAIL) && hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) { @@ -261,13 +263,51 @@ function last_login($action, $username) { AND `success` = 1 GROUP BY `real_rip`, `service` ORDER BY `datetime` DESC - LIMIT 5;'); - $stmt->execute(array(':username' => $username)); + LIMIT :sasl_limit;'); + $stmt->execute(array(':username' => $username, ':sasl_limit' => $sasl_limit)); $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)) { $sasl[$k]['real_rip'] = 'Web/EAS/Internal (' . $sasl[$k]['real_rip'] . ')'; } + elseif (filter_var($sasl[$k]['real_rip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { + try { + $sasl[$k]['location'] = $redis->hGet('IP_LOCATIONS', $sasl[$k]['real_rip']); + } + catch (RedisException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('redis_error', $e) + ); + return false; + } + if (!$sasl[$k]['location']) { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL,"https://dfdata.bella.network/lookup/" . $sasl[$k]['real_rip']); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + $ip_data = curl_exec($curl); + if (!curl_errno($curl)) { + $ip_data_array = json_decode($ip_data, true); + if ($ip_data_array !== false and !empty($ip_data_array['location']['shortcountry'])) { + $sasl[$k]['location'] = $ip_data_array['location']['shortcountry']; + try { + $redis->hSet('IP_LOCATIONS', $sasl[$k]['real_rip'], $sasl[$k]['location']); + } + catch (RedisException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_data_log), + 'msg' => array('redis_error', $e) + ); + curl_close($curl); + return false; + } + } + } + curl_close($curl); + } + } } } else { diff --git a/data/web/js/site/user.js b/data/web/js/site/user.js index 0ccabcf4..1a28c468 100644 --- a/data/web/js/site/user.js +++ b/data/web/js/site/user.js @@ -78,11 +78,11 @@ jQuery(function($){ } }) - function last_logins(action) { + function last_logins(action, lines = 5) { if (action == 'get') { $.ajax({ dataType: 'json', - url: '/api/v1/get/last-login/' + encodeURIComponent(mailcow_cc_username), + url: '/api/v1/get/last-login/' + encodeURIComponent(mailcow_cc_username) + '/' + lines, jsonp: false, error: function () { console.log('error reading last logins'); @@ -99,14 +99,24 @@ jQuery(function($){ $.each(data.sasl, function (i, item) { var datetime = new Date(item.datetime.replace(/-/g, "/")); var local_datetime = datetime.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); - if (item.service == "smtp") { service = '
' + item.service.toUpperCase() + '
'; } - else if (item.service == "imap") { service = '
' + item.service.toUpperCase() + '
'; } - else { service = '
' + item.service.toUpperCase() + '
'; } + if (item.location) { + ip_location = ''; + } else { + ip_location = ''; + } + if (item.service == "smtp") { + service = '
' + item.service.toUpperCase() + '
'; + } else if (item.service == "imap") { + service = '
' + item.service.toUpperCase() + '
'; + } else { + service = '
' + item.service.toUpperCase() + '
'; + } if (item.real_rip.startsWith("Web")) { real_rip = item.real_rip; } else { - real_rip = '' + item.real_rip + ''; + real_rip = '' + item.real_rip + ' '; } + real_rip = real_rip + ' ' + ip_location; $('.last-login').append('
  • ' + local_datetime + ' ' + service + ' ' + lang.from + ' ' + real_rip + diff --git a/data/web/json_api.php b/data/web/json_api.php index e8e9e888..3db775a4 100644 --- a/data/web/json_api.php +++ b/data/web/json_api.php @@ -641,7 +641,12 @@ if (isset($_GET['query'])) { case "last-login": if ($object) { - $data = last_login('get', $object); + if (isset($extra) && intval($extra) >= 1) { + $data = last_login('get', $object, intval($extra)); + } + else { + $data = last_login('get', $object); + } process_get_return($data); } break; diff --git a/data/web/user.php b/data/web/user.php index 466ffc4d..3f829e33 100644 --- a/data/web/user.php +++ b/data/web/user.php @@ -196,7 +196,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
    - XMPP Logo + XMPP Logo

    @.