Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 19 additions & 14 deletions src/app/api/files/upload-url/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@ export async function POST(request, { params } = {}) {
encryptedMetadata
} = parsedBody.body;

// Validate inputs before profile/conversation lookups
if (!conversationId || !messageId || !encryptedMetadata) {
console.error('UPLOAD-URL: Missing required fields');
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
}

if (typeof encryptedMetadata !== 'object' || Array.isArray(encryptedMetadata)) {
console.error('UPLOAD-URL: Invalid encrypted metadata');
return NextResponse.json({ error: 'Invalid encrypted metadata' }, { status: 400 });
}

// Extract one encrypted copy to get file size for validation
// We can't decrypt it, but we can get the size from any user's copy
const firstUserId = Object.keys(encryptedMetadata)[0];
if (!firstUserId) {
console.error('UPLOAD-URL: No encrypted metadata found');
return NextResponse.json({ error: 'Invalid encrypted metadata' }, { status: 400 });
}

// Get the internal user ID from the users table using auth_user_id
const { data: internalUser, error: userError } = await supabase
.from('users')
Expand All @@ -56,20 +75,6 @@ export async function POST(request, { params } = {}) {
const userId = internalUser.id;
console.log(`📁 [UPLOAD-URL] Using internal user ID: ${userId}`);

// Validate inputs
if (!conversationId || !messageId || !encryptedMetadata) {
console.error( '📁 [UPLOAD-URL] Missing required fields');
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
}

// Extract one encrypted copy to get file size for validation
// We can't decrypt it, but we can get the size from any user's copy
const firstUserId = Object.keys(encryptedMetadata)[0];
if (!firstUserId) {
console.error( '📁 [UPLOAD-URL] No encrypted metadata found');
return NextResponse.json({ error: 'Invalid encrypted metadata' }, { status: 400 });
}

// Validate user has access to the conversation
const { data: participant, error: participantError } = await supabase
.from('conversation_participants')
Expand Down
18 changes: 18 additions & 0 deletions src/app/api/files/upload-url/route.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,22 @@ describe('POST /api/files/upload-url validation', () => {
expect(body.error).toBe('Request body must be a JSON object');
expect(mocks.from).not.toHaveBeenCalled();
});

it('rejects non-object encrypted metadata before database work', async () => {
const { POST } = await import('./route.js');
const request = {
json: vi.fn().mockResolvedValue({
conversationId: 'conversation-1',
messageId: 'message-1',
encryptedMetadata: 'not-a-recipient-map'
})
};

const response = await POST(request);
const body = await response.json();

expect(response.status).toBe(400);
expect(body.error).toBe('Invalid encrypted metadata');
expect(mocks.from).not.toHaveBeenCalled();
});
});
Loading