diff --git a/src/app/api/auth/debug-sms-config/route.js b/src/app/api/auth/debug-sms-config/route.js index 967fd43b..b9f8bba7 100644 --- a/src/app/api/auth/debug-sms-config/route.js +++ b/src/app/api/auth/debug-sms-config/route.js @@ -81,13 +81,15 @@ export async function POST(request, { params } = {}) { try { const { testPhoneNumber } = await request.json(); - if (!testPhoneNumber) { + if (typeof testPhoneNumber !== 'string' || !testPhoneNumber.trim()) { return NextResponse.json( - { error: 'testPhoneNumber is required' }, + { error: 'testPhoneNumber must be a non-empty string' }, { status: 400 } ); } + const normalizedPhoneNumber = testPhoneNumber.trim(); + // First run the diagnostic const config = { PROJECT_REF: process.env.PROJECT_REF, @@ -118,7 +120,7 @@ export async function POST(request, { params } = {}) { console.log(`From number: ${config.TWILIO_PHONE_NUMBER || 'Message Service: ' + config.TWILIO_MESSAGE_SERVICE_SID?.substring(0, 8) + '***'}`); const { error: smsError } = await supabase.auth.signInWithOtp({ - phone: testPhoneNumber, + phone: normalizedPhoneNumber, options: { channel: 'sms', shouldCreateUser: true @@ -137,7 +139,7 @@ export async function POST(request, { params } = {}) { code: smsError.code }, diagnostic, - testPhoneNumber: testPhoneNumber.substring(0, 3) + '***' + testPhoneNumber.substring(testPhoneNumber.length - 2), + testPhoneNumber: normalizedPhoneNumber.substring(0, 3) + '***' + normalizedPhoneNumber.substring(normalizedPhoneNumber.length - 2), timestamp: new Date().toISOString() }, { status: 400 }); } @@ -148,7 +150,7 @@ export async function POST(request, { params } = {}) { success: true, message: 'SMS test successful', diagnostic, - testPhoneNumber: testPhoneNumber.substring(0, 3) + '***' + testPhoneNumber.substring(testPhoneNumber.length - 2), + testPhoneNumber: normalizedPhoneNumber.substring(0, 3) + '***' + normalizedPhoneNumber.substring(normalizedPhoneNumber.length - 2), timestamp: new Date().toISOString() }); @@ -165,4 +167,4 @@ export async function POST(request, { params } = {}) { { status: 500 } ); } -} \ No newline at end of file +} diff --git a/src/app/api/auth/debug-sms-config/route.test.js b/src/app/api/auth/debug-sms-config/route.test.js new file mode 100644 index 00000000..d94037ef --- /dev/null +++ b/src/app/api/auth/debug-sms-config/route.test.js @@ -0,0 +1,56 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const mocks = vi.hoisted(() => ({ + diagnoseSMSConfig: vi.fn(), + generateDiagnosticReport: vi.fn(), + createSupabaseServerClient: vi.fn() +})); + +vi.mock('@/lib/utils/sms-config-diagnostic.js', () => ({ + diagnoseSMSConfig: mocks.diagnoseSMSConfig, + generateDiagnosticReport: mocks.generateDiagnosticReport +})); + +vi.mock('@/lib/supabase.js', () => ({ + createSupabaseServerClient: mocks.createSupabaseServerClient +})); + +function postRequest(body) { + return new Request('https://example.com/api/auth/debug-sms-config', { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(body) + }); +} + +describe('POST /api/auth/debug-sms-config', () => { + beforeEach(() => { + vi.resetModules(); + vi.clearAllMocks(); + process.env.NODE_ENV = 'development'; + mocks.diagnoseSMSConfig.mockReturnValue({ isValid: true }); + mocks.generateDiagnosticReport.mockReturnValue('ok'); + }); + + it('rejects non-string phone values before diagnostics or Supabase work', async () => { + const { POST } = await import('./route.js'); + const response = await POST(postRequest({ testPhoneNumber: 15551234567 })); + const body = await response.json(); + + expect(response.status).toBe(400); + expect(body.error).toBe('testPhoneNumber must be a non-empty string'); + expect(mocks.diagnoseSMSConfig).not.toHaveBeenCalled(); + expect(mocks.createSupabaseServerClient).not.toHaveBeenCalled(); + }); + + it('rejects whitespace-only phone values before diagnostics or Supabase work', async () => { + const { POST } = await import('./route.js'); + const response = await POST(postRequest({ testPhoneNumber: ' ' })); + const body = await response.json(); + + expect(response.status).toBe(400); + expect(body.error).toBe('testPhoneNumber must be a non-empty string'); + expect(mocks.diagnoseSMSConfig).not.toHaveBeenCalled(); + expect(mocks.createSupabaseServerClient).not.toHaveBeenCalled(); + }); +});