Simplified auth

This commit is contained in:
Marcin Kurczewski 2014-05-01 16:12:37 +02:00
parent e673bdb50c
commit 0a7fc387ac
15 changed files with 175 additions and 178 deletions

View file

@ -157,7 +157,8 @@ $context->transport = new StdClass;
StatusHelper::init();
session_start();
AuthController::doLogIn();
if (!Auth::isLoggedIn())
Auth::tryAutoLogin();
try
{

View file

@ -37,7 +37,7 @@ class Access
if (php_sapi_name() == 'cli')
return true;
$user = getContext()->user;
$user = Auth::getCurrentUser();
$minAccessRank = AccessRank::Admin;
$key = TextCaseConverter::convert(Privilege::toString($privilege),
@ -66,19 +66,18 @@ class Access
throw new SimpleException('Insufficient privileges');
}
public static function assertEmailConfirmation()
{
$user = Auth::getCurrentUser();
if (!$user->emailConfirmed)
throw new SimpleException('Need e-mail address confirmation to continue');
}
public static function getIdentity($user)
{
if (!$user)
return 'all';
$userFromContext = getContext()->user;
return $user->id == $userFromContext->id ? 'own' : 'all';
}
public static function assertEmailConfirmation()
{
$user = getContext()->user;
if (!$user->emailConfirmed)
throw new SimpleException('Need e-mail address confirmation to continue');
return $user->id == Auth::getCurrentUser()->id ? 'own' : 'all';
}
public static function getAllowedSafety()
@ -86,11 +85,10 @@ class Access
if (php_sapi_name() == 'cli')
return PostSafety::getAll();
$context = getContext();
return array_filter(PostSafety::getAll(), function($safety) use ($context)
return array_filter(PostSafety::getAll(), function($safety)
{
return Access::check(Privilege::ListPosts, PostSafety::toString($safety))
and $context->user->hasEnabledSafety($safety);
and Auth::getCurrentUser()->hasEnabledSafety($safety);
});
}
}

92
src/Auth.php Normal file
View file

@ -0,0 +1,92 @@
<?php
class Auth
{
public static function logOut()
{
self::setCurrentUser(null);
setcookie('auth', false, 0, '/');
}
public static function login($name, $password, $remember)
{
$config = getConfig();
$context = getContext();
$dbUser = UserModel::findByNameOrEmail($name, false);
if ($dbUser === null)
throw new SimpleException('Invalid username');
$passwordHash = UserModel::hashPassword($password, $dbUser->passSalt);
if ($passwordHash != $dbUser->passHash)
throw new SimpleException('Invalid password');
if (!$dbUser->staffConfirmed and $config->registration->staffActivation)
throw new SimpleException('Staff hasn\'t confirmed your registration yet');
if ($dbUser->banned)
throw new SimpleException('You are banned');
if ($config->registration->needEmailForRegistering)
Access::requireEmail($dbUser);
if ($remember)
{
$token = implode('|', [base64_encode($name), base64_encode($password)]);
setcookie('auth', TextHelper::encrypt($token), time() + 365 * 24 * 3600, '/');
}
self::setCurrentUser($dbUser);
}
public static function tryAutoLogin()
{
if (!isset($_COOKIE['auth']))
return;
$token = TextHelper::decrypt($_COOKIE['auth']);
list ($name, $password) = array_map('base64_decode', explode('|', $token));
try
{
self::login($name, $password, false);
return true;
}
catch (Exception $e)
{
return false;
}
}
public static function isLoggedIn()
{
return isset($_SESSION['logged-in']) and $_SESSION['logged-in'];
}
public static function setCurrentUser($user)
{
if ($user == null)
{
self::setCurrentUser(self::getAnonymousUser());
}
else
{
$_SESSION['logged-in'] = $user->accessRank != AccessRank::Anonymous;
$_SESSION['user'] = serialize($user);
}
}
public static function getCurrentUser()
{
return self::isLoggedIn()
? unserialize($_SESSION['user'])
: self::getAnonymousUser();
}
private static function getAnonymousUser()
{
$dummy = UserModel::spawn();
$dummy->name = UserModel::getAnonymousName();
$dummy->accessRank = AccessRank::Anonymous;
return $dummy;
}
}

View file

