Add sendSMS() to helpers.php using Twilio REST API with cURL, credentials loaded from config/twilio.json. Wire into sendOTP, loginOTP, and sendLoginOTP endpoints, replacing TODO stubs. SMS is auto-skipped on dev environments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
88 lines
2.4 KiB
PHP
88 lines
2.4 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../helpers.php';
|
|
runAuth();
|
|
|
|
/*
|
|
Send OTP Code for Portal Login
|
|
POST: { "Email": "user@example.com" } or { "Phone": "3105551234" } or { "Identifier": "..." }
|
|
Returns: { OK: true } always (don't reveal if account exists)
|
|
*/
|
|
|
|
$data = readJsonBody();
|
|
$identifier = trim($data['Identifier'] ?? $data['Email'] ?? $data['Phone'] ?? '');
|
|
|
|
if (empty($identifier)) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'missing_identifier', 'MESSAGE' => 'Email or phone is required']);
|
|
}
|
|
|
|
$isPhone = isPhoneNumber($identifier);
|
|
$email = '';
|
|
$phone = '';
|
|
|
|
if ($isPhone) {
|
|
$phone = normalizePhone($identifier);
|
|
} else {
|
|
$email = $identifier;
|
|
}
|
|
|
|
$genericResponse = ['OK' => true, 'MESSAGE' => 'If an account exists, a code has been sent.'];
|
|
|
|
try {
|
|
if (!empty($email)) {
|
|
$user = queryOne(
|
|
"SELECT ID, FirstName, ContactNumber FROM Users WHERE EmailAddress = ? AND IsActive = 1 LIMIT 1",
|
|
[$email]
|
|
);
|
|
} else {
|
|
$user = queryOne(
|
|
"SELECT ID, FirstName, ContactNumber FROM Users WHERE ContactNumber = ? AND IsActive = 1 LIMIT 1",
|
|
[$phone]
|
|
);
|
|
}
|
|
|
|
// Always return OK to not reveal if account exists
|
|
if (!$user) {
|
|
jsonResponse($genericResponse);
|
|
}
|
|
|
|
$uid = (int) $user['ID'];
|
|
|
|
// Rate limit: max 3 codes per user in last 10 minutes
|
|
$rateCheck = queryOne(
|
|
"SELECT COUNT(*) AS cnt FROM OTPCodes WHERE UserID = ? AND CreatedAt > DATE_SUB(NOW(), INTERVAL 10 MINUTE)",
|
|
[$uid]
|
|
);
|
|
|
|
if (((int) ($rateCheck['cnt'] ?? 0)) >= 3) {
|
|
jsonResponse($genericResponse);
|
|
}
|
|
|
|
$code = random_int(100000, 999999);
|
|
$dev = isDev();
|
|
|
|
// Store with 10-minute expiry
|
|
queryTimed(
|
|
"INSERT INTO OTPCodes (UserID, Code, ExpiresAt) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 10 MINUTE))",
|
|
[$uid, $code]
|
|
);
|
|
|
|
// Send OTP via SMS or email (skip on dev)
|
|
if (!$dev) {
|
|
if (!empty($phone) && !empty($user['ContactNumber'])) {
|
|
sendSMS("+1" . $user['ContactNumber'], "Your Payfrit login code is: {$code}. It expires in 10 minutes.");
|
|
} else {
|
|
// TODO: Email sending
|
|
}
|
|
}
|
|
|
|
$resp = $genericResponse;
|
|
if ($dev) {
|
|
$resp['DEV_OTP'] = $code;
|
|
}
|
|
jsonResponse($resp);
|
|
|
|
} catch (\Exception $e) {
|
|
// Swallow errors — always return generic OK
|
|
error_log("sendLoginOTP error for {$email}: " . $e->getMessage());
|
|
jsonResponse($genericResponse);
|
|
}
|