diff --git a/src/app/api/crypto/public-keys/route.js b/src/app/api/crypto/public-keys/route.js index 618c7276..011aa8d0 100644 --- a/src/app/api/crypto/public-keys/route.js +++ b/src/app/api/crypto/public-keys/route.js @@ -99,17 +99,17 @@ async function authenticateUser(request) { export async function GET(request) { const url = new URL(request.url); try { + const userId = url.searchParams.get('user_id')?.trim(); + if (!userId) { + return NextResponse.json({ error: 'Missing user_id parameter' }, { status: 400 }); + } + // Authenticate user const { user, error: authError } = await authenticateUser(request); if (authError || !user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } - const userId = url.searchParams.get('user_id'); - if (!userId) { - return NextResponse.json({ error: 'Missing user_id parameter' }, { status: 400 }); - } - // Get the user's auth_user_id from the internal user ID const { data: userData, error: userError } = await getServiceRoleClient() .from('users') diff --git a/src/app/api/crypto/public-keys/route.test.js b/src/app/api/crypto/public-keys/route.test.js index 277d25b7..9504097f 100644 --- a/src/app/api/crypto/public-keys/route.test.js +++ b/src/app/api/crypto/public-keys/route.test.js @@ -3,6 +3,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; const mocks = vi.hoisted(() => ({ authGetUser: vi.fn(), serviceFrom: vi.fn(), + userEq: vi.fn(), rpc: vi.fn() })); @@ -32,7 +33,7 @@ function createUsersQuery() { selected = fields; return query; }), - eq: vi.fn(() => query), + eq: mocks.userEq, single: vi.fn(() => { if (selected.includes('id, auth_user_id')) { return Promise.resolve({ @@ -46,6 +47,7 @@ function createUsersQuery() { }); }) }; + mocks.userEq.mockReturnValue(query); return query; } @@ -82,4 +84,36 @@ describe('public key cookie authentication', () => { expect(body).toEqual({ public_key: 'public-key', user_id: 'target-user-id' }); expect(mocks.authGetUser).toHaveBeenCalledWith('access-token'); }); + + it('trims user_id before public key lookup and response', async () => { + const { GET } = await import('./route.js'); + const response = await GET( + new Request('https://qrypt.chat/api/crypto/public-keys?user_id=%20target-user-id%20', { + headers: { + cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('access-token')}` + } + }) + ); + const body = await response.json(); + + expect(response.status).toBe(200); + expect(body).toEqual({ public_key: 'public-key', user_id: 'target-user-id' }); + expect(mocks.userEq).toHaveBeenCalledWith('id', 'target-user-id'); + }); + + it('rejects blank user_id before public key lookup', async () => { + const { GET } = await import('./route.js'); + const response = await GET( + new Request('https://qrypt.chat/api/crypto/public-keys?user_id=%20%20', { + headers: { + cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('access-token')}` + } + }) + ); + const body = await response.json(); + + expect(response.status).toBe(400); + expect(body).toEqual({ error: 'Missing user_id parameter' }); + expect(mocks.serviceFrom).not.toHaveBeenCalled(); + }); });