@ -1,61 +1,13 @@
<?php
class AuthController
{
private static function redirectAfterLog()
{
if (isset($_SESSION['login-redirect-url']))
{
\Chibi\Util\Url::forward(\Chibi\Util\Url::makeAbsolute($_SESSION['login-redirect-url']));
unset($_SESSION['login-redirect-url']);
return;
}
\Chibi\Util\Url::forward(\Chibi\Router::linkTo(['IndexController', 'indexAction']));
}
public static function tryLogin($name, $password)
{
$config = getConfig();
$context = getContext();
$dbUser = UserModel::findByNameOrEmail($name, false);
if ($dbUser === null)
throw new SimpleException('Invalid username');
$passwordHash = UserModel::hashPassword($password, $dbUser->passSalt);
if ($passwordHash != $dbUser->passHash)
throw new SimpleException('Invalid password');
if (!$dbUser->staffConfirmed and $config->registration->staffActivation)
throw new SimpleException('Staff hasn\'t confirmed your registration yet');
if ($dbUser->banned)
throw new SimpleException('You are banned');
if ($config->registration->needEmailForRegistering)
Access::requireEmail($dbUser);
$context->user = $dbUser;
self::doReLog();
return $dbUser;
}
public static function tryAutoLogin()
{
if (!isset($_COOKIE['auth']))
return;
$token = TextHelper::decrypt($_COOKIE['auth']);
list ($name, $password) = array_map('base64_decode', explode('|', $token));
return self::tryLogin($name, $password);
}
public function loginAction()
{
$context = getContext();
$context->handleExceptions = true;
//check if already logged in
if ($context->loggedIn)
if (Auth::isLoggedIn())
{
self::redirectAfterLog();
return;
@ -66,13 +18,9 @@ class AuthController
$suppliedName = InputHelper::get('name');
$suppliedPassword = InputHelper::get('password');
$dbUser = self::tryLogin($suppliedName, $suppliedPassword);
$remember = boolval(InputHelper::get('remember'));
$dbUser = Auth::login($suppliedName, $suppliedPassword, $remember);
if (InputHelper::get('remember'))
{
$token = implode('|', [base64_encode($suppliedName), base64_encode($suppliedPassword)]);
setcookie('auth', TextHelper::encrypt($token), time() + 365 * 24 * 3600, '/');
}
StatusHelper::success();
self::redirectAfterLog();
}
@ -82,59 +30,10 @@ class AuthController
$context = getContext();
$context->viewName = null;
$context->layoutName = null;
self::doLogOut();
setcookie('auth', false, 0, '/');
Auth::logout();
\Chibi\Util\Url::forward(\Chibi\Router::linkTo(['IndexController', 'indexAction']));
}
public static function doLogOut()
{
unset($_SESSION['user']);
}
public static function doLogIn()
{
$context = getContext();
if (!isset($_SESSION['user']))
{
if (!empty($context->user) and $context->user->id)
{
$dbUser = UserModel::findById($context->user->id);
$dbUser->lastLoginDate = time();
UserModel::save($dbUser);
$_SESSION['user'] = serialize($dbUser);
}
else
{
$dummy = UserModel::spawn();
$dummy->name = UserModel::getAnonymousName();
$dummy->accessRank = AccessRank::Anonymous;
$_SESSION['user'] = serialize($dummy);
}
}
$context->user = unserialize($_SESSION['user']);
$context->loggedIn = $context->user->accessRank != AccessRank::Anonymous;
if (!$context->loggedIn)
{
try
{
self::tryAutoLogin();
}
catch (Exception $e)
{
}
}
}
public static function doReLog()
{
$context = getContext();
if ($context->user !== null)
self::doLogOut();
self::doLogIn();
}
public static function observeWorkFinish()
{
if (strpos(\Chibi\Util\Headers::get('Content-Type'), 'text/html') === false)
@ -146,4 +45,15 @@ class AuthController
return;
$_SESSION['login-redirect-url'] = $context->query;
}
private static function redirectAfterLog()
{
if (isset($_SESSION['login-redirect-url']))
{
\Chibi\Util\Url::forward(\Chibi\Util\Url::makeAbsolute($_SESSION['login-redirect-url']));
unset($_SESSION['login-redirect-url']);
return;
}
\Chibi\Util\Url::forward(\Chibi\Router::linkTo(['IndexController', 'indexAction']));
}
}

View file

@ -48,8 +48,8 @@ class CommentController
$comment = CommentModel::spawn();
$comment->setPost($post);
if ($context->loggedIn)
$comment->setCommenter($context->user);
if (Auth::isLoggedIn())
$comment->setCommenter(Auth::getCurrentUser());
else
$comment->setCommenter(null);
$comment->commentDate = time();

View file

