Add customer_password_reset_keys_o class with token generation, validation, and password reset functionality.
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use Random\RandomException;
|
||||
use traits\db_object_t;
|
||||
|
||||
class customer_password_reset_keys_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
public object_property $customer_id;
|
||||
public object_property $note;
|
||||
public object_property $token;
|
||||
public object_property $created_at;
|
||||
public object_property $updated_at;
|
||||
public object_property $deleted_at;
|
||||
const TOKEN_LENGTH = 32;
|
||||
const TOKEN_EXPIRY_SECONDS = 3600; // 1 hour
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
$this->setTable('customer_password_reset_keys');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a new customer reset key
|
||||
* @param array $data The properties
|
||||
* @returns void
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add(array $data): void
|
||||
{
|
||||
$tmp_id = self::add_object($data);
|
||||
$this->id = $tmp_id;
|
||||
self::getObjectProperties();
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique token
|
||||
* @param int $length The length of the token
|
||||
* @return string The generated token
|
||||
* @throws RandomException
|
||||
*/
|
||||
public static function generateToken(int $length = self::TOKEN_LENGTH): string
|
||||
{
|
||||
return bin2hex(random_bytes($length / 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a valid reset key by token
|
||||
* @param string $token The token to search for
|
||||
* @return customer_password_reset_keys_o|null The found reset key or null if not found
|
||||
* @throws Exception
|
||||
*/
|
||||
public function findValidByToken(string $token): ?customer_password_reset_keys_o
|
||||
{
|
||||
global $db;
|
||||
// Sanitize input to conform to the expected format
|
||||
$token = preg_replace('/[^a-f0-9]/', '', strtolower($token));
|
||||
if (strlen($token) !== self::TOKEN_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
// Query the database for a valid token
|
||||
$current_time = date('Y-m-d H:i:s');
|
||||
$sql = "SELECT id FROM $this->table WHERE token = '" . $db->escape_string($token) . "' AND deleted_at IS NULL AND created_at >= DATE_SUB('$current_time', INTERVAL " . self::TOKEN_EXPIRY_SECONDS . " SECOND) LIMIT 1";
|
||||
$result = $db->query($sql);
|
||||
if ($result->num_rows === 0) {
|
||||
return null;
|
||||
}
|
||||
$row = $result->fetch_assoc();
|
||||
$this->id = (int)$row['id'];
|
||||
$this->getObjectProperties();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the token is valid and not expired
|
||||
* @return bool True if the token is valid, false otherwise
|
||||
* @throws Exception
|
||||
*/
|
||||
public function isValidToken(): bool
|
||||
{
|
||||
self::requireSelected();
|
||||
$created_at = strtotime($this->created_at->value());
|
||||
$current_time = time();
|
||||
return (
|
||||
($current_time - $created_at) <= self::TOKEN_EXPIRY_SECONDS) &&
|
||||
($this->deleted_at->value() === null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that the token is valid and not expired
|
||||
* @throws Exception If the token is invalid or expired
|
||||
*/
|
||||
public function requireValidToken(): void
|
||||
{
|
||||
self::requireSelected();
|
||||
if (!$this->isValidToken()) {
|
||||
throw new Exception('Invalid or expired token');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password of the customer associated with this reset key
|
||||
* @param string $new_password The new password to set
|
||||
* @return void
|
||||
* @throws Exception If the token is invalid or expired
|
||||
*/
|
||||
public function setPassword(string $new_password): void
|
||||
{
|
||||
self::requireSelected();
|
||||
self::requireValidToken();
|
||||
$customer = new users_o();
|
||||
$customer->getUserByCustomerNumber((int)$this->customer_id->value());
|
||||
$customer->requireSelected();
|
||||
$customer->setPassword($new_password);
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->customer_id = new object_property($this->table, $this->id, 'customer_id', 'int', false);
|
||||
$this->note = new object_property($this->table, $this->id, 'note', 'string', false);
|
||||
$this->token = new object_property($this->table, $this->id, 'token', 'string', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false);
|
||||
$this->updated_at = new object_property($this->table, $this->id, 'updated_at', 'string', false);
|
||||
$this->deleted_at = new object_property($this->table, $this->id, 'deleted_at', 'string', false);
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user