Complete port of all 163 API endpoints from Lucee/CFML to PHP 8.3. Shared helpers in api/helpers.php (DB, auth, request/response, security). PDO prepared statements throughout. Same JSON response shapes as CFML.
78 lines
2 KiB
PHP
78 lines
2 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../helpers.php';
|
|
runAuth();
|
|
|
|
/*
|
|
Verify OTP Code for Portal Login (supports email or phone)
|
|
POST: { "Email": "user@example.com", "Code": "123456" }
|
|
or { "Phone": "3105551234", "Code": "123456" }
|
|
or { "Identifier": "...", "Code": "123456" }
|
|
Returns: { OK: true, UserID, FirstName, Token }
|
|
*/
|
|
|
|
$data = readJsonBody();
|
|
$identifier = trim($data['Identifier'] ?? $data['Email'] ?? $data['Phone'] ?? '');
|
|
$code = trim($data['Code'] ?? '');
|
|
|
|
if (empty($identifier) || empty($code)) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'missing_fields', 'MESSAGE' => 'Email/phone and code are required']);
|
|
}
|
|
|
|
$isPhone = isPhoneNumber($identifier);
|
|
$email = '';
|
|
$phone = '';
|
|
|
|
if ($isPhone) {
|
|
$phone = normalizePhone($identifier);
|
|
} else {
|
|
$email = $identifier;
|
|
}
|
|
|
|
if (!empty($email)) {
|
|
$user = queryOne(
|
|
"SELECT ID, FirstName FROM Users WHERE EmailAddress = ? AND IsActive = 1 LIMIT 1",
|
|
[$email]
|
|
);
|
|
} else {
|
|
$user = queryOne(
|
|
"SELECT ID, FirstName FROM Users WHERE ContactNumber = ? AND IsActive = 1 LIMIT 1",
|
|
[$phone]
|
|
);
|
|
}
|
|
|
|
if (!$user) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'invalid_code', 'MESSAGE' => 'Invalid or expired code']);
|
|
}
|
|
|
|
$uid = (int) $user['ID'];
|
|
|
|
// Check for valid OTP in OTPCodes table
|
|
$otpRow = queryOne(
|
|
"SELECT ID FROM OTPCodes
|
|
WHERE UserID = ? AND Code = ? AND ExpiresAt > NOW() AND UsedAt IS NULL
|
|
ORDER BY CreatedAt DESC
|
|
LIMIT 1",
|
|
[$uid, $code]
|
|
);
|
|
|
|
if (!$otpRow) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'invalid_code', 'MESSAGE' => 'Invalid or expired code']);
|
|
}
|
|
|
|
// Mark OTP as used
|
|
queryTimed("UPDATE OTPCodes SET UsedAt = NOW() WHERE ID = ?", [$otpRow['ID']]);
|
|
|
|
// Create auth token
|
|
$token = generateSecureToken();
|
|
queryTimed(
|
|
"INSERT INTO UserTokens (UserID, Token) VALUES (?, ?)",
|
|
[$uid, $token]
|
|
);
|
|
|
|
jsonResponse([
|
|
'OK' => true,
|
|
'ERROR' => '',
|
|
'UserID' => $uid,
|
|
'FirstName' => $user['FirstName'],
|
|
'Token' => $token,
|
|
]);
|