소스 검색

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 6 년 전
부모
커밋
1234929a03
8개의 변경된 파일104개의 추가작업 그리고 1개의 파일을 삭제
  1. 3 1
      api/config/default.php
  2. 9 0
      api/functions/api-functions.php
  3. 49 0
      api/functions/normal-functions.php
  4. 14 0
      api/functions/organizr-functions.php
  5. 1 0
      api/pages/login.php
  6. 15 0
      js/custom.js
  7. 0 0
      js/custom.min.js
  8. 13 0
      js/functions.js

+ 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');

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 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');

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.