@ -39,7 +39,7 @@ class PostController
$context->massTagQuery = $query;
if (!Access::check(Privilege::MassTag, 'all'))
$query = trim($query . ' submit:' . $context->user->name);
$query = trim($query . ' submit:' . Auth::getCurrentUser()->name);
}
$posts = PostSearchService::getEntities($query, $postsPerPage, $page);
@ -136,8 +136,8 @@ class PostController
//basic stuff
$anonymous = InputHelper::get('anonymous');
if ($context->loggedIn and !$anonymous)
$post->setUploader($context->user);
if (Auth::isLoggedIn() and !$anonymous)
$post->setUploader(Auth::getCurrentUser());
//store the post to get the ID in the logs
PostModel::forgeId($post);
@ -267,11 +267,11 @@ class PostController
if (!InputHelper::get('submit'))
return;
if (!$context->loggedIn)
if (!Auth::isLoggedIn())
throw new SimpleException('Not logged in');
UserModel::updateUserScore($context->user, $post, 1);
UserModel::addToUserFavorites($context->user, $post);
UserModel::updateUserScore(Auth::getCurrentUser(), $post, 1);
UserModel::addToUserFavorites(Auth::getCurrentUser(), $post);
StatusHelper::success();
}
@ -284,10 +284,10 @@ class PostController
if (!InputHelper::get('submit'))
return;
if (!$context->loggedIn)
if (!Auth::isLoggedIn())
throw new SimpleException('Not logged in');
UserModel::removeFromUserFavorites($context->user, $post);
UserModel::removeFromUserFavorites(Auth::getCurrentUser(), $post);
StatusHelper::success();
}
@ -300,10 +300,10 @@ class PostController
if (!InputHelper::get('submit'))
return;
if (!$context->loggedIn)
if (!Auth::isLoggedIn())
throw new SimpleException('Not logged in');
UserModel::updateUserScore($context->user, $post, $score);
UserModel::updateUserScore(Auth::getCurrentUser(), $post, $score);
StatusHelper::success();
}
@ -314,7 +314,7 @@ class PostController
Access::assert(Privilege::FeaturePost, Access::getIdentity($post->getUploader()));
PropertyModel::set(PropertyModel::FeaturedPostId, $post->id);
PropertyModel::set(PropertyModel::FeaturedPostDate, time());
PropertyModel::set(PropertyModel::FeaturedPostUserName, $context->user->name);
PropertyModel::set(PropertyModel::FeaturedPostUserName, Auth::getCurrentUser()->name);
StatusHelper::success();
LogHelper::log('{user} featured {post} on main page', ['post' => TextHelper::reprPost($post)]);
}
@ -346,8 +346,8 @@ class PostController
$context->transport->lastSearchQuery, $id);
}
$favorite = $context->user->hasFavorited($post);
$score = $context->user->getScore($post);
$favorite = Auth::getCurrentUser()->hasFavorited($post);
$score = Auth::getCurrentUser()->getScore($post);
$flagged = in_array(TextHelper::reprPost($post), SessionHelper::get('flagged', []));
$context->favorite = $favorite;

View file

