[FEAT] First functional version.

This commit is contained in:
NADAL Jean-Baptiste
2026-02-18 10:08:48 +01:00
parent 5c93000873
commit bc6e603af4
32 changed files with 5618 additions and 30 deletions

122
api/lib/Auth.php Normal file
View File

@@ -0,0 +1,122 @@
<?php
class Auth {
private const JWT_SECRET = 'ohmj_secret_key_change_in_production';
private const JWT_ALGO = 'HS256';
private const JWT_EXPIRY = 3600; // 1 hour
private string $usersFile;
public function __construct(string $usersFile = null) {
$this->usersFile = $usersFile ?? __DIR__ . '/../config/users.json';
}
public function login(string $username, string $password): array {
$users = $this->loadUsers();
foreach ($users['users'] as $user) {
if ($user['username'] === $username) {
if (password_verify($password, $user['password'])) {
$token = $this->generateToken($user);
return [
'success' => true,
'token' => $token,
'user' => [
'username' => $user['username'],
'role' => $user['role']
]
];
}
return ['success' => false, 'error' => 'Invalid password'];
}
}
return ['success' => false, 'error' => 'User not found'];
}
public function verifyToken(string $token): ?array {
$parts = explode('.', $token);
if (count($parts) !== 3) {
return null;
}
list($header, $payload, $signature) = $parts;
// Verify signature
$expectedSignature = base64_encode(
hash_hmac('sha256', "$header.$payload", self::JWT_SECRET, true)
);
if (!hash_equals($expectedSignature, $signature)) {
return null;
}
// Decode payload
$payloadData = json_decode(base64_decode($payload), true);
// Check expiry
if (isset($payloadData['exp']) && $payloadData['exp'] < time()) {
return null;
}
return $payloadData;
}
public function requireAuth(string $token): array {
$payload = $this->verifyToken($token);
if ($payload === null) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
return $payload;
}
public function requireAdmin(string $token): array {
$payload = $this->requireAuth($token);
if ($payload['role'] !== 'admin') {
http_response_code(403);
echo json_encode(['error' => 'Forbidden']);
exit;
}
return $payload;
}
private function generateToken(array $user): string {
$header = base64_encode(json_encode([
'alg' => self::JWT_ALGO,
'typ' => 'JWT'
]));
$payload = base64_encode(json_encode([
'username' => $user['username'],
'role' => $user['role'],
'iat' => time(),
'exp' => time() + self::JWT_EXPIRY
]));
$signature = base64_encode(
hash_hmac('sha256', "$header.$payload", self::JWT_SECRET, true)
);
return "$header.$payload.$signature";
}
private function loadUsers(): array {
if (!file_exists($this->usersFile)) {
return ['users' => []];
}
$content = file_get_contents($this->usersFile);
return json_decode($content, true) ?? ['users' => []];
}
public function hashPassword(string $password): string {
return password_hash($password, PASSWORD_BCRYPT);
}
}