96 lines
3.6 KiB
PHP
96 lines
3.6 KiB
PHP
<?php
|
|
// ride_server/intaleq/functions.php
|
|
// Bootstrap helpers for standalone REST endpoints under ride_server/intaleq/.
|
|
// Mirrors the env/key conventions already deployed on this box for
|
|
// ride_server/passenger_socket.php (/home/intaleq-rides/...), not invented.
|
|
|
|
use Firebase\JWT\JWT;
|
|
use Firebase\JWT\Key;
|
|
use Firebase\JWT\ExpiredException;
|
|
use Firebase\JWT\SignatureInvalidException;
|
|
use Firebase\JWT\BeforeValidException;
|
|
|
|
// Shared secret used to authenticate to loction_server's internal HTTP API —
|
|
// same mechanism ride_server/passenger_socket.php already uses on this box.
|
|
function getInternalSocketKey(): string {
|
|
$key = getenv('INTERNAL_SOCKET_KEY');
|
|
if ($key) return trim($key);
|
|
$path = getenv('INTERNAL_SOCKET_KEY_PATH') ?: '/home/intaleq-rides/.internal_socket_key';
|
|
if (file_exists($path)) return trim((string) @file_get_contents($path));
|
|
return '';
|
|
}
|
|
|
|
// JWT signing secret — must resolve to the same value backend's
|
|
// core/Auth/JwtService.php signs tokens with, or every token fails here.
|
|
function getJwtSecret(): string {
|
|
$keyPath = getenv('JWT_SECRET_KEY_PATH');
|
|
if ($keyPath && file_exists($keyPath)) {
|
|
return trim(file_get_contents($keyPath));
|
|
}
|
|
return getenv('JWT_SECRET_KEY') ?: '';
|
|
}
|
|
|
|
function authenticateJWT() {
|
|
$secretKey = getJwtSecret();
|
|
if (!$secretKey) {
|
|
error_log("[ride_server] JWT secret not configured.");
|
|
http_response_code(500);
|
|
echo json_encode(['status' => 'failure', 'message' => 'Internal server configuration error.']);
|
|
exit;
|
|
}
|
|
|
|
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
|
|
$token = null;
|
|
if (preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
|
|
$token = $matches[1];
|
|
}
|
|
if (!$token) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failure', 'message' => 'Authorization token required']);
|
|
exit;
|
|
}
|
|
|
|
try {
|
|
return JWT::decode($token, new Key($secretKey, 'HS256'));
|
|
} catch (ExpiredException $e) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failure', 'message' => 'Token expired']);
|
|
exit;
|
|
} catch (SignatureInvalidException $e) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failure', 'message' => 'Invalid token signature']);
|
|
exit;
|
|
} catch (BeforeValidException $e) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failure', 'message' => 'Token not yet valid']);
|
|
exit;
|
|
} catch (Exception $e) {
|
|
http_response_code(401);
|
|
echo json_encode(['status' => 'failure', 'message' => 'Invalid token']);
|
|
exit;
|
|
}
|
|
// NOTE: signature/expiry only — does not replicate backend's
|
|
// core/Auth/JwtService::authenticate() JTI-blacklist (revoked-token)
|
|
// check or X-Device-FP verification. Flagged as a follow-up in the
|
|
// plan; not blocking for this read-only endpoint.
|
|
}
|
|
|
|
// Flutter's CRUD().get() always issues an HTTP POST under the hood
|
|
// (see siro_rider/lib/controller/functions/crud.dart _makeRequest/doPost) —
|
|
// so every field this endpoint reads comes through $_POST, never $_GET.
|
|
function filterRequest($requestname, $type = 'string') {
|
|
if (isset($_POST[$requestname]) && $_POST[$requestname] !== '') {
|
|
$value = trim($_POST[$requestname]);
|
|
$value = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $value);
|
|
if ($type === 'numeric') {
|
|
return filter_var($value, FILTER_VALIDATE_FLOAT) !== false ? $value : null;
|
|
}
|
|
return $value;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function printFailure($message = "none") {
|
|
echo json_encode(["status" => "failure", "message" => $message]);
|
|
}
|