diff --git a/api/auth/loginOTP.php b/api/auth/loginOTP.php index 82adacc..ee36206 100644 --- a/api/auth/loginOTP.php +++ b/api/auth/loginOTP.php @@ -37,13 +37,9 @@ $otp = random_int(100000, 999999); queryTimed("UPDATE Users SET MobileVerifyCode = ? WHERE ID = ?", [$otp, $user['ID']]); // Send OTP via Twilio (skip on dev) -$smsMessage = 'Code saved (SMS skipped in dev)'; $dev = isDev(); - -if (!$dev) { - // TODO: Twilio integration - $smsMessage = 'Login code sent'; -} +$smsResult = sendSMS("+1{$phone}", "Your Payfrit code is: {$otp}"); +$smsMessage = $smsResult['success'] ? 'Login code sent' : ('SMS failed - ' . $smsResult['message']); $resp = [ 'OK' => true, diff --git a/api/auth/sendLoginOTP.php b/api/auth/sendLoginOTP.php index 53f4033..ad7e1ba 100644 --- a/api/auth/sendLoginOTP.php +++ b/api/auth/sendLoginOTP.php @@ -66,10 +66,10 @@ try { [$uid, $code] ); - // Send OTP via email or SMS (skip on dev) + // Send OTP via SMS or email (skip on dev) if (!$dev) { if (!empty($phone) && !empty($user['ContactNumber'])) { - // TODO: Twilio SMS + sendSMS("+1" . $user['ContactNumber'], "Your Payfrit login code is: {$code}. It expires in 10 minutes."); } else { // TODO: Email sending } diff --git a/api/auth/sendOTP.php b/api/auth/sendOTP.php index b2b9b13..4e32326 100644 --- a/api/auth/sendOTP.php +++ b/api/auth/sendOTP.php @@ -46,13 +46,9 @@ if ($existing) { } // Send OTP via Twilio (skip on dev) -$smsMessage = 'Code saved (SMS skipped in dev)'; $dev = isDev(); - -if (!$dev) { - // TODO: Twilio integration - $smsMessage = 'Code sent'; -} +$smsResult = sendSMS("+1{$phone}", "Your Payfrit code is: {$otp}"); +$smsMessage = $smsResult['success'] ? 'Code sent' : ('SMS failed - ' . $smsResult['message']); $resp = [ 'OK' => true, diff --git a/api/helpers.php b/api/helpers.php index 6fd6daa..14e4921 100644 --- a/api/helpers.php +++ b/api/helpers.php @@ -237,6 +237,61 @@ function generateUUID(): string { return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($bytes), 4)); } +// ============================================ +// TWILIO SMS +// ============================================ + +/** + * Send an SMS via Twilio REST API. + * Returns ['success' => bool, 'message' => string]. + * Skips sending on dev (returns success with note). + */ +function sendSMS(string $to, string $body): array { + if (isDev()) { + return ['success' => true, 'message' => 'SMS skipped in dev']; + } + + $configPath = realpath(__DIR__ . '/../config/twilio.json'); + if (!$configPath || !file_exists($configPath)) { + return ['success' => false, 'message' => 'Twilio config not found']; + } + + $config = json_decode(file_get_contents($configPath), true); + $sid = $config['accountSid'] ?? ''; + $token = $config['authToken'] ?? ''; + $from = $config['fromNumber'] ?? ''; + + if (empty($sid) || empty($token) || empty($from)) { + return ['success' => false, 'message' => 'Twilio config incomplete']; + } + + $url = "https://api.twilio.com/2010-04-01/Accounts/{$sid}/Messages.json"; + + $ch = curl_init($url); + curl_setopt_array($ch, [ + CURLOPT_POST => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_USERPWD => "{$sid}:{$token}", + CURLOPT_POSTFIELDS => http_build_query([ + 'From' => $from, + 'To' => $to, + 'Body' => $body, + ]), + ]); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode === 201) { + return ['success' => true, 'message' => 'Message sent']; + } + + $parsed = json_decode($response, true); + $errMsg = $parsed['message'] ?? "HTTP $httpCode"; + return ['success' => false, 'message' => $errMsg]; +} + // ============================================ // AUTH MIDDLEWARE // ============================================ diff --git a/config/twilio.json b/config/twilio.json new file mode 100644 index 0000000..746ac97 --- /dev/null +++ b/config/twilio.json @@ -0,0 +1,5 @@ +{ + "accountSid": "AC3e218c8f3496f2e3f95d3f9bb943f65a", + "authToken": "493df16db970ca6cc141768de2db7db3", + "fromNumber": "+16506678425" +}