@ -119,7 +119,7 @@ class UserController
return;
$name = $user->name;
if ($context->user->id == $user->id)
if (Auth::getCurrentUser()->id == $user->id)
{
$suppliedPasswordHash = UserModel::hashPassword($suppliedCurrentPassword, $user->passSalt);
if ($suppliedPasswordHash != $user->passHash)
@ -128,8 +128,8 @@ class UserController
$oldId = $user->id;
UserModel::remove($user);
if ($oldId == $context->user->id)
AuthController::doLogOut();
if ($oldId == Auth::getCurrentUser()->id)
Auth::logOut();
\Chibi\Util\Url::forward(\Chibi\Router::linkTo(['IndexController', 'indexAction']));
LogHelper::log('{user} removed {subject}\'s account', ['subject' => TextHelper::reprUser($name)]);
@ -165,9 +165,8 @@ class UserController
if ($user->accessRank != AccessRank::Anonymous)
UserModel::save($user);
if ($user->id == $context->user->id)
$context->user = $user;
AuthController::doReLog();
if ($user->id == Auth::getCurrentUser()->id)
Auth::setCurrentUser($user);
StatusHelper::success('Browsing settings updated!');
}
@ -232,7 +231,7 @@ class UserController
Access::getIdentity($user));
$suppliedEmail = UserModel::validateEmail($suppliedEmail);
if ($context->user->id == $user->id)
if (Auth::getCurrentUser()->id == $user->id)
{
$user->emailUnconfirmed = $suppliedEmail;
if (!empty($user->emailUnconfirmed))
@ -262,15 +261,15 @@ class UserController
'rank' => AccessRank::toString($suppliedAccessRank)]);
}
if ($context->user->id == $user->id)
if (Auth::getCurrentUser()->id == $user->id)
{
$suppliedPasswordHash = UserModel::hashPassword($suppliedCurrentPassword, $user->passSalt);
if ($suppliedPasswordHash != $currentPasswordHash)
throw new SimpleException('Must supply valid current password');
}
UserModel::save($user);
if ($context->user->id == $user->id)
AuthController::doReLog();
if (Auth::getCurrentUser()->id == $user->id)
Auth::setCurrentUser($user);
if ($confirmMail)
self::sendEmailChangeConfirmation($user);
@ -330,20 +329,20 @@ class UserController
public function toggleSafetyAction($safety)
{
$context = getContext();
$user = Auth::getCurrentUser();
Access::assert(
Privilege::ChangeUserSettings,
Access::getIdentity($context->user));
Access::getIdentity($user));
if (!in_array($safety, PostSafety::getAll()))
throw new SimpleExcetpion('Invalid safety');
$context->user->enableSafety($safety,
!$context->user->hasEnabledSafety($safety));
$user->enableSafety($safety, !$user->hasEnabledSafety($safety));
if ($context->user->accessRank != AccessRank::Anonymous)
UserModel::save($context->user);
AuthController::doReLog();
if ($user->accessRank != AccessRank::Anonymous)
UserModel::save($user);
Auth::setCurrentUser($user);
StatusHelper::success();
}
@ -354,7 +353,7 @@ class UserController
$context->handleExceptions = true;
//check if already logged in
if ($context->loggedIn)
if (Auth::isLoggedIn())
{
\Chibi\Util\Url::forward(\Chibi\Router::linkTo(['IndexController', 'indexAction']));
return;
@ -425,8 +424,7 @@ class UserController
if (!getConfig()->registration->needEmailForRegistering and !getConfig()->registration->staffActivation)
{
$context->user = $dbUser;
AuthController::doReLog();
Auth::setCurrentUser($dbUser);
}
}
@ -454,8 +452,7 @@ class UserController
if (!getConfig()->registration->staffActivation)
{
$context->user = $dbUser;
AuthController::doReLog();
Auth::setCurrentUser($dbUser);
}
}
@ -484,8 +481,7 @@ class UserController
$message = 'Password reset successful. Your new password is **' . $randomPassword . '**.';
StatusHelper::success($message);
$context->user = $dbUser;
AuthController::doReLog();
Auth::setCurrentUser($dbUser);
}
public function passwordResetProxyAction()

View file

@ -71,10 +71,9 @@ class LogEvent
$this->text = $text;
$this->ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
$context = getContext();
$tokens['anon'] = UserModel::getAnonymousName();
if ($context->loggedIn and isset($context->user))
$tokens['user'] = TextHelper::reprUser($context->user->name);
if (Auth::isLoggedIn())
$tokens['user'] = TextHelper::reprUser(Auth::getCurrentUser()->name);
else
$tokens['user'] = $tokens['anon'];
$this->tokens = $tokens;

View file

@ -24,7 +24,7 @@ class PostSearchParser extends AbstractSearchParser
protected function processTeardown()
{
if (getContext()->user->hasEnabledHidingDislikedPosts() and !$this->showDisliked)
if (Auth::getCurrentUser()->hasEnabledHidingDislikedPosts() and !$this->showDisliked)
$this->processComplexToken('special', 'disliked', true);
if (!Access::check(Privilege::ListPosts, 'hidden') or !$this->showHidden)
@ -146,11 +146,12 @@ class PostSearchParser extends AbstractSearchParser
elseif ($key == 'special')
{
$context = getContext();
$activeUser = Auth::getCurrentUser();
$value = strtolower($value);
if (in_array($value, ['fav', 'favs', 'favd']))
{
return $this->prepareCriterionForComplexToken('fav', $context->user->name);
return $this->prepareCriterionForComplexToken('fav', $activeUser->name);
}
elseif (in_array($value, ['like', 'liked', 'likes']))
@ -159,7 +160,7 @@ class PostSearchParser extends AbstractSearchParser
{
$this->statement->addLeftOuterJoin('post_score', (new Sql\ConjunctionFunctor)
->add(new Sql\EqualsFunctor('post_score.post_id', 'post.id'))
->add(new Sql\EqualsFunctor('post_score.user_id', new Sql\Binding($context->user->id))));
->add(new Sql\EqualsFunctor('post_score.user_id', new Sql\Binding($activeUser->id))));
}
return new Sql\EqualsFunctor(new Sql\IfNullFunctor('post_score.score', '0'), '1');
}
@ -171,7 +172,7 @@ class PostSearchParser extends AbstractSearchParser
{
$this->statement->addLeftOuterJoin('post_score', (new Sql\ConjunctionFunctor)
->add(new Sql\EqualsFunctor('post_score.post_id', 'post.id'))
->add(new Sql\EqualsFunctor('post_score.user_id', new Sql\Binding($context->user->id))));
->add(new Sql\EqualsFunctor('post_score.user_id', new Sql\Binding($activeUser->id))));
}
return new Sql\EqualsFunctor(new Sql\IfNullFunctor('post_score.score', '0'), '-1');
}

