WiP for one time tokens
* Added token type class * Storing Token Type as ID not varchar * Added new system to user class and fixed issues with it * Started on mail verification process in user class * Updated autoloader * Updated change password template Addresses #330
This commit is contained in:
parent
d5c14b9b44
commit
29d5d36a7e
@ -22,6 +22,8 @@ require_once(INCLUDE_DIR . '/database.inc.php');
|
||||
require_once(INCLUDE_DIR . '/smarty.inc.php');
|
||||
// Load classes that need the above as dependencies
|
||||
require_once(CLASS_DIR . '/base.class.php');
|
||||
require_once(CLASS_DIR . '/tokentype.class.php');
|
||||
require_once(CLASS_DIR . '/token.class.php');
|
||||
require_once(CLASS_DIR . '/block.class.php');
|
||||
require_once(CLASS_DIR . '/setting.class.php');
|
||||
require_once(CLASS_DIR . '/monitoring.class.php');
|
||||
|
||||
@ -24,6 +24,9 @@ class Base {
|
||||
public function setConfig($config) {
|
||||
$this->config = $config;
|
||||
}
|
||||
public function setTokenType($tokentype) {
|
||||
$this->tokentype = $tokentype;
|
||||
}
|
||||
public function setErrorMessage($msg) {
|
||||
$this->sError = $msg;
|
||||
}
|
||||
|
||||
60
public/include/classes/token.class.php
Normal file
60
public/include/classes/token.class.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
// Make sure we are called from index.php
|
||||
if (!defined('SECURITY')) die('Hacking attempt');
|
||||
|
||||
class Token Extends Base {
|
||||
var $table = 'tokens';
|
||||
|
||||
/**
|
||||
* Fetch a token from our table
|
||||
* @param name string Setting name
|
||||
* @return value string Value
|
||||
**/
|
||||
public function getToken($strToken) {
|
||||
$stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE token = ? LIMIT 1");
|
||||
if ($stmt && $stmt->bind_param('s', $strToken) && $stmt->execute() && $result = $stmt->get_result())
|
||||
return $result->fetch_assoc();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new token
|
||||
* @param name string Name of the variable
|
||||
* @param value string Variable value
|
||||
* @return mixed Insert ID on success, false on failure
|
||||
**/
|
||||
public function createToken($strType, $account_id=NULL) {
|
||||
$strToken = hash('sha256', $account_id.$strType.microtime());
|
||||
if (!$iToken_id = $this->tokentype->getTypeId($strType)) {
|
||||
$this->setErrorMessage('Invalid token type: ' . $strType);
|
||||
return false;
|
||||
}
|
||||
$stmt = $this->mysqli->prepare("
|
||||
INSERT INTO $this->table (token, type, account_id)
|
||||
VALUES (?, ?, ?)
|
||||
");
|
||||
if ($stmt && $stmt->bind_param('sii', $strToken, $iToken_id, $account_id) && $stmt->execute())
|
||||
return $stmt->insert_id;
|
||||
$this->setErrorMessage('Unable to create new token');
|
||||
$this->debug->append('Failed to create new token in database: ' . $this->mysqli->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a used token
|
||||
* @param token string Token name
|
||||
* @return bool
|
||||
**/
|
||||
public function deleteToken($token) {
|
||||
$stmt = $this->mysqli->prepare("DELETE FROM $this->table WHERE token = ? LIMIT 1");
|
||||
if ($stmt && $stmt->bind_param('s', $token) && $stmt->execute())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$token = new Token();
|
||||
$token->setDebug($debug);
|
||||
$token->setMysql($mysqli);
|
||||
$token->setTokenType($tokentype);
|
||||
21
public/include/classes/tokentype.class.php
Normal file
21
public/include/classes/tokentype.class.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
// Make sure we are called from index.php
|
||||
if (!defined('SECURITY'))
|
||||
die('Hacking attempt');
|
||||
|
||||
class Token_Type Extends Base {
|
||||
var $table = 'token_types';
|
||||
/**
|
||||
* Return ID for specific token
|
||||
* @param strName string Token Name
|
||||
* @return mixed ID on success, false on failure
|
||||
**/
|
||||
public function getTypeId($strName) {
|
||||
return $this->getSingle($strName, 'id', 'name', 's');
|
||||
}
|
||||
}
|
||||
|
||||
$tokentype = new Token_Type();
|
||||
$tokentype->setDebug($debug);
|
||||
$tokentype->setMysql($mysqli);
|
||||
@ -9,11 +9,11 @@ class User {
|
||||
private $userID = false;
|
||||
private $table = 'accounts';
|
||||
private $user = array();
|
||||
private $tableAccountBalance = 'accountBalance';
|
||||
|
||||
public function __construct($debug, $mysqli, $salt, $config) {
|
||||
public function __construct($debug, $mysqli, $token, $salt, $config) {
|
||||
$this->debug = $debug;
|
||||
$this->mysqli = $mysqli;
|
||||
$this->token = $token;
|
||||
$this->salt = $salt;
|
||||
$this->config = $config;
|
||||
$this->debug->append("Instantiated User class", 2);
|
||||
@ -485,13 +485,13 @@ class User {
|
||||
}
|
||||
if ($this->mysqli->query("SELECT id FROM $this->table LIMIT 1")->num_rows > 0) {
|
||||
$stmt = $this->mysqli->prepare("
|
||||
INSERT INTO $this->table (username, pass, email, pin, api_key)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
INSERT INTO $this->table (username, pass, email, pin, api_key, is_locked)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
");
|
||||
} else {
|
||||
$stmt = $this->mysqli->prepare("
|
||||
INSERT INTO $this->table (username, pass, email, pin, api_key, is_admin)
|
||||
VALUES (?, ?, ?, ?, ?, 1)
|
||||
INSERT INTO $this->table (username, pass, email, pin, api_key, is_admin, is_locked)
|
||||
VALUES (?, ?, ?, ?, ?, 1, 0)
|
||||
");
|
||||
}
|
||||
|
||||
@ -501,14 +501,19 @@ class User {
|
||||
$apikey_hash = $this->getHash($username);
|
||||
$username_clean = strip_tags($username);
|
||||
|
||||
if ($this->checkStmt($stmt) && $stmt->bind_param('sssss', $username_clean, $password_hash, $email1, $pin_hash, $apikey_hash)) {
|
||||
if (!$stmt->execute()) {
|
||||
$this->setErrorMessage( 'Unable to register' );
|
||||
if ($stmt->sqlstate == '23000') $this->setErrorMessage( 'Username or email already registered' );
|
||||
return false;
|
||||
//
|
||||
$this->config['confirm_email'] ? $is_locked = 1 : $is_locked = 0;
|
||||
|
||||
if ($this->checkStmt($stmt) && $stmt->bind_param('sssssi', $username_clean, $password_hash, $email1, $pin_hash, $apikey_hash, $is_locked) && $stmt->execute()) {
|
||||
if ($this->config['confirm_email']) {
|
||||
$this->token->createToken('confirm_email', $stmt->insert_id);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
$stmt->close();
|
||||
return true;
|
||||
} else {
|
||||
$this->setErrorMessage( 'Unable to register' );
|
||||
if ($stmt->sqlstate == '23000') $this->setErrorMessage( 'Username or email already registered' );
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -520,9 +525,9 @@ class User {
|
||||
* @param new2 string New password verification
|
||||
* @return bool
|
||||
**/
|
||||
public function useToken($token, $new1, $new2) {
|
||||
public function resetPassword($token, $new1, $new2) {
|
||||
$this->debug->append("STA " . __METHOD__, 4);
|
||||
if ($id = $this->getIdFromToken($token)) {
|
||||
if ($token = $this->token->getToken($token)) {
|
||||
if ($new1 !== $new2) {
|
||||
$this->setErrorMessage( 'New passwords do not match' );
|
||||
return false;
|
||||
@ -532,14 +537,20 @@ class User {
|
||||
return false;
|
||||
}
|
||||
$new_hash = $this->getHash($new1);
|
||||
$stmt = $this->mysqli->prepare("UPDATE $this->table SET pass = ?, token = NULL WHERE id = ? AND token = ?");
|
||||
if ($this->checkStmt($stmt) && $stmt->bind_param('sis', $new_hash, $id, $token) && $stmt->execute() && $stmt->affected_rows === 1) {
|
||||
return true;
|
||||
$stmt = $this->mysqli->prepare("UPDATE $this->table SET pass = ? WHERE id = ?");
|
||||
if ($this->checkStmt($stmt) && $stmt->bind_param('si', $new_hash, $token['account_id']) && $stmt->execute() && $stmt->affected_rows === 1) {
|
||||
if ($this->token->deleteToken($token)) {
|
||||
return true;
|
||||
} else {
|
||||
$this->setErrorMessage('Unable to invalidate used token');
|
||||
}
|
||||
} else {
|
||||
$this->setErrorMessage('Unable to set new password');
|
||||
}
|
||||
} else {
|
||||
$this->setErrorMessage("Unable find user for your token");
|
||||
return false;
|
||||
$this->setErrorMessage('Unable find user for your token');
|
||||
}
|
||||
$this->debug->append('Failed to update password:' . $this->mysqli->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -549,7 +560,7 @@ class User {
|
||||
* @param smarty object Smarty object for mail templating
|
||||
* @return bool
|
||||
**/
|
||||
public function resetPassword($username, $smarty) {
|
||||
public function initResetPassword($username, $smarty) {
|
||||
$this->debug->append("STA " . __METHOD__, 4);
|
||||
// Fetch the users mail address
|
||||
if (empty($username)) {
|
||||
@ -560,16 +571,11 @@ class User {
|
||||
$this->setErrorMessage("Unable to find a mail address for user $username");
|
||||
return false;
|
||||
}
|
||||
if (!$this->setUserToken($this->getUserId($username))) {
|
||||
if (!$token = $this->token->getToken($this->token->createToken('password_reset', $this->getUserId($username)))) {
|
||||
$this->setErrorMessage("Unable to setup token for password reset");
|
||||
return false;
|
||||
}
|
||||
// Send password reset link
|
||||
if (!$token = $this->getUserToken($this->getUserId($username))) {
|
||||
$this->setErrorMessage("Unable fetch token for password reset");
|
||||
return false;
|
||||
}
|
||||
$smarty->assign('TOKEN', $token);
|
||||
$smarty->assign('TOKEN', $token['token']);
|
||||
$smarty->assign('USERNAME', $username);
|
||||
$smarty->assign('SUBJECT', 'Password Reset Request');
|
||||
$smarty->assign('WEBSITENAME', $this->config['website']['name']);
|
||||
@ -608,4 +614,4 @@ class User {
|
||||
}
|
||||
|
||||
// Make our class available automatically
|
||||
$user = new User($debug, $mysqli, SALT, $config);
|
||||
$user = new User($debug, $mysqli, $token, SALT, $config);
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
if (!defined('SECURITY'))
|
||||
die('Hacking attempt');
|
||||
|
||||
if ($_POST['do'] == 'useToken') {
|
||||
if ($user->useToken($_POST['token'], $_POST['newPassword'], $_POST['newPassword2'])) {
|
||||
if ($_POST['do'] == 'resetPassword') {
|
||||
if ($user->resetPassword($_POST['token'], $_POST['newPassword'], $_POST['newPassword2'])) {
|
||||
$_SESSION['POPUP'][] = array('CONTENT' => 'Password reset complete! Please login.');
|
||||
} else {
|
||||
$_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg');
|
||||
|
||||
@ -5,7 +5,7 @@ if (!defined('SECURITY'))
|
||||
die('Hacking attempt');
|
||||
|
||||
// Process password reset request
|
||||
if ($user->resetPassword($_POST['username'], $smarty)) {
|
||||
if ($user->initResetPassword($_POST['username'], $smarty)) {
|
||||
$_SESSION['POPUP'][] = array('CONTENT' => 'Please check your mail account to finish your password reset');
|
||||
} else {
|
||||
$_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg');
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<input type="hidden" name="token" value="{$smarty.request.token|escape}">
|
||||
<input type="hidden" name="page" value="{$smarty.request.page|escape}">
|
||||
<input type="hidden" name="action" value="{$smarty.request.action|escape}">
|
||||
<input type="hidden" name="do" value="useToken">
|
||||
<input type="hidden" name="do" value="resetPassword">
|
||||
<table>
|
||||
<tr><td>New Password: </td><td><input type="password" name="newPassword"></td></tr>
|
||||
<tr><td>New Password Repeat: </td><td><input type="password" name="newPassword2"></td></tr>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user