import { generateTOTP } from "../utils/totp"; import { createSmsGatewayClient } from "../lib/sms-gateway"; import { isRateLimited } from "../utils/rate-limiter.js"; import { normalizeAndValidatePhoneNumber } from "../utils/phone-validator.js"; export default defineEventHandler(async (event) => { const config = useRuntimeConfig(); const { phoneNumber: rawPhoneNumber } = await readBody(event); let normalizedPhoneNumber; try { normalizedPhoneNumber = normalizeAndValidatePhoneNumber(rawPhoneNumber); } catch (error) { // The validator throws an error with a user-friendly message. throw createError({ statusCode: 400, statusMessage: error.message }); } // Prevent abuse by checking rate limit before sending an SMS if (isRateLimited(normalizedPhoneNumber)) { throw createError({ statusCode: 429, statusMessage: "You have already sent a message within the last week. Please try again later.", }); } if (!config.superSecretSalt) { console.error("SUPER_SECRET_SALT is not configured on the server."); throw createError({ statusCode: 500, statusMessage: "A server configuration error occurred.", }); } try { const api = createSmsGatewayClient(config); const otp = generateTOTP(normalizedPhoneNumber, config.superSecretSalt); const step_min = Math.floor(getTOTPstep() / 60); const step_sec = getTOTPstep() % 60; const message = { phoneNumbers: [normalizedPhoneNumber], message: `${otp} is your verification code. This code is valid for ${step_min}m${step_sec}s.`, }; const state = await api.send(message); return { success: true, messageId: state.id }; } catch (error) { console.error("Failed to send OTP:", error); throw createError({ statusCode: 500, statusMessage: "An error occurred while trying to send the verification code.", }); } });