Prechádzať zdrojové kódy

Added login lockout feature
Added default options for Login Attemps and Login Lockout seconds
Added login attempts variable to login API and login form
Added new cookie function for seconds

CauseFX 7 rokov pred
rodič
commit
1234929a03

+ 3 - 1
api/config/default.php

@@ -224,5 +224,7 @@ return array(
 	'description' => 'Organizr - Accept no others',
 	'debugErrors' => false,
 	'healthChecksURL' => 'https://healthchecks.io/api/v1/checks/',
-	'gaTrackingID' => ''
+	'gaTrackingID' => '',
+	'loginAttempts' => '3',
+	'loginLockout' => '60000'
 );

+ 9 - 0
api/functions/api-functions.php

@@ -31,6 +31,10 @@ function apiLogin()
 				'name' => 'tfaCode',
 				'value' => (isset($_POST['tfaCode'])) ? $_POST['tfaCode'] : false
 			),
+			array(
+				'name' => 'loginAttempts',
+				'value' => (isset($_POST['loginAttempts'])) ? $_POST['loginAttempts'] : false
+			),
 			array(
 				'name' => 'output',
 				'value' => true
@@ -74,6 +78,11 @@ function login($array)
 	$days = (isset($remember)) ? $GLOBALS['rememberMeDays'] : 1;
 	$oAuth = (isset($oAuth)) ? $oAuth : false;
 	$output = (isset($output)) ? $output : false;
+	$loginAttempts = (isset($loginAttempts)) ? $loginAttempts : false;
+	if($loginAttempts > $GLOBALS['loginAttempts']){
+		coookieSeconds('set', 'lockout', $GLOBALS['loginLockout'], $GLOBALS['loginLockout']);
+		return 'lockout';
+	}
 	try {
 		$database = new Dibi\Connection([
 			'driver' => 'sqlite3',

+ 49 - 0
api/functions/normal-functions.php

@@ -126,6 +126,55 @@ function coookie($type, $name, $value = '', $days = -1, $http = true)
 	}
 }
 
+function coookieSeconds($type, $name, $value = '', $ms, $http = true)
+{
+	if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == "https") {
+		$Secure = true;
+		$HTTPOnly = true;
+	} elseif (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' && $_SERVER['HTTPS'] !== '') {
+		$Secure = true;
+		$HTTPOnly = true;
+	} else {
+		$Secure = false;
+		$HTTPOnly = false;
+	}
+	if (!$http) {
+		$HTTPOnly = false;
+	}
+	$Path = '/';
+	$Domain = parseDomain($_SERVER['HTTP_HOST']);
+	$DomainTest = parseDomain($_SERVER['HTTP_HOST'], true);
+	if ($type == 'set') {
+		$_COOKIE[$name] = $value;
+		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
+			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + ($ms / 1000)) . ' GMT')
+			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($Domain) ? '' : '; domain=' . $Domain)
+			. (!$Secure ? '' : '; secure')
+			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
+		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
+			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() + ($ms / 1000)) . ' GMT')
+			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
+			. (!$Secure ? '' : '; secure')
+			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
+	} elseif ($type == 'delete') {
+		unset($_COOKIE[$name]);
+		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
+			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
+			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($Domain) ? '' : '; domain=' . $Domain)
+			. (!$Secure ? '' : '; secure')
+			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
+		header('Set-Cookie: ' . rawurlencode($name) . '=' . rawurlencode($value)
+			. (empty($ms) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', time() - 3600) . ' GMT')
+			. (empty($Path) ? '' : '; path=' . $Path)
+			. (empty($Domain) ? '' : '; domain=' . $DomainTest)
+			. (!$Secure ? '' : '; secure')
+			. (!$HTTPOnly ? '' : '; HttpOnly'), false);
+	}
+}
+
 function getOS()
 {
 	if (PHP_SHLIB_SUFFIX == "dll") {

+ 14 - 0
api/functions/organizr-functions.php

@@ -708,6 +708,20 @@ function getSettingsMain()
 			)*/
 		),
 		'Security' => array(
+			array(
+				'type' => 'number',
+				'name' => 'loginAttempts',
+				'label' => 'Max Login Attempts',
+				'value' => $GLOBALS['loginAttempts'],
+				'placeholder' => ''
+			),
+			array(
+				'type' => 'select',
+				'name' => 'loginLockout',
+				'label' => 'Login Lockout Seconds',
+				'value' => $GLOBALS['loginLockout'],
+				'options' => optionTime()
+			),
 			array(
 				'type' => 'number',
 				'name' => 'lockoutTimeout',

+ 1 - 0
api/pages/login.php

@@ -13,6 +13,7 @@ if(activeInfo.settings.login.rememberMe){
   <div class="login-box login-sidebar animated slideInRight">
     <div class="white-box">
       <form class="form-horizontal" id="loginform" onsubmit="return false;">
+      	<input id="login-attempts" class="form-control" name="loginAttempts" type="hidden">
         <a href="javascript:void(0)" class="text-center db visible-xs" id="login-logo">' . logoOrText() . '</a>
         <div id="oAuth-div" class="form-group hidden">
           <div class="col-xs-12">

+ 15 - 0
js/custom.js

@@ -2,6 +2,7 @@
 /*global $, jQuery, alert*/
 var idleTime = 0;
 var hasCookie = false;
+var loginAttempts = 0;
 $(document).ajaxComplete(function () {
     pageLoad();
     //new SimpleBar($('.internal-listing')[0]);
@@ -337,6 +338,8 @@ function doneTypingMediaSearch () {
 }
 $(document).on("click", ".login-button", function(e) {
     e.preventDefault;
+    loginAttempts = loginAttempts + 1;
+    $('#login-attempts').val(loginAttempts);
     var check = (local('g','loggingIn'));
     if(check == null) {
         local('s','loggingIn', true);
@@ -358,6 +361,18 @@ $(document).on("click", ".login-button", function(e) {
                 $('div.login-box').unblock({});
                 message('Login Error', ' Wrong username/email/password combo', activeInfo.settings.notifications.position, '#FFF', 'warning', '10000');
                 console.error('Organizr Function: Login failed - wrong username/email/password');
+            } else if (html.data == 'lockout') {
+                $('div.login-box').block({
+                    message: '<h5><i class="fa fa-close"></i> Locked Out!</h4>',
+                    css: {
+                        color: '#fff',
+                        border: '1px solid #e91e63',
+                        backgroundColor: '#f44336'
+                    }
+                });
+                message('Login Error', ' You have been Locked out', activeInfo.settings.notifications.position, '#FFF', 'error', '10000');
+                console.error('Organizr Function: Login failed - User has been locked out');
+                setTimeout(function(){ local('r','loggingIn'); location.reload() }, 10000);
             } else if (html.data == '2FA') {
                 $('div.login-box').unblock({});
                 $('#tfa-div').removeClass('hidden');

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
js/custom.min.js


+ 13 - 0
js/functions.js

@@ -7003,6 +7003,19 @@ function launch(){
                     getPingList(json);
                 }
                 loadCustomJava(json.appearance);
+                if(getCookie('lockout')){
+                    setTimeout(function(){
+                        $('div.login-box').block({
+                            message: '<h5><i class="fa fa-close"></i> Locked Out!</h4>',
+                            css: {
+                                color: '#fff',
+                                border: '1px solid #e91e63',
+                                backgroundColor: '#f44336'
+                            }
+                        });
+                    }, 1000);
+                    setTimeout(function(){ location.reload() }, 60000);
+                }
 				break;
 			default:
 				console.error('Organizr Function: Action not set or defined');

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov