Files
musadaq-saas/app/bootstrap/response.php
Hamza-Ayed 214d96ee8d Security Hardening: Phase 1-3 complete
- C1: Hash refresh tokens before DB storage (sha256)
- C2: Remove JWT_SECRET fallback, fail hard if missing
- H1: Enforce HTTP methods per route (405 on mismatch)
- H2: CORS with origin whitelist from CORS_ORIGIN env var
- H3: Redact sensitive fields (tokens, passwords) from logs
- M1: Build HmacMiddleware with replay attack prevention
- M2: Fix rate limiter race condition with flock LOCK_EX
- M3: Guard dd() — suppressed in production
- M4: Remove .env from git tracking, strengthen .gitignore
- I1: Add HSTS header (max-age=31536000)
2026-05-03 21:06:17 +03:00

73 lines
2.0 KiB
PHP

<?php
/**
* Standardized JSON Responses with Secure Logging
*/
declare(strict_types=1);
function json_response(bool $success, $data = null, ?string $message = null, int $code = 200) {
// H3 Fix: Redact sensitive fields before logging
$safeData = $data;
if (is_array($safeData)) {
$sensitiveKeys = ['access_token', 'refresh_token', 'password', 'password_hash', 'refresh_token_hash', 'token'];
array_walk_recursive($safeData, function (&$value, $key) use ($sensitiveKeys) {
if (in_array(strtolower((string)$key), $sensitiveKeys, true)) {
$value = '[REDACTED]';
}
});
}
// Log (safe — no secrets)
$logEntry = sprintf(
"API %s %s | %d | %s | %s",
$_SERVER['REQUEST_METHOD'] ?? 'CLI',
$_SERVER['REQUEST_URI'] ?? '',
$code,
$success ? 'OK' : 'FAIL',
$message ?? 'N/A'
);
error_log($logEntry);
// Try custom log file
$logDir = STORAGE_PATH . '/logs';
$logFile = $logDir . '/app.log';
try {
if (!is_dir($logDir)) {
@mkdir($logDir, 0775, true);
}
if (is_writable($logDir) || is_writable($logFile)) {
@file_put_contents(
$logFile,
"[" . date('Y-m-d H:i:s') . "] " . $logEntry . "\n",
FILE_APPEND
);
}
} catch (\Exception $e) {
// Fallback silently
}
// HTTP Response
header('Content-Type: application/json; charset=utf-8');
http_response_code($code);
echo json_encode([
'success' => $success,
'data' => $data, // Return real data to client
'message' => $message,
'timestamp' => date('c')
], JSON_UNESCAPED_UNICODE);
exit;
}
function json_error(string $message, int $code = 400, $errors = null) {
json_response(false, $errors, $message, $code);
}
function json_success($data = null, ?string $message = 'Success', int $code = 200) {
json_response(true, $data, $message, $code);
}