web-base/Core/Objects/DatabaseEntity/Session.class.php

135 lines
3.9 KiB
PHP
Raw Normal View History

2022-06-20 19:52:31 +02:00
<?php
2022-11-18 18:06:46 +01:00
namespace Core\Objects\DatabaseEntity;
2022-06-20 19:52:31 +02:00
use DateTime;
use Exception;
2022-11-18 18:06:46 +01:00
use Core\Objects\Context;
use Core\Objects\DatabaseEntity\Attribute\DefaultValue;
use Core\Objects\DatabaseEntity\Attribute\Json;
use Core\Objects\DatabaseEntity\Attribute\MaxLength;
use Core\Objects\DatabaseEntity\Attribute\Transient;
2022-11-20 17:13:53 +01:00
use Core\Objects\DatabaseEntity\Controller\DatabaseEntity;
2022-06-20 19:52:31 +02:00
class Session extends DatabaseEntity {
# in minutes
const DURATION = 60 * 60 * 24 * 14;
#[Transient] private Context $context;
private User $user;
private DateTime $expires;
#[MaxLength(45)] private string $ipAddress;
2024-03-24 17:36:16 +01:00
#[MaxLength(36)] private string $uuid;
2022-06-20 19:52:31 +02:00
#[DefaultValue(true)] private bool $active;
#[MaxLength(64)] private ?string $os;
#[MaxLength(64)] private ?string $browser;
#[DefaultValue(true)] public bool $stayLoggedIn;
#[MaxLength(16)] private string $csrfToken;
#[Json] private mixed $data;
public function __construct(Context $context, User $user, ?string $csrfToken = null) {
parent::__construct();
$this->context = $context;
$this->user = $user;
2024-03-24 17:36:16 +01:00
$this->uuid = uuidv4();
2022-06-20 19:52:31 +02:00
$this->stayLoggedIn = false;
$this->csrfToken = $csrfToken ?? generateRandomString(16);
$this->expires = (new DateTime())->modify(sprintf("+%d second", Session::DURATION));
$this->active = true;
}
2024-03-24 17:36:16 +01:00
public static function init(Context $context, string $sessionUUID): ?Session {
$sql = $context->getSQL();
$session = Session::findBy(Session::createBuilder($sql, true)
->fetchEntities(true)
->whereEq("Session.uuid", $sessionUUID)
->whereTrue("Session.active")
->whereGt("Session.expires", $sql->now()));
2024-03-24 17:36:16 +01:00
if (!$session) {
2022-06-20 19:52:31 +02:00
return null;
}
$user = $session->getUser();
if (!$user->isActive() || !$user->isConfirmed()) {
return null;
}
2023-03-05 15:30:06 +01:00
if (is_array($session->data)) {
foreach ($session->data as $key => $value) {
$_SESSION[$key] = $value;
if ($key === "2faAuthenticated" && $value === true) {
$tfaToken = $session->getUser()->getTwoFactorToken();
$tfaToken?->authenticate();
}
}
}
2022-06-20 19:52:31 +02:00
$session->context = $context;
return $session;
}
public function getUser(): User {
return $this->user;
}
private function updateMetaData() {
$this->expires = (new \DateTime())->modify(sprintf("+%d minutes", Session::DURATION));
$this->ipAddress = $this->context->isCLI() ? "127.0.0.1" : $_SERVER['REMOTE_ADDR'];
try {
$userAgent = @get_browser($_SERVER['HTTP_USER_AGENT'], true);
$this->os = $userAgent['platform'] ?? "Unknown";
$this->browser = $userAgent['parent'] ?? "Unknown";
} catch (Exception $ex) {
$this->os = "Unknown";
$this->browser = "Unknown";
}
}
public function setData(array $data) {
2023-03-05 15:30:06 +01:00
$this->data = $data;
2022-06-20 19:52:31 +02:00
foreach ($data as $key => $value) {
$_SESSION[$key] = $value;
}
}
2024-03-24 17:36:16 +01:00
public function getUUID(): string {
return $this->uuid;
2022-06-20 19:52:31 +02:00
}
public function sendCookie(string $domain) {
$secure = strcmp(getProtocol(), "https") === 0;
2024-03-24 17:36:16 +01:00
setcookie('session', $this->uuid, $this->getExpiresTime(), "/", $domain, $secure, true);
2022-06-20 19:52:31 +02:00
}
public function getExpiresTime(): int {
return ($this->stayLoggedIn ? $this->expires->getTimestamp() : 0);
}
public function getExpiresSeconds(): int {
return ($this->stayLoggedIn ? $this->expires->getTimestamp() - time() : -1);
}
public function destroy(): bool {
session_destroy();
$this->active = false;
2022-11-29 14:17:11 +01:00
return $this->save($this->context->getSQL(), ["active"]);
2022-06-20 19:52:31 +02:00
}
public function update(): bool {
$this->updateMetaData();
$this->expires = (new DateTime())->modify(sprintf("+%d second", Session::DURATION));
$this->data = json_encode($_SESSION ?? []);
$sql = $this->context->getSQL();
return $this->user->update($sql) &&
2023-03-05 15:30:06 +01:00
$this->save($sql, ["expires", "data", "os", "browser"]);
2022-06-20 19:52:31 +02:00
}
public function getCsrfToken(): string {
return $this->csrfToken;
}
}