0,'granted'=>''); // 'editing' will be set EditingValue() $userinfo = $users[$username]; //Check Attempts if( $userinfo['attempts'] >= 5 ){ $timeDiff = (time() - $userinfo['lastattempt'])/60; //minutes if( $timeDiff < 10 ){ msg($langmessage['LOGIN_BLOCK'],ceil(10-$timeDiff)); return false; } } //check against password sent to a user's email address from the forgot_password form $passed = self::PasswordPassed($userinfo,$nonce); //if passwords don't match if( $passed !== true ){ self::IncorrectLogin('2'); self::UpdateAttempts($users,$username); return false; } //will be saved in UpdateAttempts if( isset($userinfo['newpass']) ){ unset($userinfo['newpass']); } $session_id = self::create($userinfo, $username, $sessions); if( !$session_id ){ msg($langmessage['OOPS'].' (Data Not Saved)'); self::UpdateAttempts($users,$username,true); return false; } $logged_in = self::start($session_id,$sessions); if( $logged_in === true ){ msg($langmessage['logged_in']); } //need to save the user info regardless of success or not //also saves file_name in users.php $users[$username] = $userinfo; self::UpdateAttempts($users,$username,true); //redirect to prevent resubmission self::Redirect($logged_in); } /** * Redirect user after login * */ public static function Redirect($logged_in){ global $gp_index; if( !$logged_in ){ return; } $redirect = false; if( isset($_REQUEST['file']) ){ $redirect = \gp\tool::ArrayKey($_REQUEST['file'], $gp_index ); } if( $redirect === false ){ $redirect = 'Admin'; } $url = \gp\tool::GetUrl($redirect,'',false); \gp\tool::Redirect($url); } /** * Return the username for the login request * */ public static function GetLoginUser( $users, $nonce ){ $_POST += array('user_sha'=>'','username'=>'','login_nonce'=>''); if( gp_require_encrypt && empty($_POST['user_sha']) ){ return false; } foreach($users as $username => $info){ $sha_user = sha1($nonce.$username); if( !gp_require_encrypt && !empty($_POST['username']) && $_POST['username'] == $username ){ return $username; } if( $sha_user === $_POST['user_sha'] ){ return $username; } } return false; } /** * Check the posted password * Check against reset password if set * */ public static function PasswordPassed( &$userinfo, $nonce ){ if( gp_require_encrypt && !empty($_POST['password']) ){ return false; } //if not encrypted with js if( !empty($_POST['password']) ){ $_POST['pass_md5'] = sha1($nonce.md5($_POST['password'])); $_POST['pass_sha'] = sha1($nonce.sha1($_POST['password'])); $_POST['pass_sha512'] = \gp\tool::hash($_POST['password'],'sha512',50); } $pass_algo = self::PassAlgo($userinfo); if( !empty($userinfo['newpass']) && self::CheckPassword($userinfo['newpass'],$nonce,$pass_algo) ){ $userinfo['password'] = $userinfo['newpass']; return true; } //check password if( self::CheckPassword($userinfo['password'],$nonce,$pass_algo) ){ return true; } return false; } /** * Return the algorithm used by the user for passwords * */ public static function PassAlgo($userinfo){ global $config; if( isset($userinfo['passhash']) ){ return $userinfo['passhash']; } return $config['passhash']; } /** * Check password, choose between plaintext, md5 encrypted or sha-1 encrypted * @param string $user_pass * @param string $nonce * @param string $pass_algo Password hashing algorithm * */ public static function CheckPassword( $user_pass, $nonce, $pass_algo ){ global $config; $posted_pass = false; switch($pass_algo){ case 'md5': $posted_pass = $_POST['pass_md5']; $user_pass = sha1($nonce.$user_pass); break; case 'sha1': $posted_pass = $_POST['pass_sha']; $user_pass = sha1($nonce.$user_pass); break; case 'sha512': //javascript only loops through sha512 50 times $posted_pass = \gp\tool::hash($_POST['pass_sha512'],'sha512',950); break; case 'password_hash': if( !function_exists('password_verify') ){ msg('This version of PHP does not have password_verify(). To fix, reset your password at /Admin_Preferences and select "sha512" for the "Password Algorithm"'); return false; } return password_verify($_POST['pass_sha512'],$user_pass); } if( $posted_pass && $posted_pass === $user_pass ){ return true; } return false; } public static function IncorrectLogin($i){ global $langmessage; msg($langmessage['incorrect_login'].' ('.$i.')'); $url = \gp\tool::GetUrl('Admin','cmd=forgotten'); msg($langmessage['forgotten_password'],$url); } /** * Set the value of $userinfo['file_name'] * */ public static function SetSessionFileName($userinfo,$username){ global $dataDir; if( isset($userinfo['file_name']) ){ return $userinfo; } do{ $new_file_name = 'gpsess_'.\gp\tool::RandomString(40).'.php'; $new_file = $dataDir.'/data/_sessions/'.$new_file_name; }while( \gp\tool\Files::Exists($new_file) ); $userinfo['file_name'] = $new_file_name; return $userinfo; } public static function LogOut(){ global $langmessage; if( !isset($_COOKIE[gp_session_cookie]) ){ return false; } $session_id = $_COOKIE[gp_session_cookie]; self::Unlock($session_id); self::cookie(gp_session_cookie); self::CleanSession($session_id); msg($langmessage['LOGGED_OUT']); } /** * Remove the admin session lock * */ public static function Unlock($session_id){ \gp\tool\Files::Unlock('admin',sha1(sha1($session_id))); } public static function CleanSession($session_id){ //remove the session_id from session_ids.php $sessions = self::GetSessionIds(); unset($sessions[$session_id]); self::SaveSessionIds($sessions); } /** * Set a session cookie * Attempt to use httponly if available * */ public static function cookie($name,$value='',$expires = false){ global $dirPrefix; $cookiePath = empty($dirPrefix) ? '/' : $dirPrefix; $cookiePath = \gp\tool::HrefEncode($cookiePath,false); $secure = (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ); $domain = \gp\tool::ServerName(true); if( !$domain || strpos($domain,'.') === false ){ $domain = ''; } if( strpos($domain,':') !== false ){ $domain = substr($domain, 0, strrpos($domain, ':')); } // expire if value is empty // cookies are set with either www removed from the domain or with an empty string if( empty($value) ){ $expires = time()-2592000; if( $domain ){ setcookie($name, $value, $expires, $cookiePath, $domain , $secure , true); setcookie($name, $value, $expires, $cookiePath, $domain , false , true); } setcookie($name, $value, $expires, $cookiePath, '' , $secure , true); setcookie($name, $value, $expires, $cookiePath, '' , false , true); return; } // get expiration and set if( $expires === false ){ $expires = time()+2592000; //30 days }elseif( $expires === true ){ $expires = 0; //expire at end of session } setcookie($name, $value, $expires, $cookiePath, $domain, $secure, true); } /** * Update the number of login attempts and the time of the last attempt for a $username * */ public static function UpdateAttempts($users,$username,$reset = false){ if( $reset ){ $users[$username]['attempts'] = 0; }else{ $users[$username]['attempts']++; } $users[$username]['lastattempt'] = time(); \gp\tool\Files::SaveData('_site/users','users',$users); } //called when a user logs in public static function create( &$user_info, $username, &$sessions ){ global $dataDir, $langmessage; //update the session files to .php files //changes to $userinfo will be saved by UpdateAttempts() below $user_info = self::SetSessionFileName($user_info,$username); $user_file_name = $user_info['file_name']; $user_file = $dataDir.'/data/_sessions/'.$user_file_name; //use an existing session_id if the new login matches an existing session (uid and file_name) $sessions = self::GetSessionIds(); $uid = self::auth_browseruid(); $session_id = false; foreach($sessions as $sess_temp_id => $sess_temp_info){ if( isset($sess_temp_info['uid']) && $sess_temp_info['uid'] == $uid && $sess_temp_info['file_name'] == $user_file_name ){ $session_id = $sess_temp_id; } } //create a unique session id if needed if( $session_id === false ){ do{ $session_id = \gp\tool::RandomString(40); }while( isset($sessions[$session_id]) ); } $expires = !isset($_POST['remember']); self::cookie(gp_session_cookie,$session_id,$expires); //save session id $sessions[$session_id] = array(); $sessions[$session_id]['file_name'] = $user_file_name; $sessions[$session_id]['uid'] = $uid; //$sessions[$session_id]['time'] = time(); //for session locking if( !self::SaveSessionIds($sessions) ){ return false; } //make sure the user's file exists $new_data = self::SessionData($user_file,$checksum); $new_data['username'] = $username; $new_data['granted'] = $user_info['granted']; if( isset($user_info['editing']) ){ $new_data['editing'] = $user_info['editing']; } \gp\admin\Tools::EditingValue($new_data); // may needt to extend the cookie life later if( isset($_POST['remember']) ){ $new_data['remember'] = time(); }else{ unset($new_data['remember']); } \gp\tool\Files::SaveData($user_file,'gpAdmin',$new_data); return $session_id; } /** * Return the contents of the session_ids.php data file * @return array array of all sessions */ public static function GetSessionIds(){ return \gp\tool\Files::Get('_site/session_ids','sessions'); } /** * Save $sessions to the session_ids.php data file * @param $sessions array array of all sessions * @return bool */ public static function SaveSessionIds($sessions){ while( $current = current($sessions) ){ $key = key($sessions); //delete if older than if( isset($current['time']) && $current['time'] > 0 && ($current['time'] < (time() - 1209600)) ){ //if( $current['time'] < time() - 2592000 ){ //one month unset($sessions[$key]); $continue = true; }else{ next($sessions); } } //clean return \gp\tool\Files::SaveData('_site/session_ids','sessions',$sessions); } /** * Determine if $session_id represents a valid session and if so start the session * */ public static function start($session_id, $sessions = false ){ global $langmessage, $dataDir, $wbMessageBuffer; static $locked_message = false; //get the session file if( !$sessions ){ $sessions = self::GetSessionIds(); if( !isset($sessions[$session_id]) ){ self::cookie(gp_session_cookie); //make sure the cookie is deleted msg($langmessage['Session Expired'].' (timeout)'); return false; } } $sess_info = $sessions[$session_id]; //check ~ip, ~user agent ... if( gp_browser_auth && !empty($sess_info['uid']) ){ $auth_uid = self::auth_browseruid(); $auth_uid_legacy = self::auth_browseruid(true); //legacy option added to prevent logging users out, added 2.0b2 if( ($sess_info['uid'] != $auth_uid) && ($sess_info['uid'] != $auth_uid_legacy) ){ self::cookie(gp_session_cookie); //make sure the cookie is deleted msg($langmessage['Session Expired'].' (browser auth)'); return false; } } $session_file = $dataDir.'/data/_sessions/'.$sess_info['file_name']; if( ($session_file === false) || !\gp\tool\Files::Exists($session_file) ){ self::cookie(gp_session_cookie); //make sure the cookie is deleted msg($langmessage['Session Expired'].' (invalid)'); return false; } //prevent browser caching when editing Header( 'Last-Modified: ' . gmdate( 'D, j M Y H:i:s' ) . ' GMT' ); Header( 'Expires: ' . gmdate( 'D, j M Y H:i:s', time() ) . ' GMT' ); Header( 'Cache-Control: no-store, no-cache, must-revalidate'); // HTTP/1.1 Header( 'Cache-Control: post-check=0, pre-check=0', false ); Header( 'Pragma: no-cache' ); // HTTP/1.0 $GLOBALS['gpAdmin'] = self::SessionData($session_file,$checksum); //lock to prevent conflicting edits if( gp_lock_time > 0 && ( !empty($GLOBALS['gpAdmin']['editing']) || !empty($GLOBALS['gpAdmin']['granted']) ) ){ $expires = gp_lock_time; if( !\gp\tool\Files::Lock('admin',sha1(sha1($session_id)),$expires) ){ msg( $langmessage['site_locked'].' '.sprintf($langmessage['lock_expires_in'],ceil($expires/60)) ); $locked_message = true; $GLOBALS['gpAdmin']['locked'] = true; }else{ unset($GLOBALS['gpAdmin']['locked']); } } //extend cookie? if( isset($GLOBALS['gpAdmin']['remember']) ){ $elapsed = time() - $GLOBALS['gpAdmin']['remember']; if( $elapsed > 604800 ){ //7 days $GLOBALS['gpAdmin']['remember'] = time(); self::cookie(gp_session_cookie,$session_id); } } register_shutdown_function(array('\\gp\\tool\\Session','close'),$session_file,$checksum); self::SaveSetting(); //make sure forms have admin nonce ob_start(array('\\gp\\tool\\Session','AdminBuffer')); \gp\tool\Output::$lang_values += array( 'cancel' => 'ca', 'update' => 'up', 'caption' => 'cp', 'Width' => 'Width', 'Height' => 'Height', 'save' => 'Save', 'Saved' => 'Saved', 'Saving' => 'Saving', 'Close' => 'Close', 'Page' => 'Page', 'theme_content' => 'Extra', 'Publish Draft' => 'Draft', 'Publish' => 'Publish', 'Select Image' => 'SelectImage', 'edit' => 'edit', 'options' => 'options', 'Copy' => 'Copy', 'Copy to Clipboard' => 'CopyToClipboard', 'Available Classes' => 'AvailableClasses', 'Visibility' => 'Visibility', 'remove' => 'remove', 'delete' => 'del', 'Section %s' => 'Section', 'generic_delete_confirm' => 'generic_delete_confirm', ); \gp\tool::LoadComponents('sortable,autocomplete,gp-admin,gp-admin-css,fontawesome'); \gp\admin\Tools::VersionsAndCheckTime(); \gp\tool\Output::$inline_vars += array( 'gpRem' => \gp\admin\Tools::CanRemoteInstall(), ); //prepend messages from message buffer if( isset($GLOBALS['gpAdmin']['message_buffer']) && count($GLOBALS['gpAdmin']['message_buffer']) ){ $wbMessageBuffer = array_merge($GLOBALS['gpAdmin']['message_buffer'],$wbMessageBuffer); unset($GLOBALS['gpAdmin']['message_buffer']); } //alias if( isset($_COOKIE['gp_alias']) ){ $GLOBALS['gpAdmin']['useralias'] = $_COOKIE['gp_alias']; }else{ $GLOBALS['gpAdmin']['useralias'] = $GLOBALS['gpAdmin']['username']; } return true; } /** * Perform admin only changes to the content buffer * This will happen before \gp\tool\Output::BufferOut() * */ public static function AdminBuffer($buffer){ global $wbErrorBuffer, $gp_admin_html; //add $gp_admin_html to the document if( strpos($buffer,'') !== false ){ $buffer = \gp\tool\Output::AddToBody($buffer, '