telvero_whatson_talpa/auth/auth_functions.php
2026-02-19 15:58:15 +01:00

306 lines
7.3 KiB
PHP

<?php
/**
* Authentication Helper Functions
* Telvero Talpa Planning System
*/
if (session_status() === PHP_SESSION_NONE) {
// Secure session settings
ini_set('session.cookie_httponly', 1);
ini_set('session.use_strict_mode', 1);
ini_set('session.cookie_samesite', 'Lax');
session_start();
}
/**
* Get database connection for auth
*/
function getAuthDb(): PDO {
static $db = null;
if ($db === null) {
// Load env if not already loaded
if (!isset($_ENV['DB_HOST'])) {
require_once __DIR__ . '/../vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/..');
$dotenv->load();
}
$db = new PDO(
"mysql:host={$_ENV['DB_HOST']};dbname={$_ENV['DB_NAME']};charset=utf8mb4",
$_ENV['DB_USER'],
$_ENV['DB_PASS'],
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
}
return $db;
}
/**
* Check if user is logged in
*/
function isLoggedIn(): bool {
return isset($_SESSION['user_id']) && isset($_SESSION['user']) && !empty($_SESSION['user']);
}
/**
* Get current logged in user
*/
function getCurrentUser(): ?array {
return $_SESSION['user'] ?? null;
}
/**
* Check if user has specific role
*/
function hasRole(string $role): bool {
if (!isLoggedIn()) {
return false;
}
return ($_SESSION['user']['role'] ?? '') === $role;
}
/**
* Check if user is admin
*/
function isAdmin(): bool {
return hasRole('admin');
}
/**
* Check if user is guest
*/
function isGuest(): bool {
return hasRole('guest');
}
/**
* Check if user can perform write operations
*/
function canWrite(): bool {
return isLoggedIn() && isAdmin();
}
/**
* Check if user can create
*/
function canCreate(): bool {
return isAdmin();
}
/**
* Check if user can edit
*/
function canEdit(): bool {
return isAdmin();
}
/**
* Check if user can delete
*/
function canDelete(): bool {
return isAdmin();
}
/**
* Check if user can sync with Talpa
*/
function canSync(): bool {
return isAdmin();
}
/**
* Require user to be logged in, redirect to login if not
*/
function requireLogin(): void {
if (!isLoggedIn()) {
$currentUrl = $_SERVER['REQUEST_URI'] ?? '/';
$redirect = urlencode(ltrim($currentUrl, '/'));
header("Location: /auth/login.php?redirect=$redirect");
exit;
}
}
/**
* Require user to have specific role
*/
function requireRole(string $role): void {
requireLogin();
if (!hasRole($role)) {
http_response_code(403);
include __DIR__ . '/403.php';
exit;
}
}
/**
* Require admin role
*/
function requireAdmin(): void {
requireRole('admin');
}
/**
* Check brute force protection
* Returns true if user is blocked
*/
function isBlockedByBruteForce(string $username, string $ip): bool {
try {
$db = getAuthDb();
// Check by username
$stmt = $db->prepare("
SELECT COUNT(*) FROM login_attempts
WHERE username = ? AND success = 0
AND attempted_at > DATE_SUB(NOW(), INTERVAL 15 MINUTE)
");
$stmt->execute([$username]);
if ($stmt->fetchColumn() >= 5) {
return true;
}
// Check by IP
$stmt = $db->prepare("
SELECT COUNT(*) FROM login_attempts
WHERE ip_address = ? AND success = 0
AND attempted_at > DATE_SUB(NOW(), INTERVAL 15 MINUTE)
");
$stmt->execute([$ip]);
if ($stmt->fetchColumn() >= 10) {
return true;
}
} catch (Exception $e) {
// If we can't check, allow the attempt
}
return false;
}
/**
* Log a login attempt
*/
function logLoginAttempt(string $username, string $ip, bool $success): void {
try {
$db = getAuthDb();
$stmt = $db->prepare("
INSERT INTO login_attempts (username, ip_address, success)
VALUES (?, ?, ?)
");
$stmt->execute([$username, $ip, $success ? 1 : 0]);
} catch (Exception $e) {
// Silently fail
}
}
/**
* Attempt to login a user
* Returns array with 'success', 'user', 'error' keys
*/
function attemptLogin(string $usernameOrEmail, string $password): array {
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
// Check brute force
if (isBlockedByBruteForce($usernameOrEmail, $ip)) {
return [
'success' => false,
'error' => 'Te veel mislukte inlogpogingen. Probeer het over 15 minuten opnieuw.'
];
}
try {
$db = getAuthDb();
// Find user by username or email
$stmt = $db->prepare("
SELECT id, username, email, password_hash, role, is_active
FROM users
WHERE (username = ? OR email = ?)
LIMIT 1
");
$stmt->execute([$usernameOrEmail, $usernameOrEmail]);
$user = $stmt->fetch();
if (!$user) {
logLoginAttempt($usernameOrEmail, $ip, false);
return ['success' => false, 'error' => 'Ongeldige gebruikersnaam of wachtwoord.'];
}
if (!$user['is_active']) {
logLoginAttempt($usernameOrEmail, $ip, false);
return ['success' => false, 'error' => 'Dit account is gedeactiveerd. Neem contact op met de beheerder.'];
}
if (!password_verify($password, $user['password_hash'])) {
logLoginAttempt($usernameOrEmail, $ip, false);
return ['success' => false, 'error' => 'Ongeldige gebruikersnaam of wachtwoord.'];
}
// Success - create session
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
$_SESSION['user'] = [
'id' => $user['id'],
'username' => $user['username'],
'email' => $user['email'],
'role' => $user['role'],
];
$_SESSION['login_time'] = time();
// Log success
logLoginAttempt($usernameOrEmail, $ip, true);
// Update last login
$stmt = $db->prepare("UPDATE users SET last_login = NOW() WHERE id = ?");
$stmt->execute([$user['id']]);
return ['success' => true, 'user' => $_SESSION['user']];
} catch (Exception $e) {
return ['success' => false, 'error' => 'Er is een fout opgetreden. Probeer het opnieuw.'];
}
}
/**
* Logout the current user
*/
function logout(): void {
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(
session_name(),
'',
time() - 42000,
$params['path'],
$params['domain'],
$params['secure'],
$params['httponly']
);
}
session_destroy();
}
/**
* Check session timeout (2 hours of inactivity)
*/
function checkSessionTimeout(): void {
$timeout = 7200; // 2 hours
if (isLoggedIn()) {
if (isset($_SESSION['login_time']) && (time() - $_SESSION['login_time']) > $timeout) {
logout();
header("Location: /auth/login.php?reason=timeout");
exit;
}
// Update last activity
$_SESSION['login_time'] = time();
}
}
// Check session timeout on every request
checkSessionTimeout();