context = $context; $this->user = $user; $this->stayLoggedIn = false; $this->csrfToken = $csrfToken ?? generateRandomString(16); $this->expires = (new DateTime())->modify(sprintf("+%d second", Session::DURATION)); $this->active = true; } public static function init(Context $context, int $userId, int $sessionId): ?Session { $session = Session::find($context->getSQL(), $sessionId, true, true); if (!$session || !$session->active || $session->user->getId() !== $userId) { return null; } 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(); } } } $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) { $this->data = $data; foreach ($data as $key => $value) { $_SESSION[$key] = $value; } } public function getCookie(): string { $this->updateMetaData(); $settings = $this->context->getSettings(); $token = ['userId' => $this->user->getId(), 'sessionId' => $this->getId()]; $jwtPublicKey = $settings->getJwtPublicKey(); return JWT::encode($token, $jwtPublicKey->getKeyMaterial(), $jwtPublicKey->getAlgorithm()); } public function sendCookie(string $domain) { $sessionCookie = $this->getCookie(); $secure = strcmp(getProtocol(), "https") === 0; setcookie('session', $sessionCookie, $this->getExpiresTime(), "/", $domain, $secure, true); } 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; return $this->save($this->context->getSQL(), ["active"]); } 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) && $this->save($sql, ["expires", "data", "os", "browser"]); } public function getCsrfToken(): string { return $this->csrfToken; } }