<?php if (!defined('STORE_ROOT')) { http_response_code(403); exit; } class Auth { public static function login($email, $password) { $emailHash = hash('sha256', strtolower(trim($email))); $matched = Database::one( "SELECT id, email, password_hash, name, status, status_code FROM users WHERE email_hash = :eh", [':eh' => $emailHash] ); if (!$matched || !password_verify($password, $matched['password_hash'])) { return ['success' => false, 'error' => 'Invalid email or password.']; } $statusCode = (int)($matched['status_code'] ?? 0); if ($statusCode === 1002 || $statusCode === 1003) { return ['success' => false, 'error' => 'Account is not active.']; } if ($statusCode === 1004) { return ['success' => false, 'error' => 'Please verify your email first.']; } $_SESSION['user_id'] = (int)$matched['id']; $_SESSION['user_email'] = Crypt::encrypt($email, Crypt::DOMAIN_USER); $_SESSION['user_name'] = Crypt::render($matched['name']); $_SESSION['login_time'] = time(); Database::execute( "UPDATE users SET last_login = NOW(), last_ip = :ip WHERE id = :id", [':ip' => $_SERVER['REMOTE_ADDR'] ?? '', ':id' => $matched['id']] ); return ['success' => true]; } public static function register($email, $password, $name, $storeId = 1) { $emailHash = hash('sha256', strtolower(trim($email))); $exists = Database::one( "SELECT id FROM users WHERE email_hash = :eh", [':eh' => $emailHash] ); if ($exists) { return ['success' => false, 'error' => 'Email already registered.']; } $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]); $token = bin2hex(random_bytes(32)); $parts = explode(' ', trim($name), 2); $firstName = $parts[0]; $lastName = $parts[1] ?? ''; $id = Database::insert( "INSERT INTO users (email, email_hash, password_hash, name, first_name, last_name, verify_token, status, status_code, trust_score, created_at)              VALUES (:email, :eh, :hash, :name, :fn, :ln, :token, 'unverified', 1004, 50, NOW())", [ ':email' => Crypt::encrypt($email, Crypt::DOMAIN_USER), ':eh' => $emailHash, ':hash' => $hash, ':name' => Crypt::encrypt($name, Crypt::DOMAIN_USER), ':fn' => Crypt::encrypt($firstName, Crypt::DOMAIN_USER), ':ln' => Crypt::encrypt($lastName, Crypt::DOMAIN_USER), ':token' => $token, ] ); require_once __DIR__ . '/email_bridge.php'; $verifyUrl = EmailBridge::verifyUrl($token); EmailBridge::send(EmailBridge::TYPE_VERIFY, [ 'email' => $email, 'name' => $name, 'url' => $verifyUrl, 'token' => $token ]); return ['success' => true, 'user_id' => $id, 'verify_token' => $token]; } public static function logout() { $_SESSION = []; if (ini_get('session.use_cookies')) { $p = session_get_cookie_params(); setcookie(session_name(), '', time() - 42000, $p['path'], $p['domain'], $p['secure'], $p['httponly']); } session_destroy(); } public static function user() { if (!self::isLoggedIn()) return null; return [ 'id' => $_SESSION['user_id'], 'email' => isset($_SESSION['user_email']) ? Crypt::d($_SESSION['user_email']) : '', 'name' => $_SESSION['user_name'] ?? '', ]; } public static function isLoggedIn() { return isset($_SESSION['user_id']) && $_SESSION['user_id'] > 0; } public static function check() { return self::isLoggedIn(); } public static function id() { return (int)($_SESSION['user_id'] ?? 0); } public static function csrf() { if (empty($_SESSION[CSRF_TOKEN_NAME]) || empty($_SESSION['_csrf_ts']) || (time() - $_SESSION['_csrf_ts'] > 1800)) { $_SESSION[CSRF_TOKEN_NAME] = bin2hex(random_bytes(32)); $_SESSION['_csrf_ts'] = time(); } return $_SESSION[CSRF_TOKEN_NAME]; } public static function validateCsrf($token) { if (empty($token) || empty($_SESSION[CSRF_TOKEN_NAME])) return false; if (empty($_SESSION['_csrf_ts']) || (time() - $_SESSION['_csrf_ts'] > 1800)) return false; return hash_equals($_SESSION[CSRF_TOKEN_NAME], $token); } public static function regenerateCsrf() { $_SESSION[CSRF_TOKEN_NAME] = bin2hex(random_bytes(32)); $_SESSION['_csrf_ts'] = time(); return $_SESSION[CSRF_TOKEN_NAME]; } } 
