123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- <?php
-
- /*-- TODO ---------------------------//
- Add the JavaScript validation into the display page using the class
- //-----------------------------------*/
-
- // Allow users to reset their password while logged in
- if (!empty($LoggedUser['ID']) && $_REQUEST['act'] != 'recover') {
- header('Location: index.php');
- die();
- }
-
- if (BLOCK_OPERA_MINI && isset($_SERVER['HTTP_X_OPERAMINI_PHONE'])) {
- error('Opera Mini is banned. Please use another browser.');
- }
-
- // Check if IP is banned
- if (Tools::site_ban_ip($_SERVER['REMOTE_ADDR'])) {
- error('Your IP address has been banned.');
- }
-
- require_once SERVER_ROOT.'/classes/twofa.class.php';
- require_once SERVER_ROOT.'/classes/validate.class.php';
-
- $Validate = new VALIDATE;
- $TwoFA = new TwoFactorAuth(SITE_NAME);
-
- if (array_key_exists('action', $_GET) && $_GET['action'] == 'disabled') {
- require('disabled.php');
- die();
- }
-
- if (isset($_REQUEST['act']) && $_REQUEST['act'] == 'recover') {
- // Recover password
- if (!empty($_REQUEST['key'])) {
- // User has entered a new password, use step 2
- $DB->query("
- SELECT
- m.ID,
- m.Email,
- m.ipcc,
- i.ResetExpires
- FROM users_main AS m
- INNER JOIN users_info AS i ON i.UserID = m.ID
- WHERE i.ResetKey = '".db_string($_REQUEST['key'])."'
- AND i.ResetKey != ''");
- list($UserID, $Email, $Country, $Expires) = $DB->next_record();
-
- if (!apc_exists('DBKEY')) {
- error('Database not fully decrypted. Please wait for staff to fix this and try again later');
- }
-
- $Email = DBCrypt::decrypt($Email);
-
- if ($UserID && strtotime($Expires) > time()) {
- // If the user has requested a password change, and his key has not expired
- $Validate->SetFields('password', '1', 'regex', 'You entered an invalid password. Any password at least 6 characters long is accepted, but a strong password is 8 characters or longer, contains at least 1 lowercase and uppercase letter, contains at least a number or symbol', array('regex' => '/(?=^.{6,}$).*$/'));
- $Validate->SetFields('verifypassword', '1', 'compare', 'Your passwords did not match.', array('comparefield' => 'password'));
-
- if (!empty($_REQUEST['password'])) {
- // If the user has entered a password.
- // If the user has not entered a password, $PassWasReset is not set to 1, and the success message is not shown
- $Err = $Validate->ValidateForm($_REQUEST);
- if ($Err == '') {
- // Form validates without error, set new secret and password.
- $DB->query("
- UPDATE
- users_main AS m,
- users_info AS i
- SET
- m.PassHash = '".db_string(Users::make_sec_hash($_REQUEST['password']))."',
- i.ResetKey = '',
- m.LastLogin = NOW(),
- i.ResetExpires = NULL
- WHERE m.ID = '$UserID'
- AND i.UserID = m.ID");
- $DB->query("
- INSERT INTO users_history_passwords
- (UserID, ChangerIP, ChangeTime)
- VALUES
- ('$UserID', '".DBCrypt::encrypt($_SERVER['REMOTE_ADDR'])."', '".sqltime()."')");
- $PassWasReset = true;
- $LoggedUser['ID'] = $UserID; // Set $LoggedUser['ID'] for logout_all_sessions() to work
- logout_all_sessions();
-
- }
- }
-
- // Either a form asking for them to enter the password
- // Or a success message if $PassWasReset is 1
- require('recover_step2.php');
-
- } else {
- // Either his key has expired, or he hasn't requested a pass change at all
- if (strtotime($Expires) < time() && $UserID) {
- // If his key has expired, clear all the reset information
- $DB->query("
- UPDATE users_info
- SET ResetKey = '',
- ResetExpires = NULL
- WHERE UserID = '$UserID'");
- $_SESSION['reseterr'] = 'The link you were given has expired.'; // Error message to display on form
- }
- // Show him the first form (enter email address)
- header('Location: login.php?act=recover');
- }
-
- } // End step 2
-
- // User has not clicked the link in his email, use step 1
- else {
- $Validate->SetFields('email', '1', 'email', 'You entered an invalid email address.');
-
- if (!empty($_REQUEST['email'])) {
- // User has entered email and submitted form
- $Err = $Validate->ValidateForm($_REQUEST);
- if (!apc_exists('DBKEY')) {
- $Err = 'Database not fully decrypted. Please wait for staff to fix this and try again.';
- }
-
- if (!$Err) {
- // Form validates correctly
- $DB->query("
- SELECT
- Email
- FROM users_main");
- while(list($EncEmail) = $DB->next_record()) {
- if (strtolower($_REQUEST['email']) == strtolower(DBCrypt::decrypt($EncEmail))) {
- break; // $EncEmail is now the encrypted form of the given email from the database
- }
- }
-
- $DB->query("
- SELECT
- ID,
- Username,
- Email
- FROM users_main
- WHERE Email = '$EncEmail'");
- list($UserID, $Username, $Email) = $DB->next_record();
- $Email = DBCrypt::decrypt($Email);
-
- if ($UserID) {
- // Email exists in the database
- // Set ResetKey, send out email, and set $Sent to 1 to show success page
- Users::reset_password($UserID, $Username, $Email);
-
- $Sent = 1; // If $Sent is 1, recover_step1.php displays a success message
-
- //Log out all of the users current sessions
- $Cache->delete_value("user_info_$UserID");
- $Cache->delete_value("user_info_heavy_$UserID");
- $Cache->delete_value("user_stats_$UserID");
- $Cache->delete_value("enabled_$UserID");
-
- $DB->query("
- SELECT SessionID
- FROM users_sessions
- WHERE UserID = '$UserID'");
- while (list($SessionID) = $DB->next_record()) {
- $Cache->delete_value("session_$UserID"."_$SessionID");
- }
- $DB->query("
- UPDATE users_sessions
- SET Active = 0
- WHERE UserID = '$UserID'
- AND Active = 1");
- } else {
- $Err = 'There is no user with that email address.';
- }
- }
-
- } elseif (!empty($_SESSION['reseterr'])) {
- // User has not entered email address, and there is an error set in session data
- // This is typically because their key has expired.
- // Stick the error into $Err so recover_step1.php can take care of it
- $Err = $_SESSION['reseterr'];
- unset($_SESSION['reseterr']);
- }
-
- // Either a form for the user's email address, or a success message
- require('recover_step1.php');
- }
-
- } // End password recovery
-
- else if (isset($_REQUEST['act']) && $_REQUEST['act'] == 'newlocation') {
- if (isset($_REQUEST['key'])) {
- if ($ASNCache = $Cache->get_value('new_location_'.$_REQUEST['key'])) {
- $Cache->cache_value('new_location_'.$ASNCache['UserID'].'_'.$ASNCache['ASN'], true);
- require('newlocation.php');
- die();
- } else {
- error(403);
- }
- } else {
- error(403);
- }
- } // End new location
-
- // Normal login
- else {
- $Validate->SetFields('username', true, 'regex', 'You did not enter a valid username.', array('regex' => USERNAME_REGEX));
- $Validate->SetFields('password', '1', 'string', 'You entered an invalid password.', array('minlength' => '6', 'maxlength' => '307200'));
-
- list($Attempts, $Banned) = $Cache->get_value('login_attempts_'.db_string($_SERVER['REMOTE_ADDR']));
-
- // Function to log a user's login attempt
- function log_attempt() {
- global $Cache, $Attempts;
- $Attempts = ($Attempts ?? 0) + 1;
- $Cache->cache_value('login_attempts_'.db_string($_SERVER['REMOTE_ADDR']), array($Attempts, ($Attempts > 5)), 60*60*$Attempts);
- $AllAttempts = $Cache->get_value('login_attempts');
- $AllAttempts[$_SERVER['REMOTE_ADDR']] = time()+(60*60*$Attempts);
- foreach($AllAttempts as $IP => $Time) {
- if ($Time < time()) { unset($AllAttempts[$IP]); }
- }
- $Cache->cache_value('login_attempts', $AllAttempts, 0);
- }
-
- // If user has submitted form
- if (isset($_POST['username']) && !empty($_POST['username']) && isset($_POST['password']) && !empty($_POST['password'])) {
- if ($Banned) {
- header("Location: login.php");
- die();
- }
- $Err = $Validate->ValidateForm($_POST);
-
- if (!$Err) {
- // Passes preliminary validation (username and password "look right")
- $DB->query("
- SELECT
- ID,
- PermissionID,
- CustomPermissions,
- PassHash,
- TwoFactor,
- Enabled
- FROM users_main
- WHERE Username = '".db_string($_POST['username'])."'
- AND Username != ''");
- list($UserID, $PermissionID, $CustomPermissions, $PassHash, $TwoFactor, $Enabled) = $DB->next_record(MYSQLI_NUM, array(2));
- if (!$Banned) {
- if ($UserID && Users::check_password($_POST['password'], $PassHash)) {
- // Update hash if better algorithm available
- if (password_needs_rehash($PassHash, PASSWORD_DEFAULT)) {
- $DB->query("
- UPDATE users_main
- SET PassHash = '".make_sec_hash($_POST['password'])."'
- WHERE Username = '".db_string($_POST['username'])."'");
- }
-
- if (empty($TwoFactor) || $TwoFA->verifyCode($TwoFactor, $_POST['twofa'])) {
- if ($Enabled == 1) {
-
- // Check if the current login attempt is from a location previously logged in from
- if (apc_exists('DBKEY')) {
- $DB->query("
- SELECT IP
- FROM users_history_ips
- WHERE UserID = $UserID");
- $IPs = $DB->to_array(false, MYSQLI_NUM);
- $QueryParts = array();
- foreach ($IPs as $i => $IP) {
- $IPs[$i] = DBCrypt::decrypt($IP[0]);
- }
- $IPs = array_unique($IPs);
- if (count($IPs) > 0) { // Always allow first login
- foreach ($IPs as $IP) {
- $QueryParts[] = "(StartIP<=INET6_ATON('$IP') AND EndIP>=INET6_ATON('$IP'))";
- }
- $DB->query('SELECT ASN FROM geoip_asn WHERE '.implode(' OR ', $QueryParts));
- $PastASNs = array_column($DB->to_array(false, MYSQLI_NUM), 0);
- $DB->query("SELECT ASN FROM geoip_asn WHERE StartIP<=INET6_ATON('$_SERVER[REMOTE_ADDR]') AND EndIP>=INET6_ATON('$_SERVER[REMOTE_ADDR]')");
- list($CurrentASN) = $DB->next_record();
-
- // if we are in DEBUG_MODE, no need to enforce location restriction
- if (!in_array($CurrentASN, $PastASNs) && !DEBUG_MODE) {
- // Never logged in from this location before
- if ($Cache->get_value('new_location_'.$UserID.'_'.$CurrentASN) !== true) {
- $DB->query("
- SELECT
- UserName,
- Email
- FROM users_main
- WHERE ID = $UserID");
- list($Username, $Email) = $DB->next_record();
- Users::auth_location($UserID, $Username, $CurrentASN, DBCrypt::decrypt($Email));
- require('newlocation.php');
- die();
- }
- }
- }
- }
-
- $SessionID = Users::make_secret(64);
- $KeepLogged = ($_POST['keeplogged'] ?? false) ? 1 : 0;
- if (DEBUG_MODE) {
- // allow HTTP (non secure) cookies if running in DEBUG_MODE
- setcookie('session', $SessionID, (time()+60*60*24*365)*$KeepLogged, '/', '', false, true);
- setcookie('userid', $UserID, (time()+60*60*24*365)*$KeepLogged, '/', '', false, true);
- } else {
- setcookie('session', $SessionID, (time()+60*60*24*365)*$KeepLogged, '/', '', true, true);
- setcookie('userid', $UserID, (time()+60*60*24*365)*$KeepLogged, '/', '', true, true);
- }
-
- // Because we <3 our staff
- $Permissions = Permissions::get_permissions($PermissionID);
- $CustomPermissions = unserialize($CustomPermissions);
- if (isset($Permissions['Permissions']['site_disable_ip_history'])
- || isset($CustomPermissions['site_disable_ip_history'])
- ) {
- $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
- }
-
- $DB->query("
- INSERT INTO users_sessions
- (UserID, SessionID, KeepLogged, Browser, OperatingSystem, IP, LastUpdate, FullUA)
- VALUES
- ('$UserID', '".db_string($SessionID)."', '$KeepLogged', '$Browser', '$OperatingSystem', '".db_string(apc_exists('DBKEY')?DBCrypt::encrypt($_SERVER['REMOTE_ADDR']):'0.0.0.0')."', '".sqltime()."', '".db_string($_SERVER['HTTP_USER_AGENT'])."')");
-
- $Cache->begin_transaction("users_sessions_$UserID");
- $Cache->insert_front($SessionID, array(
- 'SessionID' => $SessionID,
- 'Browser' => $Browser,
- 'OperatingSystem' => $OperatingSystem,
- 'IP' => (apc_exists('DBKEY')?DBCrypt::encrypt($_SERVER['REMOTE_ADDR']):'0.0.0.0'),
- 'LastUpdate' => sqltime()
- ));
- $Cache->commit_transaction(0);
-
- $Sql = "
- UPDATE users_main
- SET
- LastLogin = '".sqltime()."',
- LastAccess = '".sqltime()."'
- WHERE ID = '".db_string($UserID)."'";
-
- $DB->query($Sql);
-
- if (!empty($_COOKIE['redirect'])) {
- $URL = $_COOKIE['redirect'];
- setcookie('redirect', '', time() - 60 * 60 * 24, '/', '', false);
- header("Location: $URL");
- die();
- } else {
- header('Location: index.php');
- die();
- }
- } else {
- log_attempt();
- if ($Enabled == 2) {
-
- // Save the username in a cookie for the disabled page
- setcookie('username', db_string($_POST['username']), time() + 60 * 60, '/', '', false);
- header('Location: login.php?action=disabled');
- } elseif ($Enabled == 0) {
- $Err = 'Your account has not been confirmed.<br />Please check your email.';
- }
- setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
- }
- } else {
- log_attempt();
- $Err = 'Two-factor authentication failed.';
- setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
- }
- } else {
- log_attempt();
- $Err = 'Your username or password was incorrect.';
- setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
- }
-
- } else {
- log_attempt();
- setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
- }
-
- } else {
- log_attempt();
- setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
- }
- }
- require('sections/login/login.php');
- }
|