Organized password reset and account activation

This commit is contained in:
Marcin Kurczewski 2014-05-04 15:10:51 +02:00
parent 83239a492d
commit 893e841a87
3 changed files with 91 additions and 83 deletions

View file

@ -149,6 +149,13 @@ $userValidation =
\Chibi\Router::register(['UserController', 'registrationView'], 'GET', '/register', $userValidation); \Chibi\Router::register(['UserController', 'registrationView'], 'GET', '/register', $userValidation);
\Chibi\Router::register(['UserController', 'registrationAction'], 'POST', '/register', $userValidation); \Chibi\Router::register(['UserController', 'registrationAction'], 'POST', '/register', $userValidation);
\Chibi\Router::register(['UserController', 'activationView'], 'GET', '/activation', $userValidation);
\Chibi\Router::register(['UserController', 'activationAction'], 'POST', '/activation', $userValidation);
\Chibi\Router::register(['UserController', 'activationAction'], 'GET', '/activation/{token}', $userValidation);
\Chibi\Router::register(['UserController', 'passwordResetView'], 'GET', '/password-reset', $userValidation);
\Chibi\Router::register(['UserController', 'passwordResetAction'], 'POST', '/password-reset', $userValidation);
\Chibi\Router::register(['UserController', 'passwordResetAction'], 'GET', '/password-reset/{token}', $userValidation);
\Chibi\Router::register(['UserController', 'flagAction'], 'POST', '/user/{name}/flag', $userValidation); \Chibi\Router::register(['UserController', 'flagAction'], 'POST', '/user/{name}/flag', $userValidation);
\Chibi\Router::register(['UserController', 'banAction'], 'POST', '/user/{name}/ban', $userValidation); \Chibi\Router::register(['UserController', 'banAction'], 'POST', '/user/{name}/ban', $userValidation);
\Chibi\Router::register(['UserController', 'unbanAction'], 'POST', '/user/{name}/unban', $userValidation); \Chibi\Router::register(['UserController', 'unbanAction'], 'POST', '/user/{name}/unban', $userValidation);
@ -161,12 +168,6 @@ foreach (['GET', 'POST'] as $method)
{ {
\Chibi\Router::register(['TagController', 'massTagRedirectAction'], $method, '/mass-tag-redirect', $tagValidation); \Chibi\Router::register(['TagController', 'massTagRedirectAction'], $method, '/mass-tag-redirect', $tagValidation);
\Chibi\Router::register(['UserController', 'activationAction'], $method, '/activation/{token}', $userValidation);
\Chibi\Router::register(['UserController', 'activationProxyAction'], $method, '/activation-proxy', $userValidation);
\Chibi\Router::register(['UserController', 'activationProxyAction'], $method, '/activation-proxy/{token}', $userValidation);
\Chibi\Router::register(['UserController', 'passwordResetAction'], $method, '/password-reset/{token}', $userValidation);
\Chibi\Router::register(['UserController', 'passwordResetProxyAction'], $method, '/password-reset-proxy', $userValidation);
\Chibi\Router::register(['UserController', 'passwordResetProxyAction'], $method, '/password-reset-proxy/{token}', $userValidation);
\Chibi\Router::register(['UserController', 'toggleSafetyAction'], $method, '/user/toggle-safety/{safety}', $userValidation); \Chibi\Router::register(['UserController', 'toggleSafetyAction'], $method, '/user/toggle-safety/{safety}', $userValidation);
} }

View file

