mirror of
				https://github.com/Alamantus/Lexiconga.git
				synced 2025-11-04 02:07:05 +01:00 
			
		
		
		
	Start writing password reset
This commit is contained in:
		
							parent
							
								
									1735c00d53
								
							
						
					
					
						commit
						f112e3b143
					
				
					 4 changed files with 168 additions and 0 deletions
				
			
		
							
								
								
									
										59
									
								
								src/js/account/passwordReset.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/js/account/passwordReset.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
import { setupInfoModal } from "../setupListeners";
 | 
			
		||||
import { request } from "./helpers";
 | 
			
		||||
 | 
			
		||||
export function renderForgotPasswordForm() {
 | 
			
		||||
  const modal = document.createElement('section');
 | 
			
		||||
  modal.classList.add('modal');
 | 
			
		||||
  modal.innerHTML = `<div class="modal-background"></div>
 | 
			
		||||
  <div class="modal-content">
 | 
			
		||||
    <a class="close-button">×︎</a>
 | 
			
		||||
    <section class="info-modal" id="forgotPasswordForm">
 | 
			
		||||
      <h2>Forgot Password</h2>
 | 
			
		||||
      <p>Enter the email address associated with your Lexiconga account to initiate a password reset.</p>
 | 
			
		||||
      <label>Email<br>
 | 
			
		||||
        <input type="email" id="forgotPasswordEmailField" style="max-width:250px;" maxlength="100">
 | 
			
		||||
      </label>
 | 
			
		||||
      <section id="forgotPasswordErrorMessages"></section>
 | 
			
		||||
      <button class="button" id="forgotPasswordSubmit">Email Password Reset Key</button>
 | 
			
		||||
    </section>
 | 
			
		||||
  </div>`;
 | 
			
		||||
 | 
			
		||||
  document.body.appendChild(modal);
 | 
			
		||||
 | 
			
		||||
  setupStartResetForm();
 | 
			
		||||
  setupInfoModal(modal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setupStartResetForm() {
 | 
			
		||||
  document.getElementById('forgotPasswordSubmit').addEventListener('click', sendPasswordReset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sendPasswordReset() {
 | 
			
		||||
  const email = document.getElementById('forgotPasswordEmailField').value.trim();
 | 
			
		||||
  const errorMessageElement = document.getElementById('forgotPasswordErrorMessages');
 | 
			
		||||
  let errorMessage = '';
 | 
			
		||||
  
 | 
			
		||||
  if (email === '') {
 | 
			
		||||
    errorMessage += '<p class="red bold">Please enter an email address.</p>';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  errorMessageElement.innerHTML = errorMessage;
 | 
			
		||||
 | 
			
		||||
  if (errorMessage === '') {
 | 
			
		||||
    request({
 | 
			
		||||
      action: 'initiate-password-reset',
 | 
			
		||||
      email,
 | 
			
		||||
    }, success => {
 | 
			
		||||
      console.log(success);
 | 
			
		||||
    }, error => {
 | 
			
		||||
      errorMessage += '<p class="red bold">' + error + '</p>';
 | 
			
		||||
    }).then(() => {
 | 
			
		||||
      errorMessageElement.innerHTML = errorMessage;
 | 
			
		||||
      if (errorMessage === '') {
 | 
			
		||||
        document.getElementById('forgotPasswordForm').innerHTML = `<h2>Password Reset Key Sent</h2>
 | 
			
		||||
        <p>Go check your email for the password reset link.</p>
 | 
			
		||||
        <p><em>Note that it may be sent to your spam/junk folder by mistake.</em></p>`;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ import { logIn, createAccount } from "./login";
 | 
			
		|||
import { setCookie } from "../StackOverflow/cookie";
 | 
			
		||||
import { changeDictionary, createNewDictionary } from "./dictionaryManagement";
 | 
			
		||||
import { addMessage } from "../utilities";
 | 
			
		||||
import { renderForgotPasswordForm } from "./passwordReset";
 | 
			
		||||
 | 
			
		||||
export function setupLoginModal(modal) {
 | 
			
		||||
  const closeElements = modal.querySelectorAll('.modal-background, .close-button');
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +37,7 @@ export function setupLoginModal(modal) {
 | 
			
		|||
  });
 | 
			
		||||
 | 
			
		||||
  document.getElementById('loginSubmit').addEventListener('click', logIn);
 | 
			
		||||
  document.getElementById('forgotPasswordButton').addEventListener('click', renderForgotPasswordForm);
 | 
			
		||||
  document.getElementById('createAccountSubmit').addEventListener('click', createAccount);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -267,6 +267,74 @@ VALUES (?, ?, ?, ?, ?)';
 | 
			
		|||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function setPasswordReset($email) {
 | 
			
		||||
    $date = date("Y-m-d H:i:s");
 | 
			
		||||
    $reset_code = random_int(0, 999999999);
 | 
			
		||||
    $reset_code_hash = $this->token->hash($reset_code);
 | 
			
		||||
    $query = "UPDATE `users` SET `password_reset_code`=?, `password_reset_date`=? WHERE `email`=?;";
 | 
			
		||||
    $reset = $this->db->execute($query, array(
 | 
			
		||||
      $reset_code,
 | 
			
		||||
      $date,
 | 
			
		||||
      $email,
 | 
			
		||||
    ));
 | 
			
		||||
    
 | 
			
		||||
    if ($reset) {
 | 
			
		||||
      $user_data = $this->getUserDataByEmailForPasswordReset($email);
 | 
			
		||||
      if ($user_data) {
 | 
			
		||||
        $to = $email;
 | 
			
		||||
        $subject = "Here's your Lexiconga password reset link";
 | 
			
		||||
        $message = "Hello " . $user_data['public_name'] . "\r\n\r\nSomeone has requested a password reset link for your Lexiconga account. If it was you, you can reset your password by going to the link below and entering a new password for yourself:\r\n";
 | 
			
		||||
        $message .= "http://lexicon.ga/passwordreset?account=" . $user_data['id'] . "&code=" . $reset_code_hash . "\r\n\r\n";
 | 
			
		||||
        $message .= "If it wasn't you who requested the link, you can ignore this email since it was only sent to you, but you might want to consider changing your password when you have a chance.\r\n\r\n";
 | 
			
		||||
        $message .= "The password link will only be valid for today until you use it.\r\n\r\n";
 | 
			
		||||
        $message .= "Thanks!\r\nThe Lexiconga Admins";
 | 
			
		||||
        $header = "From: Lexiconga Password Reset <donotreply@lexicon.ga>\r\n"
 | 
			
		||||
          . "Reply-To: help@lexicon.ga\r\n"
 | 
			
		||||
          . "X-Mailer: PHP/" . phpversion();
 | 
			
		||||
        if (mail($to, $subject, $message, $header)) {
 | 
			
		||||
          return true;
 | 
			
		||||
        } else {
 | 
			
		||||
          return array(
 | 
			
		||||
            'error' => 'Could not send email to ' . $email,
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      return array(
 | 
			
		||||
        'error' => $this->db->last_error_info,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function checkPasswordReset($id, $code) {
 | 
			
		||||
    $date = date("Y-m-d");
 | 
			
		||||
    $daterange = "'" . $date . " 00:00:00' AND '" . $date . " 23:59:59'";
 | 
			
		||||
    $unhashed_code = $this->token->unhash($code);
 | 
			
		||||
    $query = "SELECT * FROM `users` WHERE `id`=? AND `password_reset_code`=? AND `password_reset_date` BETWEEN " . $daterange . ";";
 | 
			
		||||
    $stmt = $this->db->query($query, array(
 | 
			
		||||
      $id,
 | 
			
		||||
      $unhashed_code,
 | 
			
		||||
    ));
 | 
			
		||||
    $results = $stmt->fetchAll();
 | 
			
		||||
    
 | 
			
		||||
    if ($stmt && $results) {
 | 
			
		||||
        return count($results) === 1;
 | 
			
		||||
    } else {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function resetPassword($password, $email) {
 | 
			
		||||
    $password_hash = password_hash($password, PASSWORD_DEFAULT);
 | 
			
		||||
    $query = "UPDATE `users` SET `password`=?, `password_reset_date`='0000-00-00 00:00:00' WHERE `email`=?;";
 | 
			
		||||
    return $this->db->execute($query, array(
 | 
			
		||||
      $password_hash,
 | 
			
		||||
      $email,
 | 
			
		||||
    ));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private function generateUserToken ($user_id, $dictionary_id) {
 | 
			
		||||
    $user_data = array(
 | 
			
		||||
      'id' => intval($user_id),
 | 
			
		||||
| 
						 | 
				
			
			@ -287,4 +355,17 @@ VALUES (?, ?, ?, ?, ?)';
 | 
			
		|||
    $stmt = $this->db->query($update_query, array($new_password));
 | 
			
		||||
    return $stmt->rowCount() === 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private function getUserDataByEmailForPasswordReset($email) {
 | 
			
		||||
    $query = 'SELECT id, public_name FROM users WHERE email=?';
 | 
			
		||||
    $stmt = $this->db->query($query, array($email));
 | 
			
		||||
    $result = $stmt->fetch();
 | 
			
		||||
    if ($stmt && $result) {
 | 
			
		||||
      return array(
 | 
			
		||||
        'id' => $result['id'],
 | 
			
		||||
        'public_name' => $result['public_name'] ? $result['public_name'] : 'Lexiconger',
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -418,6 +418,32 @@ switch ($action) {
 | 
			
		|||
      'error' => true,
 | 
			
		||||
    ), 400);
 | 
			
		||||
  }
 | 
			
		||||
  case 'initiate-password-reset': {
 | 
			
		||||
    if (isset($request['email'])) {
 | 
			
		||||
      $user = new User();
 | 
			
		||||
      $password_reset = $user->setPasswordReset($request['email']);
 | 
			
		||||
      if ($password_reset === true) {
 | 
			
		||||
        return Response::json(array(
 | 
			
		||||
          'data' => $password_reset,
 | 
			
		||||
          'error' => false,
 | 
			
		||||
        ), 200);
 | 
			
		||||
      }
 | 
			
		||||
      if (isset($password_reset['error'])) {
 | 
			
		||||
        return Response::json(array(
 | 
			
		||||
          'data' => $password_reset['error'],
 | 
			
		||||
          'error' => true,
 | 
			
		||||
        ), 500);
 | 
			
		||||
      }
 | 
			
		||||
      return Response::json(array(
 | 
			
		||||
        'data' => 'Could not send password reset key: email not found',
 | 
			
		||||
        'error' => true,
 | 
			
		||||
      ), 401);
 | 
			
		||||
    }
 | 
			
		||||
    return Response::json(array(
 | 
			
		||||
      'data' => 'Could not send password reset key: required data missing',
 | 
			
		||||
      'error' => true,
 | 
			
		||||
    ), 400);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  default: {
 | 
			
		||||
    return Response::html('Hi!');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue