fix: Strict env enforcement, rock-solid Alpine portal rendering, and Nabeh/Redis test diagnostics

This commit is contained in:
Hamza-Ayed
2026-08-26 22:25:35 +03:00
parent 388944cbff
commit 1f024d0c30
10 changed files with 990 additions and 702 deletions
+11 -14
View File
@@ -6,17 +6,18 @@ namespace App\Core;
* Advanced OWASP Security Helper
* Handles AES-256-GCM encryption/decryption, HMAC Blind Indexing,
* Bcrypt password hashing, and JWT validation.
* Strict environment variable enforcement (No default fallbacks).
*/
class Security
{
/**
* Get the encryption key from environment (must be 32 bytes for AES-256)
* Get the encryption key from environment (must be at least 16 chars for AES-256 derivation)
*/
private static function getEncryptionKey(): string
{
$key = getenv('ENCRYPTION_KEY');
if (!$key || strlen($key) < 16) {
throw new \RuntimeException("ENCRYPTION_KEY environment variable is empty or too short. Cryptographic operations aborted.");
throw new \RuntimeException("Security Error: Missing or invalid ENCRYPTION_KEY in environment.");
}
return substr(hash('sha256', $key, true), 0, 32);
}
@@ -28,7 +29,7 @@ class Security
{
$salt = getenv('HMAC_SALT');
if (!$salt) {
throw new \RuntimeException("HMAC_SALT environment variable is empty. Cryptographic operations aborted.");
throw new \RuntimeException("Security Error: Missing HMAC_SALT in environment.");
}
return $salt;
}
@@ -40,7 +41,7 @@ class Security
{
$secret = getenv('JWT_SECRET');
if (!$secret) {
throw new \RuntimeException("JWT_SECRET environment variable is empty. Cryptographic operations aborted.");
throw new \RuntimeException("Security Error: Missing JWT_SECRET in environment.");
}
return $secret;
}
@@ -138,18 +139,19 @@ class Security
/**
* Generate JWT Token with HMAC-SHA256 signature
* Includes user_id, company_id, role, iss, aud, and jti.
*/
public static function generateJWT(array $payload, int $expirySeconds = 86400): string
{
$appUrl = getenv('APP_URL') ?: 'https://saqel.intaleqapp.com';
$header = self::base64UrlEncode(json_encode(['alg' => 'HS256', 'typ' => 'JWT']));
// Standard OWASP Claims
$payload['iat'] = time();
$payload['exp'] = time() + $expirySeconds;
$payload['iss'] = getenv('APP_URL'); // Issuer
$payload['aud'] = 'saqel_app'; // Audience
$payload['jti'] = bin2hex(random_bytes(16)); // JWT ID to prevent Replay Attacks
$payload['iss'] = $appUrl;
$payload['aud'] = 'saqel_app';
$payload['jti'] = bin2hex(random_bytes(16));
$payloadEncoded = self::base64UrlEncode(json_encode($payload));
@@ -188,15 +190,10 @@ class Security
if (!$payload || !isset($payload['exp']) || time() >= $payload['exp']) {
return false;
}
// Validate Issuer
$expectedIssuer = getenv('APP_URL');
if (isset($payload['iss']) && $payload['iss'] !== $expectedIssuer) {
return false;
}
return $payload;
}
private static function base64UrlEncode(string $data): string
{
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');