diff --git a/src/app/api/messages/send/route.js b/src/app/api/messages/send/route.js index 8955b65..d59b7b8 100644 --- a/src/app/api/messages/send/route.js +++ b/src/app/api/messages/send/route.js @@ -41,6 +41,10 @@ export const POST = withAuth(async ({ request, locals }) => { return NextResponse.json({ error: 'encryptedContents values must be encrypted content strings' }, { status: 400 }); } + if (Object.values(encryptedContents).some((content) => !content.trim())) { + return NextResponse.json({ error: 'encryptedContents values must not be blank' }, { status: 400 }); + } + if (metadata !== undefined && (typeof metadata !== 'object' || Array.isArray(metadata) || metadata === null)) { return NextResponse.json({ error: 'metadata must be a JSON object' }, { status: 400 }); } diff --git a/src/app/api/messages/send/route.test.js b/src/app/api/messages/send/route.test.js index 71ba0ad..70c88a4 100644 --- a/src/app/api/messages/send/route.test.js +++ b/src/app/api/messages/send/route.test.js @@ -81,6 +81,25 @@ describe('POST /api/messages/send validation', () => { expect(mocks.mockSupabase.from).not.toHaveBeenCalled(); }); + it('rejects blank encrypted content strings before database work', async () => { + const { POST } = await import('./route.js'); + const request = { + json: vi.fn().mockResolvedValue({ + conversationId: 'conversation-1', + encryptedContents: { + 'user-1': ' ' + } + }) + }; + + const response = await POST(request); + const body = await response.json(); + + expect(response.status).toBe(400); + expect(body.error).toBe('encryptedContents values must not be blank'); + expect(mocks.mockSupabase.from).not.toHaveBeenCalled(); + }); + it('rejects non-object metadata before database work', async () => { const { POST } = await import('./route.js'); const request = {