Added attempted logins admin screen (#6018)

* Added attempted logins admin screen

* Smaller table spacing
This commit is contained in:
snipe 2018-08-01 03:51:59 -07:00 committed by GitHub
parent 911c2398ef
commit 694166862e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 166 additions and 14 deletions

View file

@ -11,6 +11,8 @@ use Mail;
use App\Notifications\SlackTest;
use Notification;
use App\Notifications\MailTest;
use App\Http\Transformers\LoginAttemptsTransformer;
use DB;
class SettingsController extends Controller
{
@ -143,6 +145,30 @@ class SettingsController extends Controller
}
/**
* Get a list of login attempts
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v5.0.0]
* @param \Illuminate\Http\Request $request
* @return array
*/
public function showLoginAttempts(Request $request)
{
$allowed_columns = ['id', 'username', 'remote_ip', 'user_agent','successful','created_at'];
$login_attempts = DB::table('login_attempts');
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'created_at';
$total = $login_attempts->count();
$login_attempts->orderBy($sort, $order);
$login_attempt_results = $login_attempts->skip(request('offset', 0))->take(request('limit', 20))->get();
return (new LoginAttemptsTransformer)->transformLoginAttempts($login_attempt_results, $total);
}
}

View file

@ -1103,4 +1103,8 @@ class SettingsController extends Controller
}
}
public function getLoginAttempts() {
return view('settings.logins');
}
}

View file

@ -0,0 +1,42 @@
<?php
namespace App\Http\Transformers;
use Illuminate\Database\Eloquent\Collection;
use Gate;
use App\Helpers\Helper;
class LoginAttemptsTransformer
{
public function transformLoginAttempts ($login_attempts, $total)
{
$array = array();
foreach ($login_attempts as $login_attempt) {
$array[] = self::transformLoginAttempt($login_attempt);
}
return (new DatatablesTransformer)->transformDatatables($array, $total);
}
public function transformLoginAttempt($login_attempt)
{
if ($login_attempt) {
$array = [
'id' => (int) $login_attempt->id,
'username' => e($login_attempt->username),
'user_agent' => e($login_attempt->user_agent),
'remote_ip' => (!config('app.lock_passwords')) ? e($login_attempt->remote_ip) : '--',
'successful' => e($login_attempt->successful),
'created_at' => Helper::getFormattedDateObject($login_attempt->created_at, 'datetime'),
];
return $array;
}
}
}

29
npm-shrinkwrap.json generated
View file

