<?php

	class AKB_AUTH {
		/**
		* AKB_AUTH
		*
		* Constructor
		*
		* @return void
		*/
		function AKB_AUTH() {
			// If the user object isnt setup or is the wrong object remake it
			if (!isset($_SESSION['user'])) {
				$_SESSION['user'] = new API_USER();
			} else if (strtolower(get_class($_SESSION['user'])) != 'api_user') {
				$_SESSION['user'] = new API_USER();
			}
		}

		/**
		* HandlePage
		*
		*
		* @return 
		*/		
		function HandlePage() {
			if ((isset($_POST['user'])) && (isset($_POST['pass'])) && (isset($_POST['submit']))) {
				$_POST['username'] = $_POST['user'];
				$this->ProcessFrontendLogin($_POST['user'],$_POST['pass']);
			} else if (isset($_GET['logout'])) {
				$this->LogOut();	
			} else {
				$this->ShowLoginForm();
			}
		}
		
		function ShowLoginForm($message="") {
			$GLOBALS['LoginMessage'] = $message;
			
			$GLOBALS['AKB_CLASS_TEMPLATE']->SetPageTitle(GetLang('hpLogin'));
			$GLOBALS['AKB_CLASS_TEMPLATE']->SetTemplate('Login');
			$GLOBALS['AKB_CLASS_TEMPLATE']->ParseTemplate();
		}
		
		function ProcessFrontendLogin($user,$pass) {
			if(!$this->UserLoginCheck(GetIPAdd(), $GLOBALS['bannedRetried'], $GLOBALS['bannedPeriod'])) {
				unset($_SESSION['user']);
				$minRemain = $GLOBALS['bannedPeriod'];
				if (isset($GLOBALS['ExactMinutesRemain'])) {
					$minRemain = $GLOBALS['ExactMinutesRemain'];
				}
				$this->ShowLoginForm(sprintf(GetLang('UserLoginBlockedMessage'), $GLOBALS['bannedRetried'], $minRemain));
				die();
			}

			$username = trim($user);
			$password = trim($pass);
			
			$remember = false;
			
			//Regenerate the session id before we begin
			//session_regenerate_id(true);			
			
			$_SESSION['user']->find('username', $username);	
			$userId = ($_SESSION['user']->checkPass($password)) ? $_SESSION['user']->userid : 0;
			
			// If this user is not in db or this user is LDAP user
			if (!$userId || API_LDAP::isLdapUser($_SESSION['user']->pass)) {
				// If LDAP authentication is enabled authentication && we have our LDAP Class initialized
				if (isset($GLOBALS['AKB_LDAP']) && $GLOBALS['AKB_LDAP']->getErrorMsg() == null) {
					$userId = API_LDAP::authenticate($username, $password, $userId);
				}
			}
			if ($userId) {
				$this->UserLoginReset(GetIPAdd());
				
				$_SESSION['user']->sessionid = session_id();
				$_SESSION['user']->updateField('sessionid', $_SESSION['user']->sessionid);
				
				if ($remember) {
					setcookie($GLOBALS['cookiePrefix'].'RememberMe',   true, time() + 3600*24*365);
					setcookie($GLOBALS['cookiePrefix'].'RememberUser', $username, time() + 3600*24*365);
					$cookiesLoginPass = md5($password);
					if (strlen($password) == 32) {
						$cookiesLoginPass = $password;
					}
					setcookie($GLOBALS['cookiePrefix'].'RememberPass', $cookiesLoginPass, time() + 3600*24*365);
				}
				
				//Success. Lets attempt to redirect to the prevPage var first.
				if ((isset($_POST['prevPage'])) && (strpos($_POST['prevPage'],$GLOBALS['pathToKB']) !== false)) {
					header("location: ".$_POST['prevPage']);
				} else {
					header("location: ".$GLOBALS['pathToKB']."/index.php");
				}
				
				die();
			} else {
				unset($_SESSION['user']);
				$this->UserLoginLog(GetIPAdd());
				sleep(5);
				$this->ShowLoginForm(GetLang("loginFailed"));
			}			
		}
		
		/**
		* IsLoggedIn
		*
		* Check if a user is logged in or not
		*
		* @return boolean
		*/
		function IsLoggedIn()
		{
			return (isset($_SESSION['user']) && $_SESSION['user']->userid > 0);
		}
		
		/**
		* HasAdminAccess
		*
		* Check if the group the user is in has access to the backend of the system.
		*
		* @return boolean
		*/		
		function HasAdminAccess($groupid=0) {
			if ((!isset($_SESSION['user'])) || (strtolower(get_class($_SESSION['user'])) != "api_user")) {
				return false;
			}
			
			//Special case for admin users.
			if ($_SESSION['user']->userid == 1) {
				return true;
			}
			
			$groups = $_SESSION['user']->groups;
			
			if (!$groups) {
				return false;
			}
			
			$hasAccess = false;
			foreach ($groups as $groupObj) {
				if ((!isset($groupObj->applies['feonly'])) || ((isset($groupObj->applies['feonly'])) && ($groupObj->applies['feonly'] == 0))) {
					$hasAccess = true;
					break;
				}
			}
			
			return $hasAccess;			
		}		
		
		/**
		* GetLoggedInUser
		*
		* Checks if a user is logged in AND returns the user object
		*
		* @return object (user)
		*/		
		function GetLoggedInUser() {
			return (AKB_AUTH::IsLoggedIn()) ? $_SESSION['user'] : false;
		}
		
		/**
		* GetUserGroupIDs
		*
		* Returns an array of user groups from the logged in user.
		*
		* @return object (user)
		*/		
		function GetUserGroupIDs() {
			$groupArray = array();
			if ($userObj =  AKB_AUTH::GetLoggedInUser()) {
				if ($userObj->userid == 1) {
					//Special case if we're dealing with the admin
					$go = new API_GROUP();
					$tempGroup = $go->getList();
					
					foreach ($tempGroup as $groupid=>$val) {
						$groupArray[] = $groupid;
					}
					
				} else {
					if ($userObj->groups) {
						foreach ($userObj->groups as $val) {
							$groupArray[] = $val->groupid;
						}
					}
				}
				
			}
			
			return $groupArray;
		}
		
		/**
		* deriveGroupSQL
		*
		* This function has a lot to do permissions wise. All frontend
		*
		*
		* @var force_question_auth:
		*	If true then this function will check question permissions no matter what. If false
		* 	then it will take the categoryRestrictOption into account and decide that way.
		*
		* @return 
		*/			
		function deriveGroupSQL($force_question_auth=true) {
			
			$userSQL = "";
			if (AKB_AUTH::IsLoggedIn()) {
				$userGroups = AKB_AUTH::GetUserGroupIDs();
				
				if ($userGroups) {
					$userObj = AKB_AUTH::GetLoggedInUser();
				
					if ($userObj->userid == 1) {
						//Special Case for super user.
						$userSQL = "OR (qa.groupid IS NOT NULL) ";
					} else {
						if ($force_question_auth) {
							$userSQL = "OR qa.groupid IN('".implode("', '",$userGroups)."')";
						} else {
							if (isset($GLOBALS['categoryRestrictOption']) && $GLOBALS['categoryRestrictOption'] == "1") {
								//Restrict based on the restrict option
								$userSQL = "OR qa.groupid IN('".implode("', '",$userGroups)."')";
							} else {
								$userSQL = "OR (qa.groupid IS NOT NULL) ";
							}
						}
					}
					
				}
			} else {
				if (isset($GLOBALS['categoryRestrictOption']) && ($GLOBALS['categoryRestrictOption'] == "0") && (!$force_question_auth)) {
					//User is not logged in AND the restrict option is 0 (which means what we display the question anyway) AND the particular
					//calling place has said that we dont want to force question auth.
					$userSQL = "OR (qa.groupid IS NOT NULL) ";
				}
			}
			
			return $userSQL;
		}
		
		/**
		* LogOut
		*
		* Kill the session auth variable and redirect the user to the login page
		*
		* @return void
		*/
		function LogOut()
		{
			unset($_SESSION['user']);

			// Set the cookies to a time in the past
			setcookie($GLOBALS['cookiePrefix'].'RememberMe', '', time() - 3600*24*365);
			setcookie($GLOBALS['cookiePrefix'].'RememberUser', '', time() - 3600*24*365);
			setcookie($GLOBALS['cookiePrefix'].'RememberPass', '', time() - 3600*24*365);

			if (isset($_COOKIE[session_name()])) {
				setcookie(session_name(), '', time()-42000, '/');
			}

			session_destroy();
			
			$referrer = @$_SERVER['HTTP_REFERER'];
			
			if (($referrer != "") && (strpos($referrer,$GLOBALS['pathToKB']) !== false)) {
				header("location: ".$referrer);
			} else {
				header("location: ".$GLOBALS['pathToKB']."/index.php");
			}

			die();
		}		
		
		/**
		* isAccessibleQuestion
		* DEPRECATED
		*
		* @return 
		*/
		function isAccessibleQuestion($questionid,$groupid) {
			$SQL = "
				SELECT questionid
				FROM ".$GLOBALS['tablePrefix']."question_auth
				WHERE
					questionid = ".(int)$questionid."
					AND
					groupid = ".$groupid."
			";
		}
		

		/**
		* HasApprovalAccess
		*
		* Check if the group the user is in has access to the backend of the system.
		* 
		* @param array $categories An array of category ids
		* @param boolean $editMode Are we in editing article mode?
		*
		* @return boolean
		*/
		function HasApprovalAccess($categories, $editMode = true) {
			
			if ((!isset($_SESSION['user'])) || (strtolower(get_class($_SESSION['user'])) != "api_user")) {
				return false;
			}

			//Special case for admin users.
			if ($_SESSION['user']->userid == 1) {
				return true;
			}
			
			if (!is_array($categories)) {
				return false;
			}
			
			if (is_array($_SESSION['user']->groups) && !empty($_SESSION['user']->groups)) {
				foreach ($_SESSION['user']->groups as $group) {
					if (isset($group->applies['category'])) {
						if (((isset($group->perms['category']['approve']) && $group->perms['category']['approve']) && ((is_array($group->applies['category']) && array_intersect($categories, $group->applies['category'])) || $group->applies['category'] == 'all')) && $group->applies['feonly'] != '1') {
							return true;
						}
					}
				}
			}
			
			// check if all the categories need any permission?
			// if not then return true.
			$catIds = "'" . implode("','", $categories) . "'";
			$query = sprintf("SELECT COUNT(categoryid) as num from %scategories where categoryid IN (%s) AND (approvaltype = '%d'", $GLOBALS['tablePrefix'], $catIds, CATEGORIES_NO_APPROVAL);
			if ($editMode) {
				$query .= sprintf(" OR approvaltype = '%d' ", CATEGORIES_ONCE_APPROVAL);
			}
			$query .= " ) ";
			$restriction = $GLOBALS['AKB_DB']->FetchOne($query);
			
			if ($restriction > 0) {
				return true;
			}
			return false;
		}
		

		function UserLoginLog($ipaddress) {
			if (!isset($GLOBALS['enabledLoginSecurity']) || !$GLOBALS['enabledLoginSecurity']) {
				return true;
			}
			if ($ipaddress != '') {
			$query = sprintf("SELECT attemptnum FROM %suserlogin WHERE ipaddress = '%s' ", $GLOBALS['tablePrefix'], $ipaddress);
			$result = $GLOBALS['AKB_DB']->Query($query);

				// if the ipaddress exist?
				if($row = $GLOBALS['AKB_DB']->Fetch($result)) {
					// increase the attempted number
					$query = sprintf("UPDATE %suserlogin SET attemptnum = '%d', tslogin = '%s' WHERE ipaddress = '%s' ", $GLOBALS['tablePrefix'], (int)$row['attemptnum']+1, date("Y-m-d H:i:s"), $ipaddress);
					$GLOBALS['AKB_DB']->Query($query);
				} else {
					// else insert a new one
					$query = sprintf("INSERT INTO %suserlogin VALUES ('%s', '%d', '%s')", $GLOBALS['tablePrefix'], $ipaddress, 1, date("Y-m-d H:i:s"));
					$GLOBALS['AKB_DB']->Query($query);
				}
				return true;
			}
			return false;
		}

		function UserLoginReset($ipaddress) {
			if (!isset($GLOBALS['enabledLoginSecurity']) || !$GLOBALS['enabledLoginSecurity']) {
				return true;
			}
			// delete all the records from the $ipaddress
			$query = sprintf("DELETE FROM %suserlogin WHERE ipaddress = '%s' ", $GLOBALS['tablePrefix'], $ipaddress);
			return $GLOBALS['AKB_DB']->Query($query);
		}
		
		function UserLoginCheck($ipaddress, $attemptnum, $min = 5) {
			if (!isset($GLOBALS['enabledLoginSecurity']) || !$GLOBALS['enabledLoginSecurity']) {
				return true;
			}
			$now = date("Y-m-d H:i:s", mktime(date("H"), date("i")-$min, date("s"), date("m")  , date("d"), date("Y")));
			$query = sprintf("SELECT attemptnum, tslogin FROM %suserlogin WHERE ipaddress = '%s' AND attemptnum >= '%d' AND tslogin >= '%s'", $GLOBALS['tablePrefix'], $ipaddress, (int)$attemptnum, $now);
			$result = $GLOBALS['AKB_DB']->Query($query);

			
			// if attemptnum is same or greater than $attemptnum AND the ipaddress is matched.
			if(!$row = $GLOBALS['AKB_DB']->Fetch($result)) {
				$query = sprintf("SELECT attemptnum FROM %suserlogin WHERE ipaddress = '%s' AND attemptnum >= '%d' AND tslogin < '%s'", $GLOBALS['tablePrefix'], $ipaddress, (int)$attemptnum, $now);
				$result = $GLOBALS['AKB_DB']->Query($query);
				if($row = $GLOBALS['AKB_DB']->Fetch($result)) {
					$this->UserLoginReset(GetIPAdd());
				}
				return true;
			}
			$GLOBALS['loginBlocked'] = 1;
			$GLOBALS['ExactMinutesRemain'] = ceil((strtotime($row['tslogin'])-mktime(date("H"), date("i")-$min, date("s"), date("m")  , date("d"), date("Y")))/60);
			return false;
		}

		
	}