View file

@ -42,7 +42,7 @@ if (!function_exists('pageUrl'))
<?php if (!empty($pagesVisible)): ?>
<?php
Assets::addStylesheet('paginator.css');
if ($this->context->user->hasEnabledEndlessScrolling())
if (Auth::getCurrentUser()->hasEnabledEndlessScrolling())
Assets::addScript('paginator-endless.js');
?>

View file

@ -41,7 +41,7 @@ if ($masstag)
<?php endif ?>
<a class="link"
<?php if ($this->context->user->hasEnabledPostTagTitles()): ?>
<?php if (Auth::getCurrentUser()->hasEnabledPostTagTitles()): ?>
title="<?= TextHelper::reprTags($this->context->post->getTags()) ?>"
<?php endif ?>
href="<?= \Chibi\Router::linkTo(['PostController', 'viewAction'], ['id' => $this->context->post->id]) ?>">

View file

@ -57,10 +57,10 @@
\Chibi\Router::linkTo(['UserController', 'listAction']),
$activeController == 'user' and $activeAction != 'registration' and
(!isset($this->context->route->arguments['name']) or
$this->context->route->arguments['name'] != $this->context->user->name));
$this->context->route->arguments['name'] != Auth::getCurrentUser()->name));
}
if (!$this->context->loggedIn)
if (!Auth::isLoggedIn())
{
$registerNavItem(
'Log in',
@ -76,9 +76,9 @@
{
$registerNavItem(
'My account',
\Chibi\Router::linkTo(['UserController', 'viewAction'], ['name' => $this->context->user->name]),
\Chibi\Router::linkTo(['UserController', 'viewAction'], ['name' => Auth::getCurrentUser()->name]),
$activeController == 'user' and isset($this->context->route->arguments['name']) and
$this->context->route->arguments['name'] == $this->context->user->name);
$this->context->route->arguments['name'] == Auth::getCurrentUser()->name);
$registerNavItem(
'Log out',
@ -104,7 +104,7 @@
}
?>
<?php if (Access::check(Privilege::ChangeUserSettings, Access::getIdentity($this->context->user))): ?>
<?php if (Access::check(Privilege::ChangeUserSettings, Access::getIdentity(Auth::getCurrentUser()))): ?>
<li class="safety">
<ul>
<?php foreach (PostSafety::getAll() as $safety): ?>
@ -117,13 +117,13 @@
TextCaseConverter::CAMEL_CASE,
TextCaseConverter::SPINAL_CASE) ?>">
<a class="<?= $this->context->user->hasEnabledSafety($safety) ? 'enabled' : 'disabled' ?>"
<a class="<?= Auth::getCurrentUser()->hasEnabledSafety($safety) ? 'enabled' : 'disabled' ?>"
href="<?= \Chibi\Router::linkTo(
['UserController', 'toggleSafetyAction'],
['safety' => $safety]) ?>"
title="<?= sprintf('Searching %s posts: %s',
PostSafety::toDisplayString($safety),
$this->context->user->hasEnabledSafety($safety)
Auth::getCurrentUser()->hasEnabledSafety($safety)
? 'enabled'
: 'disabled') ?>">

View file

@ -7,7 +7,7 @@
autocomplete="off"
data-confirm-text="Are you sure you want to delete your account?">
<?php if ($this->context->user->id == $this->context->transport->user->id): ?>
<?php if (Auth::getCurrentUser()->id == $this->context->transport->user->id): ?>
<div class="form-row current-password">
<label for="current-password">Current password:</label>
<div class="input-wrapper">

View file

@ -6,7 +6,7 @@
class="edit"
autocomplete="off">
<?php if ($this->context->user->id == $this->context->transport->user->id): ?>
<?php if (Auth::getCurrentUser()->id == $this->context->transport->user->id): ?>
<div class="form-row current-password">
<label for="current-password">Current password:</label>
<div class="input-wrapper">

View file

@ -2,7 +2,7 @@
Assets::setSubTitle('users');
Assets::addStylesheet('user-list.css');
Assets::addStylesheet('paginator.css');
if ($this->context->user->hasEnabledEndlessScrolling())
if (Auth::getCurrentUser()->hasEnabledEndlessScrolling())
Assets::addScript('paginator-endless.js');
?>