@ -216,32 +216,66 @@ class UserController
Messenger::message($message); Messenger::message($message);
} }
public function activationView()
{
$context = getContext();
$context->viewName = 'user-select';
Assets::setSubTitle('account activation');
}
public function activationAction($token) public function activationAction($token)
{ {
$context = getContext(); $context = getContext();
$context->viewName = 'message'; $context->viewName = 'message';
Assets::setSubTitle('account activation'); Assets::setSubTitle('account activation');
$dbToken = TokenModel::findByToken($token); if (empty($token))
TokenModel::checkValidity($dbToken);
$dbUser = $dbToken->getUser();
$dbUser->emailConfirmed = $dbUser->emailUnconfirmed;
$dbUser->emailUnconfirmed = null;
$dbToken->used = true;
TokenModel::save($dbToken);
UserModel::save($dbUser);
LogHelper::log('{subject} just activated account', ['subject' => TextHelper::reprUser($dbUser)]);
$message = 'Activation completed successfully.';
if (getConfig()->registration->staffActivation)
$message .= ' However, your account still must be confirmed by staff.';
Messenger::message($message);
if (!getConfig()->registration->staffActivation)
{ {
Auth::setCurrentUser($dbUser); $name = InputHelper::get('name');
$user = UserModel::findByNameOrEmail($name);
if (empty($user->emailUnconfirmed))
{
if (!empty($user->emailConfirmed))
throw new SimpleException('E-mail was already confirmed; activation skipped');
else
throw new SimpleException('This user has no e-mail specified; activation cannot proceed');
}
EditUserEmailJob::sendEmail($user);
Messenger::message('Activation e-mail resent.');
} }
else
{
$dbToken = TokenModel::findByToken($token);
TokenModel::checkValidity($dbToken);
$dbUser = $dbToken->getUser();
if (empty($dbUser->emailConfirmed))
{
$dbUser->emailConfirmed = $dbUser->emailUnconfirmed;
$dbUser->emailUnconfirmed = null;
}
$dbToken->used = true;
TokenModel::save($dbToken);
UserModel::save($dbUser);
LogHelper::log('{subject} just activated account', ['subject' => TextHelper::reprUser($dbUser)]);
$message = 'Activation completed successfully.';
if (getConfig()->registration->staffActivation)
$message .= ' However, your account still must be confirmed by staff.';
Messenger::message($message);
if (!getConfig()->registration->staffActivation)
{
Auth::setCurrentUser($dbUser);
}
}
}
public function passwordResetView()
{
$context = getContext();
$context->viewName = 'user-select';
Assets::setSubTitle('password reset');
} }
public function passwordResetAction($token) public function passwordResetAction($token)
@ -250,66 +284,39 @@ class UserController
$context->viewName = 'message'; $context->viewName = 'message';
Assets::setSubTitle('password reset'); Assets::setSubTitle('password reset');
$dbToken = TokenModel::findByToken($token); if (empty($token))
TokenModel::checkValidity($dbToken);
$alphabet = array_merge(range('A', 'Z'), range('a', 'z'), range('0', '9'));
$randomPassword = join('', array_map(function($x) use ($alphabet)
{ {
return $alphabet[$x]; $name = InputHelper::get('name');
}, array_rand($alphabet, 8))); $user = UserModel::findByNameOrEmail($name);
if (empty($user->emailConfirmed))
throw new SimpleException('This user has no e-mail confirmed; password reset cannot proceed');
$dbUser = $dbToken->getUser(); self::sendPasswordResetConfirmation($user);
$dbUser->passHash = UserModel::hashPassword($randomPassword, $dbUser->passSalt); Messenger::message('E-mail sent. Follow instructions to reset password.');
$dbToken->used = true; }
TokenModel::save($dbToken); else
UserModel::save($dbUser); {
$dbToken = TokenModel::findByToken($token);
LogHelper::log('{subject} just reset password', ['subject' => TextHelper::reprUser($dbUser)]); TokenModel::checkValidity($dbToken);
$message = 'Password reset successful. Your new password is **' . $randomPassword . '**.';
Messenger::message($message); $alphabet = array_merge(range('A', 'Z'), range('a', 'z'), range('0', '9'));
$randomPassword = join('', array_map(function($x) use ($alphabet)
Auth::setCurrentUser($dbUser); {
} return $alphabet[$x];
}, array_rand($alphabet, 8)));
public function passwordResetProxyAction()
{ $dbUser = $dbToken->getUser();
$context = getContext(); $dbUser->passHash = UserModel::hashPassword($randomPassword, $dbUser->passSalt);
$context->viewName = 'user-select'; $dbToken->used = true;
Assets::setSubTitle('password reset'); TokenModel::save($dbToken);
UserModel::save($dbUser);
if (!InputHelper::get('submit'))
return; LogHelper::log('{subject} just reset password', ['subject' => TextHelper::reprUser($dbUser)]);
$message = 'Password reset successful. Your new password is **' . $randomPassword . '**.';
$name = InputHelper::get('name'); Messenger::message($message);
$user = UserModel::findByNameOrEmail($name);
if (empty($user->emailConfirmed)) Auth::setCurrentUser($dbUser);
throw new SimpleException('This user has no e-mail confirmed; password reset cannot proceed');
self::sendPasswordResetConfirmation($user);
Messenger::message('E-mail sent. Follow instructions to reset password.');
}
public function activationProxyAction()
{
$context = getContext();
$context->viewName = 'user-select';
Assets::setSubTitle('account activation');
if (!InputHelper::get('submit'))
return;
$name = InputHelper::get('name');
$user = UserModel::findByNameOrEmail($name);
if (empty($user->emailUnconfirmed))
{
if (!empty($user->emailConfirmed))
throw new SimpleException('E-mail was already confirmed; activation skipped');
else
throw new SimpleException('This user has no e-mail specified; activation cannot proceed');
} }
EditUserEmailJob::sendEmail($user);
Messenger::message('Activation e-mail resent.');
} }
private static function sendPasswordResetConfirmation($user) private static function sendPasswordResetConfirmation($user)

View file

@ -43,8 +43,8 @@ Assets::addStylesheet('auth.css');
<div> <div>
<p>Problems logging in?</p> <p>Problems logging in?</p>
<ul> <ul>
<li><a href="<?= \Chibi\Router::linkTo(['UserController', 'passwordResetProxyAction']) ?>">I don't remember my password</a></li> <li><a href="<?= \Chibi\Router::linkTo(['UserController', 'passwordResetView']) ?>">I don't remember my password</a></li>
<li><a href="<?= \Chibi\Router::linkTo(['UserController', 'activationProxyAction']) ?>">I haven't received activation e-mail</a></li> <li><a href="<?= \Chibi\Router::linkTo(['UserController', 'activationView']) ?>">I haven't received activation e-mail</a></li>
<li><a href="<?= \Chibi\Router::linkTo(['UserController', 'registrationView']) ?>">I don't have an account</a></li> <li><a href="<?= \Chibi\Router::linkTo(['UserController', 'registrationView']) ?>">I don't have an account</a></li>
</ul> </ul>
</div> </div>