Rewrote session code to be OOP.

This commit is contained in:
flash 2020-05-25 19:58:06 +00:00
parent 58f22c9d74
commit d2aa478c58
58 changed files with 753 additions and 414 deletions

View file

@ -0,0 +1,22 @@
<?php
namespace Misuzu\DatabaseMigrations\SessionsTableFixes;
use PDO;
function migrate_up(PDO $conn): void {
$conn->exec("
ALTER TABLE `msz_sessions`
CHANGE COLUMN `session_key` `session_key` BINARY(64) NOT NULL AFTER `user_id`,
CHANGE COLUMN `session_expires` `session_expires` TIMESTAMP NOT NULL DEFAULT DATE_ADD(NOW(), INTERVAL 1 MONTH) AFTER `session_country`,
ADD INDEX `sessions_created_index` (`session_created`);
");
}
function migrate_down(PDO $conn): void {
$conn->exec("
ALTER TABLE `msz_sessions`
CHANGE COLUMN `session_key` `session_key` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_bin' AFTER `user_id`,
CHANGE COLUMN `session_expires` `session_expires` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP() AFTER `session_country`,
DROP INDEX `sessions_created_index`;
");
}

View file

@ -8,6 +8,8 @@ use Misuzu\Net\GeoIP;
use Misuzu\Net\IPAddress;
use Misuzu\Users\User;
use Misuzu\Users\UserNotFoundException;
use Misuzu\Users\UserSession;
use Misuzu\Users\UserSessionNotFoundException;
define('MSZ_STARTUP', microtime(true));
define('MSZ_ROOT', __DIR__);
@ -418,19 +420,49 @@ MIG;
exit;
}
if(!empty($_COOKIE['msz_uid']) && !empty($_COOKIE['msz_sid'])
&& ctype_digit($_COOKIE['msz_uid']) && ctype_xdigit($_COOKIE['msz_sid'])
&& strlen($_COOKIE['msz_sid']) === 64) {
$_COOKIE['msz_auth'] = Base64::decode(user_session_cookie_pack($_COOKIE['msz_uid'], $_COOKIE['msz_sid']), true);
setcookie('msz_auth', $_COOKIE['msz_auth'], strtotime('1 year'), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
if(isset($_COOKIE['msz_uid']) && isset($_COOKIE['msz_sid'])) {
$authToken = (new AuthToken)
->setUserId(filter_input(INPUT_COOKIE, 'msz_uid', FILTER_SANITIZE_NUMBER_INT) ?? 0)
->setSessionToken(filter_input(INPUT_COOKIE, 'msz_sid', FILTER_SANITIZE_STRING) ?? '');
if($authToken->isValid())
setcookie('msz_auth', $authToken->pack(), strtotime('1 year'), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
setcookie('msz_uid', '', -3600, '/', '', !empty($_SERVER['HTTPS']), true);
setcookie('msz_sid', '', -3600, '/', '', !empty($_SERVER['HTTPS']), true);
}
if(!empty($_COOKIE['msz_auth']) && is_string($_COOKIE['msz_auth'])) {
$cookieData = user_session_cookie_unpack(Base64::decode($_COOKIE['msz_auth'], true));
if(!isset($authToken))
$authToken = AuthToken::unpack(filter_input(INPUT_COOKIE, 'msz_auth', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) ?? '');
if($authToken->isValid()) {
try {
$sessionInfo = $authToken->getSession();
if($sessionInfo->hasExpired()) {
$sessionInfo->delete();
} elseif($sessionInfo->getUserId() === $authToken->getUserId()) {
$userInfo = $sessionInfo->getUser();
if(!$userInfo->isDeleted()) {
$sessionInfo->setCurrent();
$userInfo->setCurrent();
if(!empty($cookieData) && user_session_start($cookieData['user_id'], $cookieData['session_token'])) {
$sessionInfo->bump();
if($sessionInfo->shouldBumpExpire())
setcookie('msz_auth', $authToken->pack(), $sessionInfo->getExpiresTime(), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
}
}
} catch(UserNotFoundException $ex) {
UserSession::unsetCurrent();
User::unsetCurrent();
} catch(UserSessionNotFoundException $ex) {
UserSession::unsetCurrent();
User::unsetCurrent();
}
if(!UserSession::hasCurrent()) {
setcookie('msz_auth', '', -9001, '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
setcookie('msz_auth', '', -9001, '/', '', !empty($_SERVER['HTTPS']), true);
} else {
$userDisplayInfo = DB::prepare('
SELECT
u.`user_id`, u.`username`, u.`user_background_settings`, u.`user_deleted`,
@ -439,38 +471,19 @@ MIG;
LEFT JOIN `msz_roles` AS r
ON u.`display_role` = r.`role_id`
WHERE `user_id` = :user_id
');
$userDisplayInfo->bind('user_id', $cookieData['user_id']);
$userDisplayInfo = $userDisplayInfo->fetch();
') ->bind('user_id', $userInfo->getId())
->fetch();
if($userDisplayInfo) {
if(!is_null($userDisplayInfo['user_deleted'])) {
setcookie('msz_auth', '', -9001, '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
setcookie('msz_auth', '', -9001, '/', '', !empty($_SERVER['HTTPS']), true);
user_session_stop(true);
$userDisplayInfo = [];
} else {
try {
User::byId($cookieData['user_id'])->setCurrent();
} catch(UserNotFoundException $ex) {}
user_bump_last_active($userInfo->getId());
user_bump_last_active($cookieData['user_id']);
user_session_bump_active(user_session_current('session_id'));
if(user_session_current('session_expires_bump')) {
setcookie('msz_auth', $_COOKIE['msz_auth'], strtotime('1 month'), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
}
$userDisplayInfo['perms'] = perms_get_user($userDisplayInfo['user_id']);
$userDisplayInfo['ban_expiration'] = user_warning_check_expiration($userDisplayInfo['user_id'], MSZ_WARN_BAN);
$userDisplayInfo['silence_expiration'] = $userDisplayInfo['ban_expiration'] > 0 ? 0 : user_warning_check_expiration($userDisplayInfo['user_id'], MSZ_WARN_SILENCE);
}
}
$userDisplayInfo['perms'] = perms_get_user($userInfo->getId());
$userDisplayInfo['ban_expiration'] = user_warning_check_expiration($userInfo->getId(), MSZ_WARN_BAN);
$userDisplayInfo['silence_expiration'] = $userDisplayInfo['ban_expiration'] > 0 ? 0 : user_warning_check_expiration($userInfo->getId(), MSZ_WARN_SILENCE);
}
}
CSRF::setGlobalSecretKey(Config::get('csrf.secret', Config::TYPE_STR, 'soup'));
CSRF::setGlobalIdentity(empty($userDisplayInfo) ? IPAddress::remote() : $cookieData['session_token']);
CSRF::setGlobalIdentity(UserSession::hasCurrent() ? UserSession::getCurrent()->getToken() : IPAddress::remote());
if(Config::get('private.enabled', Config::TYPE_BOOL)) {
$onLoginPage = $_SERVER['PHP_SELF'] === url('auth-login');
@ -478,14 +491,16 @@ MIG;
$misuzuBypassLockdown = !empty($misuzuBypassLockdown) || $onLoginPage;
if(!$misuzuBypassLockdown) {
if(user_session_active()) {
if(UserSession::hasCurrent()) {
$privatePermCat = Config::get('private.perm.cat', Config::TYPE_STR);
$privatePermVal = Config::get('private.perm.val', Config::TYPE_INT);
if(!empty($privatePermCat) && $privatePermVal > 0) {
if(!perms_check_user($privatePermCat, $userDisplayInfo['user_id'], $privatePermVal)) {
if(!perms_check_user($privatePermCat, User::getCurrent()->getId(), $privatePermVal)) {
// au revoir
unset($userDisplayInfo);
user_session_stop(); // au revoir
UserSession::unsetCurrent();
User::unsetCurrent();
}
}
} elseif(!$onLoginPage && !($onPasswordPage && Config::get('private.allow_password_reset', Config::TYPE_BOOL, true))) {
@ -495,14 +510,13 @@ MIG;
}
}
if(!empty($userDisplayInfo)) {
if(!empty($userDisplayInfo)) // delete this
Template::set('current_user', $userDisplayInfo);
}
$inManageMode = starts_with($_SERVER['REQUEST_URI'], '/manage');
$hasManageAccess = !empty($userDisplayInfo['user_id'])
&& !user_warning_check_restriction($userDisplayInfo['user_id'])
&& perms_check_user(MSZ_PERMS_GENERAL, $userDisplayInfo['user_id'], MSZ_PERM_GENERAL_CAN_MANAGE);
$hasManageAccess = User::hasCurrent()
&& !user_warning_check_restriction(User::getCurrent()->getId())
&& perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_CAN_MANAGE);
Template::set('has_manage_access', $hasManageAccess);
if($inManageMode) {
@ -511,6 +525,6 @@ MIG;
exit;
}
Template::set('manage_menu', manage_get_menu($userDisplayInfo['user_id'] ?? 0));
Template::set('manage_menu', manage_get_menu(User::getCurrent()->getId()));
}
}

View file

@ -1,14 +1,17 @@
<?php
namespace Misuzu;
use Misuzu\AuthToken;
use Misuzu\Net\IPAddress;
use Misuzu\Users\User;
use Misuzu\Users\UserNotFoundException;
use Misuzu\Users\UserLoginAttempt;
use Misuzu\Users\UserSession;
use Misuzu\Users\UserSessionCreationFailedException;
require_once '../../misuzu.php';
if(user_session_active()) {
if(UserSession::hasCurrent()) {
url_redirect('index');
return;
}
@ -23,7 +26,6 @@ $notices = [];
$siteIsPrivate = Config::get('private.enable', Config::TYPE_BOOL);
$loginPermCat = $siteIsPrivate ? Config::get('private.perm.cat', Config::TYPE_STR) : '';
$loginPermVal = $siteIsPrivate ? Config::get('private.perm.val', Config::TYPE_INT) : 0;
$ipAddress = IPAddress::remote();
$remainingAttempts = UserLoginAttempt::remaining();
while(!empty($_POST['login']) && is_array($_POST['login'])) {
@ -32,7 +34,6 @@ while(!empty($_POST['login']) && is_array($_POST['login'])) {
break;
}
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$loginRedirect = empty($_POST['login']['redirect']) || !is_string($_POST['login']['redirect']) ? '' : $_POST['login']['redirect'];
if(empty($_POST['login']['username']) || empty($_POST['login']['password'])
@ -54,58 +55,56 @@ while(!empty($_POST['login']) && is_array($_POST['login'])) {
$loginFailedError = "Invalid username or password, {$attemptsRemainingError}.";
try {
$userData = User::findForLogin($_POST['login']['username']);
$userInfo = User::findForLogin($_POST['login']['username']);
} catch(UserNotFoundException $ex) {
UserLoginAttempt::create(false);
$notices[] = $loginFailedError;
break;
}
if(!$userData->hasPassword()) {
if(!$userInfo->hasPassword()) {
$notices[] = 'Your password has been invalidated, please reset it.';
break;
}
if($userData->isDeleted() || !$userData->checkPassword($_POST['login']['password'])) {
UserLoginAttempt::create(false, $userData);
if($userInfo->isDeleted() || !$userInfo->checkPassword($_POST['login']['password'])) {
UserLoginAttempt::create(false, $userInfo);
$notices[] = $loginFailedError;
break;
}
if($userData->passwordNeedsRehash()) {
$userData->setPassword($_POST['login']['password']);
if($userInfo->passwordNeedsRehash()) {
$userInfo->setPassword($_POST['login']['password']);
}
if(!empty($loginPermCat) && $loginPermVal > 0 && !perms_check_user($loginPermCat, $userData->getId(), $loginPermVal)) {
if(!empty($loginPermCat) && $loginPermVal > 0 && !perms_check_user($loginPermCat, $userInfo->getId(), $loginPermVal)) {
$notices[] = "Login succeeded, but you're not allowed to browse the site right now.";
UserLoginAttempt::create(true, $userData);
UserLoginAttempt::create(true, $userInfo);
break;
}
if($userData->hasTOTP()) {
if($userInfo->hasTOTP()) {
url_redirect('auth-two-factor', [
'token' => user_auth_tfa_token_create($userData->getId()),
'token' => user_auth_tfa_token_create($userInfo->getId()),
]);
return;
}
UserLoginAttempt::create(true, $userData);
$sessionKey = user_session_create($userData->getId(), $ipAddress, $userAgent);
UserLoginAttempt::create(true, $userInfo);
if(empty($sessionKey)) {
try {
$sessionInfo = UserSession::create($userInfo);
$sessionInfo->setCurrent();
} catch(UserSessionCreationFailedException $ex) {
$notices[] = "Something broke while creating a session for you, please tell an administrator or developer about this!";
break;
}
user_session_start($userData->getId(), $sessionKey);
$authToken = AuthToken::create($userInfo, $sessionInfo);
setcookie('msz_auth', $authToken->pack(), $sessionInfo->getExpiresTime(), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
$cookieLife = strtotime(user_session_current('session_expires'));
$cookieValue = Base64::encode(user_session_cookie_pack($userData->getId(), $sessionKey), true);
setcookie('msz_auth', $cookieValue, $cookieLife, '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
if(!is_local_url($loginRedirect)) {
if(!is_local_url($loginRedirect))
$loginRedirect = url('index');
}
redirect($loginRedirect);
return;

View file

@ -1,9 +1,12 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
use Misuzu\Users\UserSession;
require_once '../../misuzu.php';
if(!user_session_active()) {
if(!UserSession::hasCurrent()) {
url_redirect('index');
return;
}
@ -11,7 +14,9 @@ if(!user_session_active()) {
if(CSRF::validateRequest()) {
setcookie('msz_auth', '', -9001, '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
setcookie('msz_auth', '', -9001, '/', '', !empty($_SERVER['HTTPS']), true);
user_session_stop(true);
UserSession::getCurrent()->delete();
UserSession::unsetCurrent();
User::unsetCurrent();
url_redirect('index');
return;
}

View file

@ -6,10 +6,11 @@ use Misuzu\AuditLog;
use Misuzu\Net\IPAddress;
use Misuzu\Users\User;
use Misuzu\Users\UserLoginAttempt;
use Misuzu\Users\UserSession;
require_once '../../misuzu.php';
if(user_session_active()) {
if(UserSession::hasCurrent()) {
url_redirect('settings-account');
return;
}

View file

@ -5,10 +5,11 @@ use Misuzu\Net\IPAddress;
use Misuzu\Net\IPAddressBlacklist;
use Misuzu\Users\User;
use Misuzu\Users\UserLoginAttempt;
use Misuzu\Users\UserSession;
require_once '../../misuzu.php';
if(user_session_active()) {
if(UserSession::hasCurrent()) {
url_redirect('index');
return;
}

View file

@ -4,10 +4,12 @@ namespace Misuzu;
use Misuzu\Net\IPAddress;
use Misuzu\Users\User;
use Misuzu\Users\UserLoginAttempt;
use Misuzu\Users\UserSession;
use Misuzu\Users\UserSessionCreationFailedException;
require_once '../../misuzu.php';
if(user_session_active()) {
if(UserSession::hasCurrent()) {
url_redirect('index');
return;
}
@ -22,11 +24,11 @@ $tokenInfo = user_auth_tfa_token_info(
)
);
$userData = User::byId($tokenInfo['user_id']);
$userInfo = User::byId($tokenInfo['user_id']);
// checking user_totp_key specifically because there's a fringe chance that
// there's a token present, but totp is actually disabled
if(!$userData->hasTOTP()) {
if(!$userInfo->hasTOTP()) {
url_redirect('auth-login');
return;
}
@ -50,30 +52,29 @@ while(!empty($twofactor)) {
break;
}
if(!in_array($twofactor['code'], $userData->getValidTOTPTokens())) {
if(!in_array($twofactor['code'], $userInfo->getValidTOTPTokens())) {
$notices[] = sprintf(
"Invalid two factor code, %d attempt%s remaining",
$remainingAttempts - 1,
$remainingAttempts === 2 ? '' : 's'
);
UserLoginAttempt::create(false, $userData);
UserLoginAttempt::create(false, $userInfo);
break;
}
UserLoginAttempt::create(true, $userData);
$sessionKey = user_session_create($tokenInfo['user_id'], $ipAddress, $userAgent);
UserLoginAttempt::create(true, $userInfo);
user_auth_tfa_token_invalidate($tokenInfo['tfa_token']);
if(empty($sessionKey)) {
try {
$sessionInfo = UserSession::create($userInfo);
$sessionInfo->setCurrent();
} catch(UserSessionCreationFailedException $ex) {
$notices[] = "Something broke while creating a session for you, please tell an administrator or developer about this!";
break;
}
user_auth_tfa_token_invalidate($tokenInfo['tfa_token']);
user_session_start($tokenInfo['user_id'], $sessionKey);
$cookieLife = strtotime(user_session_current('session_expires'));
$cookieValue = Base64::encode(user_session_cookie_pack($tokenInfo['user_id'], $sessionKey), true);
setcookie('msz_auth', $cookieValue, $cookieLife, '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
$authToken = AuthToken::create($userInfo, $sessionInfo);
setcookie('msz_auth', $authToken->pack(), $sessionInfo->getExpiresTime(), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
if(!is_local_url($redirect)) {
$redirect = url('index');

View file

@ -1,6 +1,8 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../misuzu.php';
$forumId = !empty($_GET['f']) && is_string($_GET['f']) ? (int)$_GET['f'] : 0;
@ -12,7 +14,8 @@ if($forumId === 0) {
}
$forum = forum_get($forumId);
$forumUserId = user_session_current('user_id', 0);
$forumUser = User::getCurrent();
$forumUserId = $forumUser === null ? 0 : $forumUser->getId();
if(empty($forum) || ($forum['forum_type'] == MSZ_FORUM_TYPE_LINK && empty($forum['forum_link']))) {
echo render_error(404);

View file

@ -1,25 +1,27 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../misuzu.php';
$indexMode = !empty($_GET['m']) && is_string($_GET['m']) ? (string)$_GET['m'] : '';
$forumId = !empty($_GET['f']) && is_string($_GET['f']) ? (int)$_GET['f'] : 0;
$currentUser = User::getCurrent();
$currentUserId = $currentUser === null ? 0 : $currentUser->getId();
switch($indexMode) {
case 'mark':
url_redirect($forumId < 1 ? 'forum-mark-global' : 'forum-mark-single', ['forum' => $forumId]);
break;
default:
$categories = forum_get_root_categories(user_session_current('user_id', 0));
$categories = forum_get_root_categories($currentUserId);
$blankForum = count($categories) < 1;
foreach($categories as $key => $category) {
$categories[$key]['forum_subforums'] = forum_get_children(
$category['forum_id'],
user_session_current('user_id', 0)
);
$categories[$key]['forum_subforums'] = forum_get_children($category['forum_id'], $currentUserId);
foreach($categories[$key]['forum_subforums'] as $skey => $sub) {
if(!forum_may_have_children($sub['forum_type'])) {
@ -27,10 +29,7 @@ switch($indexMode) {
}
$categories[$key]['forum_subforums'][$skey]['forum_subforums']
= forum_get_children(
$sub['forum_id'],
user_session_current('user_id', 0)
);
= forum_get_children($sub['forum_id'], $currentUserId);
}
}

View file

@ -1,9 +1,11 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_FORUM, user_session_current('user_id'), MSZ_PERM_FORUM_VIEW_LEADERBOARD)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_FORUM, User::getCurrent()->getId(), MSZ_PERM_FORUM_VIEW_LEADERBOARD)) {
echo render_error(403);
return;
}
@ -15,7 +17,7 @@ $leaderboardId = !empty($_GET['id']) && is_string($_GET['id'])
: MSZ_FORUM_LEADERBOARD_CATEGORY_ALL;
$leaderboardIdLength = strlen($leaderboardId);
$leaderboardYear = $leaderboardIdLength === 4 || $leaderboardIdLength === 6 ? substr($leaderboardId, 0, 4) : null;
$leaderboardYear = $leaderboardIdLength === 4 || $leaderboardIdLength === 6 ? substr($leaderboardId, 0, 4) : null;
$leaderboardMonth = $leaderboardIdLength === 6 ? substr($leaderboardId, 4, 2) : null;
$unrankedForums = !empty($_GET['allow_unranked']) ? [] : Config::get('forum_leader.unranked.forum', Config::TYPE_ARR);

View file

@ -1,6 +1,8 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../misuzu.php';
$redirect = !empty($_SERVER['HTTP_REFERER']) && empty($_SERVER['HTTP_X_MISUZU_XHR']) ? $_SERVER['HTTP_REFERER'] : '';
@ -18,12 +20,14 @@ if(!CSRF::validateRequest()) {
return;
}
if(!user_session_active()) {
$currentUser = User::getCurrent();
if($currentUser === null) {
echo render_info_or_json($isXHR, 'You must be logged in to vote on polls.', 401);
return;
}
$currentUserId = user_session_current('user_id', 0);
$currentUserId = $currentUser->getId();
if(user_warning_check_expiration($currentUserId, MSZ_WARN_BAN) > 0) {
echo render_info_or_json($isXHR, 'You have been banned, check your profile for more information.', 403);

View file

@ -2,6 +2,8 @@
namespace Misuzu;
use Misuzu\AuditLog;
use Misuzu\Users\User;
use Misuzu\Users\UserSession;
require_once '../../misuzu.php';
@ -23,12 +25,13 @@ if($isXHR) {
$postRequestVerified = CSRF::validateRequest();
if(!empty($postMode) && !user_session_active()) {
if(!empty($postMode) && !UserSession::hasCurrent()) {
echo render_info_or_json($isXHR, 'You must be logged in to manage posts.', 401);
return;
}
$currentUserId = (int)user_session_current('user_id', 0);
$currentUser = User::getCurrent():
$currentUserId = $currentUser === null ? 0 : $currentUser->getId();
if(user_warning_check_expiration($currentUserId, MSZ_WARN_BAN) > 0) {
echo render_info_or_json($isXHR, 'You have been banned, check your profile for more information.', 403);
@ -251,7 +254,7 @@ switch($postMode) {
break;
}
$postFind = forum_post_find($postInfo['post_id'], user_session_current('user_id', 0));
$postFind = forum_post_find($postInfo['post_id'], $currentUserId);
if(empty($postFind)) {
echo render_error(404);

View file

@ -3,15 +3,20 @@ namespace Misuzu;
use Misuzu\Net\IPAddress;
use Misuzu\Parsers\Parser;
use Misuzu\Users\User;
require_once '../../misuzu.php';
if(!user_session_active()) {
$currentUser = User::getCurrent();
if($currentUser === null) {
echo render_error(401);
return;
}
if(user_warning_check_restriction(user_session_current('user_id', 0))) {
$currentUserId = $currentUser->getId();
if(user_warning_check_restriction($currentUserId)) {
echo render_error(403);
return;
}
@ -83,7 +88,7 @@ if(empty($forum)) {
return;
}
$perms = forum_perms_get_user($forum['forum_id'], user_session_current('user_id'))[MSZ_FORUM_PERMS_GENERAL];
$perms = forum_perms_get_user($forum['forum_id'], $currentUserId)[MSZ_FORUM_PERMS_GENERAL];
if($forum['forum_archived']
|| (!empty($topic['topic_locked']) && !perms_check($perms, MSZ_FORUM_PERM_LOCK_TOPIC))
@ -121,7 +126,7 @@ if($mode === 'edit') {
return;
}
if(!perms_check($perms, $post['poster_id'] === user_session_current('user_id') ? MSZ_FORUM_PERM_EDIT_POST : MSZ_FORUM_PERM_EDIT_ANY_POST)) {
if(!perms_check($perms, $post['poster_id'] === $currentUserId ? MSZ_FORUM_PERM_EDIT_POST : MSZ_FORUM_PERM_EDIT_ANY_POST)) {
echo render_error(403);
return;
}
@ -142,7 +147,7 @@ if(!empty($_POST)) {
$isEditingTopic = empty($topic) || ($mode === 'edit' && $post['is_opening_post']);
if($mode === 'create') {
$timeoutCheck = max(1, forum_timeout($forumId, user_session_current('user_id')));
$timeoutCheck = max(1, forum_timeout($forumId, $currentUserId));
if($timeoutCheck < 5) {
$notices[] = sprintf("You're posting too quickly! Please wait %s seconds before posting again.", number_format($timeoutCheck));
@ -195,7 +200,7 @@ if(!empty($_POST)) {
} else {
$topicId = forum_topic_create(
$forum['forum_id'],
user_session_current('user_id', 0),
$currentUserId,
$topicTitle,
$topicType
);
@ -204,13 +209,13 @@ if(!empty($_POST)) {
$postId = forum_post_create(
$topicId,
$forum['forum_id'],
user_session_current('user_id', 0),
$currentUserId,
IPAddress::remote(),
$postText,
$postParser,
$postSignature
);
forum_topic_mark_read(user_session_current('user_id', 0), $topicId, $forum['forum_id']);
forum_topic_mark_read($currentUserId, $topicId, $forum['forum_id']);
forum_count_increase($forum['forum_id'], empty($topic));
break;
@ -248,7 +253,7 @@ if($mode === 'edit') { // $post is pretty much sure to be populated at this poin
Template::set('posting_post', $post);
}
$displayInfo = forum_posting_info(user_session_current('user_id'));
$displayInfo = forum_posting_info($currentUserId);
Template::render('forum.posting', [
'posting_breadcrumbs' => forum_get_breadcrumbs($forumId),

View file

@ -1,14 +1,16 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../misuzu.php';
if(!MSZ_DEBUG) {
if(!MSZ_DEBUG)
return;
}
$topicId = !empty($_GET['t']) && is_string($_GET['t']) ? (int)$_GET['t'] : 0;
$topicUserId = user_session_current('user_id', 0);
$topicUser = User::getCurrent();
$topicUserId = $topicUser === null ? 0 : $topicUser->getId();
if($topicUserId < 1) {
echo render_error(403);
@ -48,6 +50,6 @@ if(!forum_has_priority_voting($topic['forum_type'])) {
return;
}
forum_topic_priority_increase($topicId, user_session_current('user_id', 0));
forum_topic_priority_increase($topicId, $topicUserId);
url_redirect('forum-topic', ['topic' => $topicId]);

View file

@ -2,6 +2,8 @@
namespace Misuzu;
use Misuzu\AuditLog;
use Misuzu\Users\User;
use Misuzu\Users\UserSession;
require_once '../../misuzu.php';
@ -10,7 +12,8 @@ $topicId = !empty($_GET['t']) && is_string($_GET['t']) ? (int)$_GET['t'] : 0;
$moderationMode = !empty($_GET['m']) && is_string($_GET['m']) ? (string)$_GET['m'] : '';
$submissionConfirmed = !empty($_GET['confirm']) && is_string($_GET['confirm']) && $_GET['confirm'] === '1';
$topicUserId = user_session_current('user_id', 0);
$topicUser = User::getCurrent();
$topicUserId = $topicUser === null ? 0 : $this->getId();
if($topicId < 1 && $postId > 0) {
$postInfo = forum_post_find($postId, $topicUserId);
@ -91,7 +94,7 @@ if(in_array($moderationMode, $validModerationModes, true)) {
header(CSRF::header());
if(!user_session_active()) {
if(!UserSession::hasCurrent()) {
echo render_info_or_json($isXHR, 'You must be logged in to manage posts.', 401);
return;
}

View file

@ -11,7 +11,7 @@ use Misuzu\Users\UserNotFoundException;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_CHANGELOG, user_session_current('user_id'), MSZ_PERM_CHANGELOG_MANAGE_CHANGES)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_CHANGELOG, User::getCurrent()->getId(), MSZ_PERM_CHANGELOG_MANAGE_CHANGES)) {
echo render_error(403);
return;
}

View file

@ -2,10 +2,11 @@
namespace Misuzu;
use Misuzu\Changelog\ChangelogChange;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_CHANGELOG, user_session_current('user_id'), MSZ_PERM_CHANGELOG_MANAGE_CHANGES)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_CHANGELOG, User::getCurrent()->getId(), MSZ_PERM_CHANGELOG_MANAGE_CHANGES)) {
echo render_error(403);
return;
}

View file

@ -8,7 +8,7 @@ use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_CHANGELOG, user_session_current('user_id'), MSZ_PERM_CHANGELOG_MANAGE_TAGS)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_CHANGELOG, User::getCurrent()->getId(), MSZ_PERM_CHANGELOG_MANAGE_TAGS)) {
echo render_error(403);
return;
}

View file

@ -2,10 +2,11 @@
namespace Misuzu;
use Misuzu\Changelog\ChangelogTag;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_CHANGELOG, user_session_current('user_id'), MSZ_PERM_CHANGELOG_MANAGE_TAGS)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_CHANGELOG, User::getCurrent()->getId(), MSZ_PERM_CHANGELOG_MANAGE_TAGS)) {
echo render_error(403);
return;
}

View file

@ -1,9 +1,11 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_GENERAL, user_session_current('user_id'), MSZ_PERM_FORUM_MANAGE_FORUMS)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_FORUM_MANAGE_FORUMS)) {
echo render_error(403);
return;
}

View file

@ -1,9 +1,11 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_GENERAL, user_session_current('user_id'), MSZ_PERM_FORUM_MANAGE_FORUMS)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_FORUM_MANAGE_FORUMS)) {
echo render_error(403);
return;
}

View file

@ -2,10 +2,11 @@
namespace Misuzu;
use Misuzu\Net\IPAddressBlacklist;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_GENERAL, user_session_current('user_id'), MSZ_PERM_GENERAL_MANAGE_BLACKLIST)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_MANAGE_BLACKLIST)) {
echo render_error(403);
return;
}

View file

@ -1,9 +1,11 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_GENERAL, user_session_current('user_id'), MSZ_PERM_GENERAL_MANAGE_EMOTES)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_MANAGE_EMOTES)) {
echo render_error(403);
return;
}

View file

@ -1,9 +1,11 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_GENERAL, user_session_current('user_id'), MSZ_PERM_GENERAL_MANAGE_EMOTES)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_MANAGE_EMOTES)) {
echo render_error(403);
return;
}

View file

@ -144,11 +144,11 @@ $statistics = DB::query('
FROM `msz_ip_blacklist`
) AS `stat_blacklist`,
(
SELECT COUNT(`attempt_id`)
SELECT COUNT(*)
FROM `msz_login_attempts`
) AS `stat_login_attempts_total`,
(
SELECT COUNT(`attempt_id`)
SELECT COUNT(*)
FROM `msz_login_attempts`
WHERE `attempt_success` = 0
) AS `stat_login_attempts_failed`,

View file

@ -3,10 +3,11 @@ namespace Misuzu;
use Misuzu\AuditLog;
use Misuzu\Pagination;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_GENERAL, user_session_current('user_id'), MSZ_PERM_GENERAL_VIEW_LOGS)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_VIEW_LOGS)) {
echo render_error(403);
return;
}

View file

@ -1,9 +1,11 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_GENERAL, user_session_current('user_id'), MSZ_PERM_GENERAL_MANAGE_CONFIG)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_MANAGE_CONFIG)) {
echo render_error(403);
return;
}

View file

@ -2,10 +2,11 @@
namespace Misuzu;
use Misuzu\News\NewsCategory;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_NEWS, user_session_current('user_id'), MSZ_PERM_NEWS_MANAGE_CATEGORIES)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_NEWS, User::getCurrent()->getId(), MSZ_PERM_NEWS_MANAGE_CATEGORIES)) {
echo render_error(403);
return;
}

View file

@ -4,10 +4,11 @@ namespace Misuzu;
use Misuzu\AuditLog;
use Misuzu\News\NewsCategory;
use Misuzu\News\NewsCategoryNotFoundException;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_NEWS, user_session_current('user_id'), MSZ_PERM_NEWS_MANAGE_CATEGORIES)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_NEWS, User::getCurrent()->getId(), MSZ_PERM_NEWS_MANAGE_CATEGORIES)) {
echo render_error(403);
return;
}

View file

@ -5,10 +5,11 @@ use Misuzu\AuditLog;
use Misuzu\News\NewsCategory;
use Misuzu\News\NewsPost;
use Misuzu\News\NewsPostNotFoundException;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_NEWS, user_session_current('user_id'), MSZ_PERM_NEWS_MANAGE_POSTS)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_NEWS, User::getCurrent()->getId(), MSZ_PERM_NEWS_MANAGE_POSTS)) {
echo render_error(403);
return;
}
@ -31,7 +32,7 @@ if(!empty($_POST['post']) && CSRF::validateRequest()) {
$isNew = true;
}
$currentUserId = user_session_current('user_id');
$currentUserId = User::getCurrent()->getId();
$postInfo->setTitle( $_POST['post']['title'])
->setText($_POST['post']['text'])
->setCategoryId($_POST['post']['category'])

View file

@ -2,10 +2,11 @@
namespace Misuzu;
use Misuzu\News\NewsPost;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_NEWS, user_session_current('user_id'), MSZ_PERM_NEWS_MANAGE_POSTS)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_NEWS, User::getCurrent()->getId(), MSZ_PERM_NEWS_MANAGE_POSTS)) {
echo render_error(403);
return;
}

View file

@ -1,9 +1,11 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_USER, user_session_current('user_id'), MSZ_PERM_USER_MANAGE_USERS)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_USER, User::getCurrent()->getId(), MSZ_PERM_USER_MANAGE_USERS)) {
echo render_error(403);
return;
}

View file

@ -1,17 +1,18 @@
<?php
// TODO: UNFUCK THIS FILE
namespace Misuzu;
// TODO: UNFUCK THIS FILE
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_USER, user_session_current('user_id'), MSZ_PERM_USER_MANAGE_ROLES)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_USER, User::getCurrent()->getId(), MSZ_PERM_USER_MANAGE_ROLES)) {
echo render_error(403);
return;
}
$roleId = $_GET['r'] ?? null;
$currentUserId = user_session_current('user_id');
$currentUserId = User::getCurrent()->getId();
/*$isSuperUser = user_check_super($currentUserId);
$canEdit = $isSuperUser || user_check_authority($currentUserId, $userId);*/
$canEditPerms = /*$canEdit && */perms_check_user(MSZ_PERMS_USER, $currentUserId, MSZ_PERM_USER_MANAGE_PERMS);

View file

@ -1,9 +1,11 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_USER, user_session_current('user_id'), MSZ_PERM_USER_MANAGE_ROLES)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_USER, User::getCurrent()->getId(), MSZ_PERM_USER_MANAGE_ROLES)) {
echo render_error(403);
return;
}

View file

@ -1,16 +1,18 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_USER, user_session_current('user_id'), MSZ_PERM_USER_MANAGE_USERS)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_USER, User::getCurrent()->getId(), MSZ_PERM_USER_MANAGE_USERS)) {
echo render_error(403);
return;
}
$notices = [];
$userId = (int)($_GET['u'] ?? 0);
$currentUserId = user_session_current('user_id');
$currentUserId = User::getCurrent()->getId();
if($userId < 1) {
echo render_error(404);

View file

@ -2,16 +2,17 @@
namespace Misuzu;
use Misuzu\Net\IPAddress;
use Misuzu\Users\User;
require_once '../../../misuzu.php';
if(!perms_check_user(MSZ_PERMS_USER, user_session_current('user_id'), MSZ_PERM_USER_MANAGE_WARNINGS)) {
if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_USER, User::getCurrent()->getId(), MSZ_PERM_USER_MANAGE_WARNINGS)) {
echo render_error(403);
return;
}
$notices = [];
$currentUserId = user_session_current('user_id');
$currentUserId = User::getCurrent()->getId();
if(!empty($_POST['lookup']) && is_string($_POST['lookup'])) {
url_redirect('manage-users-warnings', ['user' => user_id_from_username($_POST['lookup'])]);

View file

@ -1,6 +1,8 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../misuzu.php';
$roleId = !empty($_GET['r']) && is_string($_GET['r']) ? (int)$_GET['r'] : MSZ_ROLE_MAIN;
@ -75,10 +77,7 @@ if(empty($orderDir)) {
return;
}
$canManageUsers = perms_check_user(
MSZ_PERMS_USER, user_session_current('user_id', 0),
MSZ_PERM_USER_MANAGE_USERS
);
$canManageUsers = perms_check_user(MSZ_PERMS_USER, User::hasCurrent() ? User::getCurrent()->getId() : 0, MSZ_PERM_USER_MANAGE_USERS);
$role = user_role_get($roleId);
@ -153,7 +152,7 @@ $getUsers = DB::prepare(sprintf(
$usersPagination->getRange()
));
$getUsers->bind('role_id', $role['role_id']);
$getUsers->bind('current_user_id', user_session_current('user_id', 0));
$getUsers->bind('current_user_id', User::hasCurrent() ? User::getCurrent()->getId() : 0);
$users = $getUsers->fetchAll();
if(empty($users)) {

View file

@ -4,6 +4,7 @@ namespace Misuzu;
use Misuzu\Parsers\Parser;
use Misuzu\Users\User;
use Misuzu\Users\UserNotFoundException;
use Misuzu\Users\UserSession;
require_once '../misuzu.php';
@ -21,15 +22,16 @@ try {
$notices = [];
$currentUserId = user_session_current('user_id', 0);
$viewingAsGuest = $currentUserId === 0;
$currentUser = User::getCurrent();
$viewingAsGuest = $currentUser === null;
$currentUserId = $viewingAsGuest ? 0 : $currentUser->getId();
$viewingOwnProfile = $currentUserId === $profileUser->getId();
$isBanned = user_warning_check_restriction($profileUser->getId());
$userPerms = perms_get_user($currentUserId)[MSZ_PERMS_USER];
$canManageWarnings = perms_check($userPerms, MSZ_PERM_USER_MANAGE_WARNINGS);
$canEdit = !$isBanned
&& user_session_active()
&& UserSession::hasCurrent()
&& (
$viewingOwnProfile
|| user_check_super($currentUserId)
@ -297,7 +299,7 @@ $profileStats = DB::prepare(sprintf('
WHERE `user_id` = :user_id
', MSZ_USER_RELATION_FOLLOW))->bind('user_id', $profileUser->getId())->fetch();
$relationInfo = user_session_active()
$relationInfo = UserSession::hasCurrent()
? user_relation_info($currentUserId, $profileUser->getId())
: [];

View file

@ -1,6 +1,8 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
require_once '../misuzu.php';
// basing whether or not this is an xhr request on whether a referrer header is present
@ -22,14 +24,14 @@ if(!CSRF::validateRequest()) {
header(CSRF::header());
if(!user_session_active()) {
$currentUser = User::getCurrent();
if($currentUser === null) {
echo render_info_or_json($isXHR, 'You must be logged in to manage relations.', 401);
return;
}
$userId = (int)user_session_current('user_id');
if(user_warning_check_expiration($userId, MSZ_WARN_BAN) > 0) {
if(user_warning_check_expiration($currentUser->getId(), MSZ_WARN_BAN) > 0) {
echo render_info_or_json($isXHR, 'You have been banned, check your profile for more information.', 403);
return;
}
@ -42,12 +44,12 @@ if(!user_relation_is_valid_type($relationType)) {
return;
}
if($userId < 1 || $subjectId < 1) {
if($currentUser->getId() < 1 || $subjectId < 1) {
echo render_info_or_json($isXHR, "That user doesn't exist.", 400);
return;
}
if(!user_relation_set($userId, $subjectId, $relationType)) {
if(!user_relation_set($currentUser->getId(), $subjectId, $relationType)) {
echo render_info_or_json($isXHR, "Failed to save relation.", 500);
return;
}
@ -55,7 +57,7 @@ if(!user_relation_set($userId, $subjectId, $relationType)) {
if(($relationType === MSZ_USER_RELATION_NONE || $relationType === MSZ_USER_RELATION_FOLLOW)
&& in_array($subjectId, Config::get('relations.replicate', Config::TYPE_ARR))) {
user_relation_set($subjectId, $userId, $relationType);
user_relation_set($subjectId, $currentUser->getId(), $relationType);
}
if(!$isXHR) {
@ -64,7 +66,7 @@ if(!$isXHR) {
}
echo json_encode([
'user_id' => $userId,
'user_id' => $currentUser->getId(),
'subject_id' => $subjectId,
'relation_type' => $relationType,
]);

View file

@ -2,13 +2,14 @@
namespace Misuzu;
use Misuzu\News\NewsPost;
use Misuzu\Users\User;
require_once '../misuzu.php';
$searchQuery = !empty($_GET['q']) && is_string($_GET['q']) ? $_GET['q'] : '';
if(!empty($searchQuery)) {
$forumTopics = forum_topic_listing_search($searchQuery, user_session_current('user_id', 0));
$forumTopics = forum_topic_listing_search($searchQuery, User::hasCurrent() ? User::getCurrent()->getId() : 0);
$forumPosts = forum_post_search($searchQuery);
$newsPosts = NewsPost::bySearchQuery($searchQuery);
@ -67,7 +68,7 @@ if(!empty($searchQuery)) {
MSZ_USER_RELATION_FOLLOW
));
$findUsers->bind('query', $searchQuery);
$findUsers->bind('current_user_id', user_session_current('user_id', 0));
$findUsers->bind('current_user_id', User::hasCurrent() ? User::getCurrent()->getId() : 0);
$users = $findUsers->fetchAll();
}

View file

@ -3,12 +3,13 @@ namespace Misuzu;
use Misuzu\AuditLog;
use Misuzu\Users\User;
use Misuzu\Users\UserSession;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\QROptions;
require_once '../../misuzu.php';
if(!user_session_active()) {
if(!UserSession::hasCurrent()) {
echo render_error(401);
return;
}

View file

@ -4,10 +4,11 @@ namespace Misuzu;
use ZipArchive;
use Misuzu\AuditLog;
use Misuzu\Users\User;
use Misuzu\Users\UserSession;
require_once '../../misuzu.php';
if(!user_session_active()) {
if(!UserSession::hasCurrent()) {
echo render_error(401);
return;
}

View file

@ -1,13 +1,13 @@
<?php
namespace Misuzu;
use Misuzu\Users\UserSession;
require_once '../../misuzu.php';
if(!user_session_active()) {
if(!UserSession::hasCurrent()) {
echo render_error(401);
return;
}
// do something with this page
url_redirect('settings-account');

View file

@ -2,17 +2,22 @@
namespace Misuzu;
use Misuzu\AuditLog;
use Misuzu\Users\User;
use Misuzu\Users\UserSession;
use Misuzu\Users\UserSessionNotFoundException;
require_once '../../misuzu.php';
if(!user_session_active()) {
if(!User::hasCurrent()) {
echo render_error(401);
return;
}
$errors = [];
$currentUserId = user_session_current('user_id');
$sessionActive = user_session_current('session_id');
$currentUser = User::getCurrent();
$currentSession = UserSession::getCurrent();
$currentUserId = $currentUser->getId();
$sessionActive = $currentSession->getId();;
if(!empty($_POST['session']) && CSRF::validateRequest()) {
$currentSessionKilled = false;
@ -20,23 +25,24 @@ if(!empty($_POST['session']) && CSRF::validateRequest()) {
if(is_array($_POST['session'])) {
foreach($_POST['session'] as $sessionId) {
$sessionId = intval($sessionId);
$session = user_session_find($sessionId);
if(!$session || (int)$session['user_id'] !== $currentUserId) {
try {
$sessionInfo = UserSession::byId($sessionId);
} catch(UserSessionNotFoundException $ex) {}
if(empty($sessionInfo) || $sessionInfo->getUserId() !== $currentUser->getId()) {
$errors[] = "Session #{$sessionId} does not exist.";
continue;
} elseif((int)$session['session_id'] === $sessionActive) {
} elseif($sessionInfo->getId() === $sessionActive) {
$currentSessionKilled = true;
}
user_session_delete($session['session_id']);
AuditLog::create(AuditLog::PERSONAL_SESSION_DESTROY, [
$session['session_id'],
]);
$sessionInfo->delete();
AuditLog::create(AuditLog::PERSONAL_SESSION_DESTROY, [$sessionInfo->getId()]);
}
} elseif($_POST['session'] === 'all') {
$currentSessionKilled = true;
user_session_purge_all($currentUserId);
UserSession::purgeUser($currentUser);
AuditLog::create(AuditLog::PERSONAL_SESSION_DESTROY_ALL);
}
@ -46,17 +52,11 @@ if(!empty($_POST['session']) && CSRF::validateRequest()) {
}
}
$sessionPagination = new Pagination(user_session_count($currentUserId), 15);
$sessionList = user_session_list(
$sessionPagination->getOffset(),
$sessionPagination->getRange(),
$currentUserId
);
$pagination = new Pagination(UserSession::countAll($currentUser), 15);
Template::render('settings.sessions', [
'errors' => $errors,
'session_list' => $sessionList,
'session_active_id' => $sessionActive,
'session_pagination' => $sessionPagination,
'session_list' => UserSession::all($pagination, $currentUser),
'session_current' => $currentSession,
'session_pagination' => $pagination,
]);

View file

@ -22,7 +22,7 @@ $canViewImages = !$userExists
|| !user_warning_check_expiration($userId, MSZ_WARN_BAN)
|| (
parse_url($_SERVER['HTTP_REFERER'] ?? '', PHP_URL_PATH) === url('user-profile')
&& perms_check_user(MSZ_PERMS_USER, user_session_current('user_id', 0), MSZ_PERM_USER_MANAGE_USERS)
&& perms_check_user(MSZ_PERMS_USER, User::hasCurrent() ? User::getCurrent()->getId() : 0, MSZ_PERM_USER_MANAGE_USERS)
);
switch($userAssetsMode) {

90
src/AuthToken.php Normal file
View file

@ -0,0 +1,90 @@
<?php
namespace Misuzu;
use Misuzu\Users\User;
use Misuzu\Users\UserSession;
class AuthToken {
public const VERSION = 1;
public const WIDTH = 37;
private $userId = -1;
private $sessionToken = '';
private $user = null;
private $session = null;
public function isValid(): bool {
return $this->getUserId() > 0
&& !empty($this->getSessionToken());
}
public function getUserId(): int {
return $this->userId < 1 ? -1 : $this->userId;
}
public function setUserId(int $userId): self {
$this->user = null;
$this->userId = $userId;
return $this;
}
public function getUser(): User {
if($this->user === null)
$this->user = User::byId($this->getUserId());
return $this->user;
}
public function setUser(User $user): self {
$this->user = $user;
$this->userId = $user->getId();
return $this;
}
public function getSessionToken(): string {
return $this->sessionToken ?? '';
}
public function setSessionToken(string $token): self {
$this->session = null;
$this->sessionToken = $token;
return $this;
}
public function getSession(): UserSession {
if($this->session === null)
$this->session = UserSession::byToken($this->getSessionToken());
return $this->session;
}
public function setSession(UserSession $session): self {
$this->session = $session;
$this->sessionToken = $session->getToken();
return $this;
}
public function pack(bool $base64 = true): string {
$packed = pack('CNH*', self::VERSION, $this->getUserId(), $this->getSessionToken());
if($base64)
$packed = Base64::encode($packed, true);
return $packed;
}
public static function unpack(string $data, bool $base64 = true): self {
$obj = new static;
if(empty($data))
return $obj;
if($base64)
$data = Base64::decode($data, true);
$data = str_pad($data, self::WIDTH, "\x00");
$data = unpack('Cversion/Nuser/H*token', $data);
if($data['version'] >= 1)
$obj->setUserId($data['user'])
->setSessionToken($data['token']);
return $obj;
}
public static function create(User $user, UserSession $session): self {
return (new static)
->setUser($user)
->setSession($session);
}
}

View file

@ -3,10 +3,12 @@ namespace Misuzu\Http\Filters;
use Misuzu\Http\HttpResponseMessage;
use Misuzu\Http\HttpRequestMessage;
use Misuzu\Users\User;
use Misuzu\Users\UserSession;
class EnforceLogInFilter implements FilterInterface {
public function process(HttpRequestMessage $request): ?HttpResponseMessage {
if(!user_session_active())
if(!UserSession::hasCurrent() || !User::hasCurrent())
return new HttpResponseMessage(403);
return null;

View file

@ -3,10 +3,12 @@ namespace Misuzu\Http\Filters;
use Misuzu\Http\HttpResponseMessage;
use Misuzu\Http\HttpRequestMessage;
use Misuzu\Users\User;
use Misuzu\Users\UserSession;
class EnforceLogOutFilter implements FilterInterface {
public function process(HttpRequestMessage $request): ?HttpResponseMessage {
if(user_session_active())
if(UserSession::hasCurrent() || User::hasCurrent())
return new HttpResponseMessage(404);
return null;

View file

@ -4,6 +4,7 @@ namespace Misuzu\Http\Handlers;
use HttpResponse;
use HttpRequest;
use Misuzu\CSRF;
use Misuzu\Users\User;
final class ForumHandler extends Handler {
public function markAsReadGET(HttpResponse $response, HttpRequest $request): void {
@ -20,7 +21,7 @@ final class ForumHandler extends Handler {
public function markAsReadPOST(HttpResponse $response, HttpRequest $request) {
$forumId = (int)$request->getBodyParam('forum', FILTER_SANITIZE_NUMBER_INT);
forum_mark_read($forumId, user_session_current('user_id'));
forum_mark_read($forumId, User::getCurrent()->getId());
$response->redirect(
url($forumId ? 'forum-category' : 'forum-index', ['forum' => $forumId]),

View file

@ -8,6 +8,7 @@ use Misuzu\DB;
use Misuzu\Pagination;
use Misuzu\Changelog\ChangelogChange;
use Misuzu\News\NewsPost;
use Misuzu\Users\UserSession;
final class HomeHandler extends Handler {
public function index(HttpResponse $response, HttpRequest $request): void {
@ -58,7 +59,7 @@ final class HomeHandler extends Handler {
$changelog = ChangelogChange::all(new Pagination(10));
$birthdays = user_session_active() ? user_get_birthdays() : [];
$birthdays = UserSession::hasCurrent() ? user_get_birthdays() : [];
$latestUser = DB::query('
SELECT

View file

@ -3,6 +3,7 @@ namespace Misuzu\Http\Handlers;
use HttpResponse;
use HttpRequest;
use Misuzu\AuthToken;
use Misuzu\Base64;
use Misuzu\Config;
use Misuzu\DB;
@ -13,6 +14,8 @@ use Misuzu\Users\UserNotFoundException;
use Misuzu\Users\UserChatToken;
use Misuzu\Users\UserChatTokenNotFoundException;
use Misuzu\Users\UserChatTokenCreationFailedException;
use Misuzu\Users\UserSession;
use Misuzu\Users\UserSessionNotFoundException;
final class SockChatHandler extends Handler {
private string $hashKey = 'woomy';
@ -222,21 +225,27 @@ final class SockChatHandler extends Handler {
// $userId = $authInfo->user_id;
} elseif($authMethod === 'SESS:') {
$sessionToken = mb_substr($authInfo->token, 5);
$tokenData = user_session_cookie_unpack(
Base64::decode($sessionToken, true),
true
);
if(isset($tokenData['session_token']))
$sessionToken = $tokenData['session_token'];
$authToken = AuthToken::unpack($sessionToken);
if($authToken->isValid())
$sessionToken = $authToken->getSessionToken();
user_session_start($authInfo->user_id, $sessionToken);
try {
$sessionInfo = UserSession::byToken($sessionToken);
} catch(UserSessionNotFoundException $ex) {
return ['success' => false, 'reason' => 'token'];
}
if(user_session_active()) {
$userId = user_session_current('user_id');
user_bump_last_active($userId);
user_session_bump_active(user_session_current('session_id'));
} else return ['success' => false, 'reason' => 'expired'];
if($sessionInfo->getUserId() !== $userInfo->getId())
return ['success' => false, 'reason' => 'user'];
if($sessionInfo->hasExpired()) {
$sessionInfo->delete();
return ['success' => false, 'reason' => 'expired'];
}
$sessionInfo->bump();
user_bump_last_active($userInfo->getId());
} else {
try {
$token = UserChatToken::byExact($userInfo, $authInfo->token);

View file

@ -173,16 +173,19 @@ class User {
public static function unsetCurrent(): void {
self::$localUser = null;
}
public static function getCurrent(): ?User {
public static function getCurrent(): ?self {
return self::$localUser;
}
public static function hasCurrent(): bool {
return self::$localUser !== null;
}
public static function create(
string $username,
string $password,
string $email,
string $ipAddress
): ?User {
): ?self {
$createUser = DB::prepare('
INSERT INTO `msz_users` (
`username`, `password`, `email`, `register_ip`,
@ -210,7 +213,7 @@ class User {
return $memoizer;
}
public static function byId(int $userId): ?User {
public static function byId(int $userId): ?self {
return self::getMemoizer()->find($userId, function() use ($userId) {
$user = DB::prepare(self::USER_SELECT . 'WHERE `user_id` = :user_id')
->bind('user_id', $userId)
@ -220,7 +223,7 @@ class User {
return $user;
});
}
public static function findForLogin(string $usernameOrEmail): ?User {
public static function findForLogin(string $usernameOrEmail): ?self {
$usernameOrEmailLower = mb_strtolower($usernameOrEmail);
return self::getMemoizer()->find(function($user) use ($usernameOrEmailLower) {
return mb_strtolower($user->getUsername()) === $usernameOrEmailLower
@ -235,7 +238,7 @@ class User {
return $user;
});
}
public static function findForProfile($userIdOrName): ?User {
public static function findForProfile($userIdOrName): ?self {
$userIdOrNameLower = mb_strtolower($userIdOrName);
return self::getMemoizer()->find(function($user) use ($userIdOrNameLower) {
return $user->getId() == $userIdOrNameLower || mb_strtolower($user->getUsername()) === $userIdOrNameLower;

View file

@ -67,7 +67,7 @@ class UserLoginAttempt {
}
public static function remaining(?string $remoteAddr = null): int {
$remoteAddr = $ipAddress ?? IPAddress::remote();
$remoteAddr = $remoteAddr ?? IPAddress::remote();
return (int)DB::prepare(
'SELECT 5 - COUNT(*)'
. ' FROM `' . DB::PREFIX . self::TABLE . '`'
@ -79,7 +79,7 @@ class UserLoginAttempt {
}
public static function create(bool $success, ?User $user = null, ?string $remoteAddr = null, string $userAgent = null): void {
$remoteAddr = $ipAddress ?? IPAddress::remote();
$remoteAddr = $remoteAddr ?? IPAddress::remote();
$userAgent = $userAgent ?? filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) ?? '';
$createLog = DB::prepare(
'INSERT INTO `' . DB::PREFIX . self::TABLE . '` (`user_id`, `attempt_success`, `attempt_ip`, `attempt_country`, `attempt_user_agent`)'

256
src/Users/UserSession.php Normal file
View file

@ -0,0 +1,256 @@
<?php
namespace Misuzu\Users;
use Misuzu\DB;
use Misuzu\Pagination;
use Misuzu\Net\IPAddress;
use WhichBrowser\Parser as UserAgentParser;
class UserSessionException extends UsersException {}
class UserSessionCreationFailedException extends UserSessionException {}
class UserSessionNotFoundException extends UserSessionException {}
class UserSession {
public const TOKEN_SIZE = 64;
public const LIFETIME = 60 * 60 * 24 * 31;
// Database fields
private $session_id = -1;
private $user_id = -1;
private $session_key = '';
private $session_ip = '::1';
private $session_ip_last = null;
private $session_user_agent = '';
private $session_country = 'XX';
private $session_expires = null;
private $session_expires_bump = 1;
private $session_created = null;
private $session_active = null;
private $user = null;
private $uaInfo = null;
private static $localSession = null;
public const TABLE = 'sessions';
private const QUERY_SELECT = 'SELECT %1$s FROM `' . DB::PREFIX . self::TABLE . '` AS '. self::TABLE;
private const SELECT = '%1$s.`session_id`, %1$s.`user_id`, %1$s.`session_key`, %1$s.`session_user_agent`, %1$s.`session_country`, %1$s.`session_expires_bump`'
. ', INET6_NTOA(%1$s.`session_ip`) AS `session_ip`'
. ', INET6_NTOA(%1$s.`session_ip_last`) AS `session_ip_last`'
. ', UNIX_TIMESTAMP(%1$s.`session_created`) AS `session_created`'
. ', UNIX_TIMESTAMP(%1$s.`session_active`) AS `session_active`'
. ', UNIX_TIMESTAMP(%1$s.`session_expires`) AS `session_expires`';
public function getId(): int {
return $this->session_id < 1 ? -1 : $this->session_id;
}
public function getUserId(): int {
return $this->user_id < 1 ? -1 : $this->user_id;
}
public function getUser(): User {
if($this->user === null)
$this->user = User::byId($this->getUserId());
return $this->user;
}
public function getToken(): string {
return $this->session_key;
}
public function getInitialRemoteAddress(): string {
return $this->session_ip;
}
public function getLastRemoteAddress(): string {
return $this->session_ip_last ?? '';
}
public function hasLastRemoteAddress(): bool {
return !empty($this->session_ip_last);
}
public function setLastRemoteAddress(string $remoteAddr): self {
$this->session_ip_last = $remoteAddr;
return $this;
}
public function getUserAgent(): string {
return $this->session_user_agent;
}
public function getUserAgentInfo(): UserAgentParser {
if($this->uaInfo === null)
$this->uaInfo = new UserAgentParser($this->getUserAgent());
return $this->uaInfo;
}
public function getCountry(): string {
return $this->session_country;
}
public function getCountryName(): string {
return get_country_name($this->getCountry());
}
public function getCreatedTime(): int {
return $this->session_created === null ? -1 : $this->session_created;
}
public function getActiveTime(): int {
return $this->session_active === null ? -1 : $this->session_active;
}
public function hasActiveTime(): bool {
return $this->session_active !== null;
}
public function setActiveTime(int $timestamp): self {
if($timestamp > $this->session_active)
$this->session_active = $timestamp;
return $this;
}
public function getExpiresTime(): int {
return $this->session_expires === null ? -1 : $this->session_expires;
}
public function setExpiresTime(int $timestamp): self {
$this->session_expires = $timestamp;
return $this;
}
public function hasExpired(): bool {
return $this->getExpiresTime() <= time();
}
public function shouldBumpExpire(): bool {
return boolval($this->session_expires_bump);
}
public function bump(bool $callUpdate = true, ?int $timestamp = null, ?string $remoteAddr = null): void {
$timestamp = $timestamp ?? time();
$remoteAddr = $remoteAddr ?? IPAddress::remote();
$this->setActiveTime($timestamp)
->setLastRemoteAddress($remoteAddr);
if($this->shouldBumpExpire())
$this->setExpiresTime($timestamp + self::LIFETIME);
if($callUpdate)
$this->update();
}
public function delete(): void {
DB::prepare('DELETE FROM `' . DB::PREFIX . self::TABLE . '` WHERE `session_id` = :session')
->bind('session', $this->getId())
->execute();
}
public static function purgeUser(User $user): void {
DB::prepare('DELETE FROM `' . DB::PREFIX . self::TABLE . '` WHERE `user_id` = :user')
->bind('user', $user->getId())
->execute();
}
public function setCurrent(): void {
self::$localSession = $this;
}
public static function unsetCurrent(): void {
self::$localSession = null;
}
public static function getCurrent(): ?self {
return self::$localSession;
}
public static function hasCurrent(): bool {
return self::$localSession !== null;
}
public static function generateToken(): string {
return bin2hex(random_bytes(self::TOKEN_SIZE / 2));
}
public function update(): void {
DB::prepare(
'UPDATE `' . DB::PREFIX . self::TABLE . '`'
. ' SET `session_active` = FROM_UNIXTIME(:active), `session_ip_last` = INET6_ATON(:remote_addr), `session_expires` = FROM_UNIXTIME(:expires)'
. ' WHERE `session_id` = :session'
) ->bind('active', $this->session_active)
->bind('remote_addr', $this->session_ip_last)
->bind('expires', $this->session_expires)
->bind('session', $this->session_id)
->execute();
}
public static function create(User $user, ?string $remoteAddr = null, ?string $userAgent = null, ?string $token = null): self {
$remoteAddr = $remoteAddr ?? IPAddress::remote();
$userAgent = $userAgent ?? filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) ?? '';
$token = $token ?? self::generateToken();
$sessionId = DB::prepare(
'INSERT INTO `' . DB::PREFIX . self::TABLE . '`'
. ' (`user_id`, `session_ip`, `session_country`, `session_user_agent`, `session_key`, `session_created`, `session_expires`)'
. ' VALUES (:user, INET6_ATON(:remote_addr), :country, :user_agent, :token, NOW(), NOW() + INTERVAL :expires SECOND)'
) ->bind('user', $user->getId())
->bind('remote_addr', $remoteAddr)
->bind('country', IPAddress::country($remoteAddr))
->bind('user_agent', $userAgent)
->bind('token', $token)
->bind('expires', self::LIFETIME)
->executeGetId();
if($sessionId < 1)
throw new UserSessionCreationFailedException;
return self::byId($sessionId);
}
private static function countQueryBase(): string {
return sprintf(self::QUERY_SELECT, sprintf('COUNT(*)', self::TABLE));
}
public static function countAll(?User $user = null): int {
$getCount = DB::prepare(
self::countQueryBase()
. ($user === null ? '' : ' WHERE `user_id` = :user')
);
if($user !== null)
$getCount->bind('user', $user->getId());
return (int)$getCount->fetchColumn();
}
private static function byQueryBase(): string {
return sprintf(self::QUERY_SELECT, sprintf(self::SELECT, self::TABLE));
}
public static function byId(int $sessionId): self {
$session = DB::prepare(self::byQueryBase() . ' WHERE `session_id` = :session_id')
->bind('session_id', $sessionId)
->fetchObject(self::class);
if(!$session)
throw new UserSessionNotFoundException;
return $session;
}
public static function byToken(string $token): self {
$session = DB::prepare(self::byQueryBase() . ' WHERE `session_key` = :token')
->bind('token', $token)
->fetchObject(self::class);
if(!$session)
throw new UserSessionNotFoundException;
return $session;
}
public static function all(?Pagination $pagination = null, ?User $user = null): array {
$sessionsQuery = self::byQueryBase()
. ($user === null ? '' : ' WHERE `user_id` = :user')
. ' ORDER BY `session_created` DESC';
if($pagination !== null)
$sessionsQuery .= ' LIMIT :range OFFSET :offset';
$getSessions = DB::prepare($sessionsQuery);
if($user !== null)
$getSessions->bind('user', $user->getId());
if($pagination !== null)
$getSessions->bind('range', $pagination->getRange())
->bind('offset', $pagination->getOffset());
return $getSessions->fetchObjects(self::class);
}
}

View file

@ -1,211 +1,90 @@
<?php
define('MSZ_SESSION_KEY_SIZE', 64);
// These functions are used by external scripts that hook into Misuzu.
// They will remain in a backwards compatible manner for the time being.
function user_session_create(
int $userId,
string $ipAddress,
string $userAgent
): string {
$sessionKey = user_session_generate_key();
$createSession = \Misuzu\DB::prepare('
INSERT INTO `msz_sessions`
(
`user_id`, `session_ip`, `session_country`,
`session_user_agent`, `session_key`, `session_created`, `session_expires`
)
VALUES
(
:user_id, INET6_ATON(:session_ip), :session_country,
:session_user_agent, :session_key, NOW(), NOW() + INTERVAL 1 MONTH
)
');
$createSession->bind('user_id', $userId);
$createSession->bind('session_ip', $ipAddress);
$createSession->bind('session_country', \Misuzu\Net\IPAddress::country($ipAddress));
$createSession->bind('session_user_agent', $userAgent);
$createSession->bind('session_key', $sessionKey);
return $createSession->execute() ? $sessionKey : '';
}
function user_session_find($sessionId, bool $byKey = false): array {
if(!$byKey && $sessionId < 1) {
return [];
function user_session_create(int $userId, string $ipAddress, string $userAgent): string {
try {
$userInfo = \Misuzu\Users\User::byId($userId);
} catch(\Misuzu\Users\UserNotFoundException $ex) {
return '';
}
$findSession = \Misuzu\DB::prepare(sprintf('
SELECT
`session_id`, `user_id`,
INET6_NTOA(`session_ip`) as `session_ip`,
INET6_NTOA(`session_ip_last`) as `session_ip_last`,
`session_country`, `session_user_agent`, `session_key`, `session_created`,
`session_expires`, `session_active`, `session_expires_bump`
FROM `msz_sessions`
WHERE `%s` = :session_id
', $byKey ? 'session_key' : 'session_id'));
$findSession->bind('session_id', $sessionId);
return $findSession->fetch();
}
function user_session_delete(int $sessionId): void {
$deleteSession = \Misuzu\DB::prepare('
DELETE FROM `msz_sessions`
WHERE `session_id` = :session_id
');
$deleteSession->bind('session_id', $sessionId);
$deleteSession->execute();
}
function user_session_generate_key(): string {
return bin2hex(random_bytes(MSZ_SESSION_KEY_SIZE / 2));
}
function user_session_purge_all(int $userId): void {
\Misuzu\DB::prepare('
DELETE FROM `msz_sessions`
WHERE `user_id` = :user_id
')->execute([
'user_id' => $userId,
]);
}
function user_session_count($userId = 0): int {
$getCount = \Misuzu\DB::prepare(sprintf('
SELECT COUNT(`session_id`)
FROM `msz_sessions`
%s
', $userId < 1 ? '' : 'WHERE `user_id` = :user_id'));
if($userId >= 1) {
$getCount->bind('user_id', $userId);
try {
$sessionInfo = \Misuzu\Users\UserSession::create($userInfo, $ipAddress, $userAgent);
} catch(\Misuzu\Users\UserSessionCreationFailedException $ex) {
return '';
}
return (int)$getCount->fetchColumn();
return $sessionInfo->getToken();
}
function user_session_list(int $offset, int $take, int $userId = 0): array {
$offset = max(0, $offset);
$take = max(1, $take);
$getSessions = \Misuzu\DB::prepare(sprintf('
SELECT
`session_id`, `session_country`, `session_user_agent`, `session_created`,
`session_expires`, `session_active`, `session_expires_bump`,
INET6_NTOA(`session_ip`) as `session_ip`,
INET6_NTOA(`session_ip_last`) as `session_ip_last`
FROM `msz_sessions`
WHERE %s
ORDER BY `session_id` DESC
LIMIT :offset, :take
', $userId < 1 ? '1' : '`user_id` = :user_id'));
if($userId > 0) {
$getSessions->bind('user_id', $userId);
}
$getSessions->bind('offset', $offset);
$getSessions->bind('take', $take);
return $getSessions->fetchAll();
}
function user_session_bump_active(int $sessionId, string $ipAddress = null): void {
if($sessionId < 1) {
function user_session_bump_active(int $sessionId, ?string $ipAddress = null): void {
try {
$sessionInfo = \Misuzu\Users\UserSession::byId($sessionId);
} catch(\Misuzu\Users\UserSessionNotFoundException $ex) {
return;
}
$bump = \Misuzu\DB::prepare('
UPDATE `msz_sessions`
SET `session_active` = NOW(),
`session_ip_last` = INET6_ATON(:last_ip),
`session_expires` = IF(`session_expires_bump`, NOW() + INTERVAL 1 MONTH, `session_expires`)
WHERE `session_id` = :session_id
');
$bump->bind('session_id', $sessionId);
$bump->bind('last_ip', $ipAddress ?? \Misuzu\Net\IPAddress::remote());
$bump->execute();
}
if($ipAddress !== null)
$sessionInfo->setLastRemoteAddress($ipAddress);
// the functions below this line are imperative
function user_session_data(?array $newData = null): array {
static $data = [];
if(!is_null($newData)) {
$data = $newData;
}
return $data;
$sessionInfo->bump();
}
function user_session_start(int $userId, string $sessionKey): bool {
$session = user_session_find($sessionKey, true);
$session = \Misuzu\Users\UserSession::getCurrent();
if(!$session || $session['user_id'] !== $userId) {
if($session !== null
&& $session->getToken() === $sessionKey
&& $session->getUserId() === $userId)
return true;
try {
$session = \Misuzu\Users\UserSession::byToken($sessionKey);
} catch(\Misuzu\Users\UserSessionNotFoundException $ex) {
return false;
}
if(time() >= strtotime($session['session_expires'])) {
user_session_delete($session['session_id']);
if($session->getUserId() !== $userId)
return false;
if($session->hasExpired()) {
$session->delete();
return false;
}
user_session_data($session);
$session->setCurrent();
return true;
}
function user_session_stop(bool $delete = false): void {
if(empty(user_session_data())) {
return;
}
if($delete) {
user_session_delete(user_session_data()['session_id']);
}
user_session_data([]);
}
function user_session_current(?string $variable = null, $default = null) {
if(empty($variable)) {
return user_session_data() ?? [];
}
$getVar = !empty($variable);
$session = \Misuzu\Users\UserSession::getCurrent();
return user_session_data()[$variable] ?? $default;
if($session === null)
return $getVar ? $default : [];
$data = [
'session_id' => $session->getId(),
'user_id' => $session->getUserId(),
'session_ip' => $session->getInitialRemoteAddress(),
'session_ip_last' => $session->getLastRemoteAddress(),
'session_country' => $session->getCountry(),
'session_user_agent' => $session->getUserAgent(),
'session_key' => $session->getToken(),
'session_created' => $session->getCreatedTime(),
'session_expires' => $session->getExpiresTime(),
'session_active' => ($date = $session->getActiveTime()) < 0 ? null : $date,
'session_expires_bump' => $session->shouldBumpExpire() ? 1 : 0,
];
if(!$getVar)
return $data;
return $data[$variable] ?? $default;
}
function user_session_active(): bool {
return !empty(user_session_data())
&& time() < strtotime(user_session_data()['session_expires']);
}
define('MSZ_SESSION_COOKIE_VERSION', 1);
// make sure to match this to the final fixed size of the cookie string
// it'll pad older tokens out for backwards compatibility
define('MSZ_SESSION_COOKIE_SIZE', 37);
function user_session_cookie_pack(int $userId, string $sessionToken): ?string {
if(strlen($sessionToken) !== MSZ_SESSION_KEY_SIZE) {
return null;
}
return pack('CNH64', MSZ_SESSION_COOKIE_VERSION, $userId, $sessionToken);
}
function user_session_cookie_unpack(string $packed): array {
$packed = str_pad($packed, MSZ_SESSION_COOKIE_SIZE, "\x00");
$unpacked = unpack('Cversion/Nuser/H64token', $packed);
if($unpacked['version'] < 1 || $unpacked['version'] > MSZ_SESSION_COOKIE_VERSION) {
return [];
}
// Make sure this contains all fields with a default for version > 1 exclusive stuff
$data = [
'user_id' => $unpacked['user'],
'session_token' => $unpacked['token'],
];
return $data;
return \Misuzu\Users\UserSession::hasCurrent()
&& !\Misuzu\Users\UserSession::getCurrent()->hasExpired();
}

View file

@ -22,8 +22,8 @@ function manage_get_menu(int $userId): array {
$menu['Users & Roles']['Users'] = url('manage-users');
if(perms_check_user(MSZ_PERMS_USER, $userId, MSZ_PERM_USER_MANAGE_ROLES))
$menu['Users & Roles']['Roles'] = url('manage-roles');
if(perms_check_user(MSZ_PERMS_USER, $userId, MSZ_PERM_USER_MANAGE_REPORTS))
$menu['Users & Roles']['Reports'] = url('manage-users-reports');
//if(perms_check_user(MSZ_PERMS_USER, $userId, MSZ_PERM_USER_MANAGE_REPORTS))
// $menu['Users & Roles']['Reports'] = url('manage-users-reports');
if(perms_check_user(MSZ_PERMS_USER, $userId, MSZ_PERM_USER_MANAGE_WARNINGS))
$menu['Users & Roles']['Warnings'] = url('manage-users-warnings');

View file

@ -31,7 +31,7 @@
<div class="settings__sessions__list">
{% for session in session_list %}
{{ user_session(session, session.session_id == session_active_id) }}
{{ user_session(session, session_current.id == session.id) }}
{% endfor %}
</div>

View file

@ -123,18 +123,18 @@
{% macro user_session(session, is_current_session) %}
{% from '_layout/input.twig' import input_hidden, input_csrf, input_checkbox_raw %}
<div class="settings__session{% if is_current_session %} settings__session--current{% endif %}" id="session-{{ session.session_id }}">
<div class="settings__session{% if is_current_session %} settings__session--current{% endif %}" id="session-{{ session.id }}">
<div class="settings__session__container">
<div class="settings__session__important">
<div class="flag flag--{{ session.session_country|lower }} settings__session__flag" title="{{ session.session_country|country_name }}">{{ session.session_country }}</div>
<div class="flag flag--{{ session.country|lower }} settings__session__flag" title="{{ session.countryName }}">{{ session.country }}</div>
<div class="settings__session__description">
{{ session.session_user_agent|default('')|as_platform }}
{{ session.userAgentInfo.toString }}
</div>
<form class="settings__session__actions" method="post" action="{{ url('settings-sessions') }}">
{{ input_csrf() }}
{{ input_hidden('session[]', session.session_id) }}
{{ input_hidden('session[]', session.id) }}
<button class="settings__session__action" title="{{ is_current_session ? 'Logout' : 'End Session' }}">
{% if is_current_session %}
@ -152,46 +152,46 @@
Created from IP
</div>
<div class="settings__session__detail__value">
{{ session.session_ip }}
{{ session.initialRemoteAddress }}
</div>
</div>
{% if session.session_ip_last is not null %}
{% if session.hasLastRemoteAddress %}
<div class="settings__session__detail">
<div class="settings__session__detail__title">
Last used from IP
</div>
<div class="settings__session__detail__value">
{{ session.session_ip_last }}
{{ session.lastRemoteAddress }}
</div>
</div>
{% endif %}
<div class="settings__session__detail" title="{{ session.session_created|date('r') }}">
<div class="settings__session__detail" title="{{ session.createdTime|date('r') }}">
<div class="settings__session__detail__title">
Created
</div>
<time class="settings__session__detail__value" datetime="{{ session.session_created|date('c') }}">
{{ session.session_created|time_diff }}
<time class="settings__session__detail__value" datetime="{{ session.createdTime|date('c') }}">
{{ session.createdTime|time_diff }}
</time>
</div>
<div class="settings__session__detail" title="{{ session.session_expires|date('r') }}">
<div class="settings__session__detail" title="{{ session.expiresTime|date('r') }}">
<div class="settings__session__detail__title">
Expires{% if not session.session_expires_bump %} (static){% endif %}
Expires{% if not session.shouldBumpExpire %} (static){% endif %}
</div>
<time class="settings__session__detail__value" datetime="{{ session.session_expires|date('c') }}">
{{ session.session_expires|time_diff }}
<time class="settings__session__detail__value" datetime="{{ session.expiresTime|date('c') }}">
{{ session.expiresTime|time_diff }}
</time>
</div>
{% if session.session_active is not null %}
<div class="settings__session__detail" title="{{ session.session_active|date('r') }}">
{% if session.hasActiveTime %}
<div class="settings__session__detail" title="{{ session.activeTime|date('r') }}">
<div class="settings__session__detail__title">
Last Active
</div>
<time class="settings__session__detail__value" datetime="{{ session.session_active|date('c') }}">
{{ session.session_active|time_diff }}
<time class="settings__session__detail__value" datetime="{{ session.activeTime|date('c') }}">
{{ session.activeTime|time_diff }}
</time>
</div>
{% endif %}
@ -201,7 +201,7 @@
User Agent
</div>
<div class="settings__session__detail__value">
{{ session.session_user_agent|length > 0 ? session.session_user_agent : 'None' }}
{{ session.userAgent is empty ? 'None' : session.userAgent }}
</div>
</div>
</div>