@ -2,6 +2,11 @@
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@fortawesome/fontawesome-free": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.2.0.tgz",
"integrity": "sha512-4pgStJx9UmydKc7wwF6Xjw4dFqzUnQejeuP2aUNHWazayWbmMbrx5rieN9+oob4bUwkf1thS3am0Ko+uhFHpNA=="
},
"@sindresorhus/is": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
@ -462,7 +467,7 @@
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
"dev": true,
"requires": {
"ms": "2.0.0"
@ -2242,7 +2247,7 @@
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
"dev": true,
"requires": {
"ms": "2.0.0"
@ -5645,7 +5650,7 @@
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
"dev": true
},
"uglify-js": {
@ -9116,7 +9121,7 @@
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=",
"dev": true,
"requires": {
"color-convert": "1.9.1"
@ -9136,7 +9141,7 @@
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
"dev": true
},
"supports-color": {
@ -9479,7 +9484,7 @@
"postcss": {
"version": "5.2.18",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
"integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
"integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=",
"dev": true,
"requires": {
"chalk": "1.1.3",
@ -9558,7 +9563,7 @@
"schema-utils": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz",
"integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==",
"integrity": "sha1-IYNvBgiqwXt4+ePiTa/xSlyhOj4=",
"dev": true,
"requires": {
"ajv": "6.4.0",
@ -12449,13 +12454,13 @@
"commander": {
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
"integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==",
"integrity": "sha1-aWS8pnaF33wfFDDFhPB9dZeIW5w=",
"dev": true
},
"schema-utils": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz",
"integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==",
"integrity": "sha1-IYNvBgiqwXt4+ePiTa/xSlyhOj4=",
"dev": true,
"requires": {
"ajv": "6.4.0",
@ -12465,13 +12470,13 @@
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
"dev": true
},
"uglify-es": {
"version": "3.3.9",
"resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
"integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==",
"integrity": "sha1-DBxPBwC+2NvBJM2zBNJZLKID5nc=",
"dev": true,
"requires": {
"commander": "2.13.0",
@ -12945,7 +12950,7 @@
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
"dev": true
}
}

View file

@ -21,6 +21,7 @@
"vue-template-compiler": "2.4.4"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^5.2.0",
"blueimp-file-upload": "^9.18.0",
"bootstrap": "^3.3.7",
"bootstrap-colorpicker": "^2.5.1",

View file

@ -151,6 +151,17 @@
</div>
</div>
<div class="col-md-4 col-lg-3 col-sm-6 col-xl-1">
<div class="box box-default">
<div class="box-body text-center">
<a href="{{ route('settings.logins.index') }}" class="btn btn-lg btn-white"><i class="fa fa-sign-in fa-3x"></i></a>
<br>
Login Attempts
<p class="help-block">List of logins</p>
</div>
</div>
</div>
<div class="col-md-4 col-lg-3 col-sm-6 col-xl-1">
<div class="box box-default">

View file

@ -0,0 +1,54 @@
@extends('layouts/default')
{{-- Page title --}}
@section('title')
Attempted Logins
@parent
@stop
{{-- Page content --}}
@section('content')
<div class="row">
<div class="col-md-12">
<div class="box box-default">
<div class="box-body">
<table
data-cookie-id-table="loginReport"
data-pagination="true"
data-id-table="loginReport"
data-search="false"
data-side-pagination="server"
data-show-columns="true"
data-show-export="true"
data-show-refresh="true"
data-sort-order="desc"
data-sort-name="created_at"
id="loginReport"
data-url="{{ route('api.settings.login_attempts') }}"
data-mobile-responsive="true"
class="table table-striped snipe-table"
data-export-options='{
"fileName": "login-report-{{ date('Y-m-d') }}"}'>
<thead>
<tr>
<th class="col-sm-2" data-field="username" data-visible="true" data-sortable="true">Username</th>
<th class="col-sm-2" data-field="created_at" data-visible="true" data-sortable="true" data-formatter="dateDisplayFormatter">Login Attempt</th>
<th class="col-sm-2" data-field="user_agent" data-visible="true" data-sortable="true">User Agent</th>
<th class="col-sm-2" data-field="remote_ip" data-visible="true" data-sortable="true">IP</th>
<th class="col-sm-2" data-field="successful" data-visible="true" data-formatter="trueFalseFormatter" data-sortable="true">Success</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
@stop
@section('moar_scripts')
@include ('partials.bootstrap-table')
@stop

View file

@ -186,8 +186,8 @@ img {
.table td {
color: #74787E;
font-size: 15px;
line-height: 18px;
padding: 10px 0;
line-height: 15px;
padding: 8px 0;
}
.content-cell {

View file

@ -555,6 +555,13 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () {
'uses' => 'SettingsController@ldaptest'
]);
Route::get('settings/login-attempts', [
'middleware' => ['auth', 'authorize:superuser'],
'as' => 'api.settings.login_attempts',
'uses' => 'SettingsController@showLoginAttempts'
]);
Route::post('settings/ldaptestlogin', [
'as' => 'api.settings.ldaptestlogin',
'uses' => 'SettingsController@ldaptestlogin'

View file

@ -166,6 +166,8 @@ Route::group([ 'prefix' => 'admin','middleware' => ['auth', 'authorize:superuser
Route::get('purge', ['as' => 'settings.purge.index', 'uses' => 'SettingsController@getPurge']);
Route::post('purge', ['as' => 'settings.purge.save', 'uses' => 'SettingsController@postPurge']);
Route::get('login-attempts', ['as' => 'settings.logins.index','uses' => 'SettingsController@getLoginAttempts' ]);
# Backups
Route::group([ 'prefix' => 'backups', 'middleware' => 'auth' ], function () {