Move user registration to the backend and remove mail veification and captures.
This commit is contained in:
@@ -38,7 +38,7 @@ return array(
|
|||||||
"FEEDBACK_PASSWORD_REPEAT_WRONG" => "Password and password repeat are not the same.",
|
"FEEDBACK_PASSWORD_REPEAT_WRONG" => "Password and password repeat are not the same.",
|
||||||
"FEEDBACK_PASSWORD_TOO_SHORT" => "Password has a minimum length of 6 characters.",
|
"FEEDBACK_PASSWORD_TOO_SHORT" => "Password has a minimum length of 6 characters.",
|
||||||
"FEEDBACK_USERNAME_TOO_SHORT_OR_TOO_LONG" => "Username cannot be shorter than 2 or longer than 64 characters.",
|
"FEEDBACK_USERNAME_TOO_SHORT_OR_TOO_LONG" => "Username cannot be shorter than 2 or longer than 64 characters.",
|
||||||
"FEEDBACK_ACCOUNT_SUCCESSFULLY_CREATED" => "Your account has been created successfully and we have sent you an email. Please click the VERIFICATION LINK within that mail.",
|
"FEEDBACK_ACCOUNT_SUCCESSFULLY_CREATED" => "The account has been created successfully.",
|
||||||
"FEEDBACK_VERIFICATION_MAIL_SENDING_FAILED" => "Sorry, we could not send you an verification mail. Your account has NOT been created.",
|
"FEEDBACK_VERIFICATION_MAIL_SENDING_FAILED" => "Sorry, we could not send you an verification mail. Your account has NOT been created.",
|
||||||
"FEEDBACK_ACCOUNT_CREATION_FAILED" => "Sorry, your registration failed. Please go back and try again.",
|
"FEEDBACK_ACCOUNT_CREATION_FAILED" => "Sorry, your registration failed. Please go back and try again.",
|
||||||
"FEEDBACK_VERIFICATION_MAIL_SENDING_ERROR" => "Verification mail could not be sent due to: ",
|
"FEEDBACK_VERIFICATION_MAIL_SENDING_ERROR" => "Verification mail could not be sent due to: ",
|
||||||
|
|||||||
@@ -32,4 +32,25 @@ class AdminController extends Controller
|
|||||||
|
|
||||||
Redirect::to("admin");
|
Redirect::to("admin");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function registerUser()
|
||||||
|
{
|
||||||
|
// Ensure the user is logged in and is an admin
|
||||||
|
if (!LoginModel::isUserLoggedIn() || !LoginModel::isAdmin()) {
|
||||||
|
Session::add('feedback_negative', Text::get('FEEDBACK_ADMIN_ONLY'));
|
||||||
|
Redirect::to('admin/index');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and register the new user
|
||||||
|
$registration_successful = RegistrationModel::registerNewUser(true);
|
||||||
|
|
||||||
|
if ($registration_successful) {
|
||||||
|
Session::add('feedback_positive', Text::get('FEEDBACK_USER_REGISTERED_SUCCESSFULLY'));
|
||||||
|
} else {
|
||||||
|
Session::add('feedback_negative', Text::get('FEEDBACK_USER_REGISTRATION_FAILED'));
|
||||||
|
}
|
||||||
|
|
||||||
|
Redirect::to('admin/index');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,13 @@ class RegisterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
if (LoginModel::isUserLoggedIn()) {
|
// Redirect non-logged-in users to the login page
|
||||||
Redirect::home();
|
if (!LoginModel::isUserLoggedIn()) {
|
||||||
} else {
|
Redirect::to('login/index');
|
||||||
$this->View->render('register/index');
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->View->render('register/index');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,6 +37,13 @@ class RegisterController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function register_action()
|
public function register_action()
|
||||||
{
|
{
|
||||||
|
// Restrict registration to admins only
|
||||||
|
if (!LoginModel::isAdmin()) {
|
||||||
|
Session::add('feedback_negative', Text::get('FEEDBACK_ADMIN_ONLY'));
|
||||||
|
Redirect::to('login/index');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$registration_successful = RegistrationModel::registerNewUser();
|
$registration_successful = RegistrationModel::registerNewUser();
|
||||||
|
|
||||||
if ($registration_successful) {
|
if ($registration_successful) {
|
||||||
@@ -62,13 +71,12 @@ class RegisterController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Generate a captcha, write the characters into $_SESSION['captcha'] and returns a real image which will be used
|
* Generate a captcha, write the characters into $_SESSION['captcha'] and returns a real image which will be used
|
||||||
* like this: <img src="......./login/showCaptcha" />
|
* like this: <img src="......./login/showCaptcha" />
|
||||||
* IMPORTANT: As this action is called via <img ...> AFTER the real application has finished executing (!), the
|
*
|
||||||
* SESSION["captcha"] has no content when the application is loaded. The SESSION["captcha"] gets filled at the
|
* This method is now deprecated as Captcha is no longer used in the registration process.
|
||||||
* moment the end-user requests the <img .. >
|
|
||||||
* Maybe refactor this sometime.
|
|
||||||
*/
|
*/
|
||||||
public function showCaptcha()
|
public function showCaptcha()
|
||||||
{
|
{
|
||||||
CaptchaModel::generateAndShowCaptcha();
|
Session::add('feedback_negative', Text::get('FEEDBACK_CAPTCHA_NOT_USED'));
|
||||||
|
Redirect::to('register/index');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Text
|
|||||||
|
|
||||||
// load config file (this is only done once per application lifecycle)
|
// load config file (this is only done once per application lifecycle)
|
||||||
if (!self::$texts) {
|
if (!self::$texts) {
|
||||||
self::$texts = require('../application/config/texts.php');
|
self::$texts = require(__DIR__ . '/../config/texts.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if array key exists
|
// check if array key exists
|
||||||
|
|||||||
@@ -379,4 +379,15 @@ class LoginModel
|
|||||||
{
|
{
|
||||||
return Session::userIsLoggedIn();
|
return Session::userIsLoggedIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the logged-in user is an admin
|
||||||
|
*
|
||||||
|
* @return bool True if the user is an admin, false otherwise
|
||||||
|
*/
|
||||||
|
public static function isAdmin()
|
||||||
|
{
|
||||||
|
$user_role = Session::get('user_role'); // Assuming user role is stored in session
|
||||||
|
return $user_role === 'admin';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,101 +13,61 @@ class RegistrationModel
|
|||||||
*
|
*
|
||||||
* @return boolean Gives back the success status of the registration
|
* @return boolean Gives back the success status of the registration
|
||||||
*/
|
*/
|
||||||
public static function registerNewUser()
|
public static function registerNewUser($isAdmin = false)
|
||||||
{
|
{
|
||||||
// clean the input
|
// clean the input
|
||||||
$user_name = strip_tags(Request::post('user_name'));
|
$user_name = strip_tags(Request::post('user_name'));
|
||||||
$user_email = strip_tags(Request::post('user_email'));
|
$user_email = strip_tags(Request::post('user_email'));
|
||||||
$user_email_repeat = strip_tags(Request::post('user_email_repeat'));
|
// Use 'user_password' if provided (admin registration), otherwise 'user_password_new'
|
||||||
$user_password_new = Request::post('user_password_new');
|
$user_password_new = $isAdmin ? Request::post('user_password') : Request::post('user_password_new');
|
||||||
$user_password_repeat = Request::post('user_password_repeat');
|
|
||||||
|
|
||||||
// stop registration flow if registrationInputValidation() returns false (= anything breaks the input check rules)
|
// validate input (skip captcha validation)
|
||||||
$validation_result = self::registrationInputValidation(Request::post('captcha'), $user_name, $user_password_new, $user_password_repeat, $user_email, $user_email_repeat);
|
$validation_result = self::registrationInputValidation($user_name, $user_password_new, $user_email);
|
||||||
if (!$validation_result) {
|
if (!$validation_result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// crypt the password with the PHP 5.5's password_hash() function, results in a 60 character hash string.
|
// hash the password
|
||||||
// @see php.net/manual/en/function.password-hash.php for more, especially for potential options
|
|
||||||
$user_password_hash = password_hash($user_password_new, PASSWORD_DEFAULT);
|
$user_password_hash = password_hash($user_password_new, PASSWORD_DEFAULT);
|
||||||
|
|
||||||
// make return a bool variable, so both errors can come up at once if needed
|
// check if username or email already exists
|
||||||
$return = true;
|
if (UserModel::doesUsernameAlreadyExist($user_name) || UserModel::doesEmailAlreadyExist($user_email)) {
|
||||||
|
Session::add('feedback_negative', Text::get('FEEDBACK_USERNAME_OR_EMAIL_TAKEN'));
|
||||||
// check if username already exists
|
return false;
|
||||||
if (UserModel::doesUsernameAlreadyExist($user_name)) {
|
|
||||||
Session::add('feedback_negative', Text::get('FEEDBACK_USERNAME_ALREADY_TAKEN'));
|
|
||||||
$return = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if email already exists
|
// directly activate user (skip email verification)
|
||||||
if (UserModel::doesEmailAlreadyExist($user_email)) {
|
$user_active = 1;
|
||||||
Session::add('feedback_negative', Text::get('FEEDBACK_USER_EMAIL_ALREADY_TAKEN'));
|
|
||||||
$return = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if Username or Email were false, return false
|
|
||||||
if (!$return) return false;
|
|
||||||
|
|
||||||
// generate random hash for email verification (40 bytes)
|
|
||||||
$user_activation_hash = bin2hex(random_bytes(40));
|
|
||||||
|
|
||||||
// write user data to database
|
// write user data to database
|
||||||
if (!self::writeNewUserToDatabase($user_name, $user_password_hash, $user_email, time(), $user_activation_hash)) {
|
if (!self::writeNewUserToDatabase($user_name, $user_password_hash, $user_email, time(), $user_active)) {
|
||||||
Session::add('feedback_negative', Text::get('FEEDBACK_ACCOUNT_CREATION_FAILED'));
|
Session::add('feedback_negative', Text::get('FEEDBACK_ACCOUNT_CREATION_FAILED'));
|
||||||
return false; // no reason not to return false here
|
|
||||||
}
|
|
||||||
|
|
||||||
// get user_id of the user that has been created, to keep things clean we DON'T use lastInsertId() here
|
|
||||||
$user_id = UserModel::getUserIdByUsername($user_name);
|
|
||||||
|
|
||||||
if (!$user_id) {
|
|
||||||
Session::add('feedback_negative', Text::get('FEEDBACK_UNKNOWN_ERROR'));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send verification email
|
|
||||||
if (self::sendVerificationEmail($user_id, $user_email, $user_activation_hash)) {
|
|
||||||
Session::add('feedback_positive', Text::get('FEEDBACK_ACCOUNT_SUCCESSFULLY_CREATED'));
|
Session::add('feedback_positive', Text::get('FEEDBACK_ACCOUNT_SUCCESSFULLY_CREATED'));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if verification email sending failed: instantly delete the user
|
|
||||||
self::rollbackRegistrationByUserId($user_id);
|
|
||||||
Session::add('feedback_negative', Text::get('FEEDBACK_VERIFICATION_MAIL_SENDING_FAILED'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the registration input
|
* Validates the registration input
|
||||||
*
|
*
|
||||||
* @param $captcha
|
|
||||||
* @param $user_name
|
* @param $user_name
|
||||||
* @param $user_password_new
|
* @param $user_password_new
|
||||||
* @param $user_password_repeat
|
|
||||||
* @param $user_email
|
* @param $user_email
|
||||||
* @param $user_email_repeat
|
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function registrationInputValidation($captcha, $user_name, $user_password_new, $user_password_repeat, $user_email, $user_email_repeat)
|
public static function registrationInputValidation($user_name, $user_password_new, $user_email)
|
||||||
{
|
{
|
||||||
$return = true;
|
$return = true;
|
||||||
|
|
||||||
// perform all necessary checks
|
if (empty($user_name) || empty($user_password_new) || empty($user_email)) {
|
||||||
if (!CaptchaModel::checkCaptcha($captcha)) {
|
Session::add('feedback_negative', Text::get('FEEDBACK_FIELDS_EMPTY'));
|
||||||
Session::add('feedback_negative', Text::get('FEEDBACK_CAPTCHA_WRONG'));
|
|
||||||
$return = false;
|
$return = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if username, email and password are all correctly validated, but make sure they all run on first sumbit
|
return $return;
|
||||||
if (self::validateUserName($user_name) AND self::validateUserEmail($user_email, $user_email_repeat) AND self::validateUserPassword($user_password_new, $user_password_repeat) AND $return) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, return false
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,12 +168,20 @@ class RegistrationModel
|
|||||||
$sql = "INSERT INTO users (user_name, user_password_hash, user_email, user_creation_timestamp, user_activation_hash, user_provider_type)
|
$sql = "INSERT INTO users (user_name, user_password_hash, user_email, user_creation_timestamp, user_activation_hash, user_provider_type)
|
||||||
VALUES (:user_name, :user_password_hash, :user_email, :user_creation_timestamp, :user_activation_hash, :user_provider_type)";
|
VALUES (:user_name, :user_password_hash, :user_email, :user_creation_timestamp, :user_activation_hash, :user_provider_type)";
|
||||||
$query = $database->prepare($sql);
|
$query = $database->prepare($sql);
|
||||||
$query->execute(array(':user_name' => $user_name,
|
try {
|
||||||
|
$query->execute(array(
|
||||||
|
':user_name' => $user_name,
|
||||||
':user_password_hash' => $user_password_hash,
|
':user_password_hash' => $user_password_hash,
|
||||||
':user_email' => $user_email,
|
':user_email' => $user_email,
|
||||||
':user_creation_timestamp' => $user_creation_timestamp,
|
':user_creation_timestamp' => $user_creation_timestamp,
|
||||||
':user_activation_hash' => $user_activation_hash,
|
':user_activation_hash' => $user_activation_hash,
|
||||||
':user_provider_type' => 'DEFAULT'));
|
':user_provider_type' => 'DEFAULT'
|
||||||
|
));
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Database error during user creation: " . $e->getMessage());
|
||||||
|
Session::add('feedback_negative', "Database error: " . $e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$count = $query->rowCount();
|
$count = $query->rowCount();
|
||||||
if ($count == 1) {
|
if ($count == 1) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -36,9 +36,6 @@
|
|||||||
<li <?php if (View::checkForActiveControllerAndAction($filename, "login/index")) { echo ' class="active" '; } ?> >
|
<li <?php if (View::checkForActiveControllerAndAction($filename, "login/index")) { echo ' class="active" '; } ?> >
|
||||||
<a href="<?php echo Config::get('URL'); ?>login/index">Login</a>
|
<a href="<?php echo Config::get('URL'); ?>login/index">Login</a>
|
||||||
</li>
|
</li>
|
||||||
<li <?php if (View::checkForActiveControllerAndAction($filename, "register/index")) { echo ' class="active" '; } ?> >
|
|
||||||
<a href="<?php echo Config::get('URL'); ?>register/index">Register</a>
|
|
||||||
</li>
|
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -53,5 +53,15 @@
|
|||||||
<?php } ?>
|
<?php } ?>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h3>Register a new user</h3>
|
||||||
|
|
||||||
|
<form method="post" action="<?php echo Config::get('URL'); ?>admin/registerUser">
|
||||||
|
<input type="text" name="user_name" placeholder="Username" required />
|
||||||
|
<input type="email" name="user_email" placeholder="Email address" required />
|
||||||
|
<input type="password" name="user_password" placeholder="Password" required />
|
||||||
|
<input type="submit" value="Register User" />
|
||||||
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -38,13 +38,6 @@
|
|||||||
<a href="<?php echo Config::get('URL'); ?>login/requestPasswordReset">I forgot my password</a>
|
<a href="<?php echo Config::get('URL'); ?>login/requestPasswordReset">I forgot my password</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- register box on right side -->
|
|
||||||
<div class="register-box">
|
|
||||||
<h2>No account yet ?</h2>
|
|
||||||
<a href="<?php echo Config::get('URL'); ?>register/index">Register</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,30 +9,12 @@
|
|||||||
|
|
||||||
<!-- register form -->
|
<!-- register form -->
|
||||||
<form method="post" action="<?php echo Config::get('URL'); ?>register/register_action">
|
<form method="post" action="<?php echo Config::get('URL'); ?>register/register_action">
|
||||||
<!-- the user name input field uses a HTML5 pattern check -->
|
|
||||||
<input type="text" pattern="[a-zA-Z0-9]{2,64}" name="user_name" placeholder="Username (letters/numbers, 2-64 chars)" required />
|
<input type="text" pattern="[a-zA-Z0-9]{2,64}" name="user_name" placeholder="Username (letters/numbers, 2-64 chars)" required />
|
||||||
<input type="text" name="user_email" placeholder="email address (a real address)" required />
|
<input type="text" name="user_email" placeholder="email address (a real address)" required />
|
||||||
<input type="text" name="user_email_repeat" placeholder="repeat email address (to prevent typos)" required />
|
<input type="text" name="user_email_repeat" placeholder="repeat email address (to prevent typos)" required />
|
||||||
<input type="password" name="user_password_new" pattern=".{6,}" placeholder="Password (6+ characters)" required autocomplete="off" />
|
<input type="password" name="user_password_new" pattern=".{6,}" placeholder="Password (6+ characters)" required autocomplete="off" />
|
||||||
<input type="password" name="user_password_repeat" pattern=".{6,}" required placeholder="Repeat your password" autocomplete="off" />
|
<input type="password" name="user_password_repeat" pattern=".{6,}" required placeholder="Repeat your password" autocomplete="off" />
|
||||||
|
|
||||||
<!-- show the captcha by calling the login/showCaptcha-method in the src attribute of the img tag -->
|
|
||||||
<img id="captcha" src="<?php echo Config::get('URL'); ?>register/showCaptcha" />
|
|
||||||
<input type="text" name="captcha" placeholder="Please enter above characters" required />
|
|
||||||
|
|
||||||
<!-- quick & dirty captcha reloader -->
|
|
||||||
<a href="#" style="display: block; font-size: 11px; margin: 5px 0 15px 0; text-align: center"
|
|
||||||
onclick="document.getElementById('captcha').src = '<?php echo Config::get('URL'); ?>register/showCaptcha?' + Math.random(); return false">Reload Captcha</a>
|
|
||||||
|
|
||||||
<input type="submit" value="Register" />
|
<input type="submit" value="Register" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
|
||||||
<p style="display: block; font-size: 11px; color: #999;">
|
|
||||||
Please note: This captcha will be generated when the img tag requests the captcha-generation
|
|
||||||
(= a real image) from YOURURL/register/showcaptcha. As this is a client-side triggered request, a
|
|
||||||
$_SESSION["captcha"] dump will not show the captcha characters. The captcha generation
|
|
||||||
happens AFTER the request that generates THIS page has been finished.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user