1
0
Fork 0
Lightning-Tracker/src/Session/Session.php

162 lines
4.0 KiB
PHP

<?php
declare(strict_types = 1);
namespace Session;
use Data\UserId;
use Database\DB;
use Database\Objects\UserProfile;
use Database\Tables\UserLoginTable;
use Database\Tables\UserTable;
use Exception;
use Logging\Log;
use LogicException;
final class Session{
private const COOKIE_NAME = 'logon';
private const TOKEN_EXPIRATION_TIME = 365 * 24 * 60;
private static ?Session $instance = null;
public static function get(): self{
if (self::$instance === null){
self::$instance = new self();
}
return self::$instance;
}
private static function checkToken(string $token, bool $renew): SessionLoginInfo{
try{
$logins = new UserLoginTable(DB::get());
$login = $logins->checkLogin($token);
$login = $login === null ? SessionLoginInfo::guest() : SessionLoginInfo::user($login);
if ($renew){
try{
$logins->renewToken($token, self::TOKEN_EXPIRATION_TIME);
self::setCookie($token);
}catch(Exception $e){
Log::critical($e);
}
}
return $login;
}catch(Exception $e){
Log::critical($e);
return SessionLoginInfo::guest();
}
}
private static function checkCookie(): SessionLoginInfo{
if (isset($_COOKIE[self::COOKIE_NAME])){
return self::checkToken($_COOKIE[self::COOKIE_NAME], true);
}
else{
return SessionLoginInfo::guest();
}
}
private static function setCookie(string $token): void{
$path = BASE_PATH_ENC;
$expire_in_seconds = self::TOKEN_EXPIRATION_TIME * 60;
header("Set-Cookie: logon=$token; Max-Age=$expire_in_seconds; Path=$path/; HttpOnly; SameSite=Lax");
}
private static function unsetCookie(): void{
$path = BASE_PATH_ENC;
header("Set-Cookie: logon=; Max-Age=0; Path=$path/; HttpOnly; SameSite=Lax");
}
private ?SessionLoginInfo $login = null;
private function __construct(){ }
private function getLogin(): SessionLoginInfo{
if ($this->login === null){
$this->login = self::checkCookie();
}
return $this->login;
}
public function getLogonUser(): ?UserProfile{
return $this->getLogin()->getLogonUser();
}
public function getLogonUserOrThrow(): ?UserProfile{
$logon_user = $this->getLogonUser();
if ($logon_user === null){
throw new LogicException('Expected a logged in user.');
}
return $logon_user;
}
public function getLogonUserId(): ?UserId{
$logon_user = $this->getLogonUser();
return $logon_user === null ? null : $logon_user->getId();
}
public function getLogonUserIdOrThrow(): UserId{
return $this->getLogonUserOrThrow()->getId();
}
public function getPermissions(): PermissionManager{
return $this->getLogin()->getPermissionManager();
}
public function tryLoginWithName(string $name): bool{
$id = null;
try{
$users = new UserTable(DB::get());
$id = $users->findIdByName($name);
}catch(Exception $e){
Log::critical($e);
return false;
}
return $id !== null && $this->tryLoginWithId($id);
}
public function tryLoginWithId(UserId $id): bool{
if ($this->login !== null){
$this->login = SessionLoginInfo::guest();
}
try{
$token = bin2hex(random_bytes(32));
$logins = new UserLoginTable(DB::get());
$logins->addOrRenewToken($id, $token, self::TOKEN_EXPIRATION_TIME);
$this->login = self::checkToken($token, false);
self::setCookie($token);
return true;
}catch(Exception $e){
Log::critical($e);
return false;
}
}
public function destroyCurrentLogin(): void{
if (isset($_COOKIE[self::COOKIE_NAME])){
try{
$logins = new UserLoginTable(DB::get());
$logins->destroyToken($_COOKIE[self::COOKIE_NAME]);
}catch(Exception $e){
Log::critical($e);
}finally{
unset($_COOKIE[self::COOKIE_NAME]);
}
}
$this->login = null;
self::unsetCookie();
}
}
?>