Files
flash-call-otp/backend/api/pending-sms.php
2026-05-23 16:17:20 +03:00

122 lines
3.7 KiB
PHP

<?php
/**
* GET /api/pending-sms
*
* Called by Caller Android App every 3 seconds to fetch the next pending SMS task.
*
* Query params:
* device_id — Registered device identifier
* app_key — Device authentication key
*/
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, X-App-Key');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_response_code(405);
echo json_encode(['success' => false, 'message' => 'method_not_allowed']);
exit;
}
require_once __DIR__ . '/../includes/Database.php';
require_once __DIR__ . '/../includes/Auth.php';
require_once __DIR__ . '/../includes/Logger.php';
// Authenticate — requires device key
Auth::requireAuth('device');
$deviceId = $_GET['device_id'] ?? null;
if (!$deviceId) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'missing_device_id']);
RequestLogger::log('pending-sms', 'GET', $_GET, 400, 'missing_device_id');
exit;
}
$db = Database::getInstance();
try {
// Verify device exists and is active
$stmt = $db->prepare(
"SELECT id, device_id, is_active FROM caller_devices WHERE device_id = ?"
);
$stmt->execute([$deviceId]);
$device = $stmt->fetch();
if (!$device || !$device['is_active']) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'device_not_registered_or_inactive']);
RequestLogger::log('pending-sms', 'GET', $_GET, 403, 'invalid_device');
exit;
}
// Update last_seen
$stmt = $db->prepare("UPDATE caller_devices SET last_seen = NOW() WHERE device_id = ?");
$stmt->execute([$deviceId]);
// Find oldest pending SMS task
$stmt = $db->prepare(
"SELECT id, phone, otp_code, expires_at
FROM otp_requests
WHERE method = 'sms'
AND status = 'pending_sms'
AND expires_at > NOW()
AND (device_id IS NULL OR device_id = ?)
ORDER BY
CASE WHEN device_id = ? THEN 0 ELSE 1 END,
created_at ASC
LIMIT 1"
);
$stmt->execute([$deviceId, $deviceId]);
$task = $stmt->fetch();
if (!$task) {
echo json_encode(['success' => true, 'task_id' => null]);
RequestLogger::log('pending-sms', 'GET', $_GET, 200);
exit;
}
// Claim this task
$stmt = $db->prepare(
"UPDATE otp_requests
SET status = 'calling', device_id = ?, updated_at = NOW()
WHERE id = ? AND status = 'pending_sms'"
);
$stmt->execute([$deviceId, $task['id']]);
if ($stmt->rowCount() === 0) {
echo json_encode(['success' => true, 'task_id' => null]);
RequestLogger::log('pending-sms', 'GET', $_GET, 200);
exit;
}
// Calculate remaining timeout
$expiresAt = new \DateTime($task['expires_at']);
$now = new \DateTime();
$timeoutSeconds = max(10, $expiresAt->getTimestamp() - $now->getTimestamp());
echo json_encode([
'success' => true,
'task_id' => (int) $task['id'],
'phone' => $task['phone'],
'otp' => $task['otp_code'],
'timeout_seconds' => $timeoutSeconds,
]);
RequestLogger::log('pending-sms', 'GET', $_GET, 200);
} catch (\Throwable $e) {
error_log('pending-sms error: ' . $e->getMessage());
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'internal_error']);
RequestLogger::log('pending-sms', 'GET', $_GET, 500, $e->getMessage());
}