Skip to content

Commit 2e6f23a

Browse files
authored
fix(api): enhance sendAccountRouter to validate user and tag ownership for setting main tag, improving error handling and security (#1620)
1 parent 58ba648 commit 2e6f23a

File tree

1 file changed

+42
-23
lines changed

1 file changed

+42
-23
lines changed

packages/api/src/routers/sendAccount.ts

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -459,36 +459,55 @@ export const sendAccountRouter = createTRPCRouter({
459459
})
460460
)
461461
.mutation(async ({ ctx: { supabase }, input: { tagId } }) => {
462-
// Leverage RLS - just try to update and let the database constraints and triggers handle validation
463-
const { data: result, error } = await supabase
462+
const { data: profile } = await supabase.auth.getUser()
463+
if (!profile.user) throw new TRPCError({ code: 'UNAUTHORIZED' })
464+
465+
// Get user's send account
466+
const { data: sendAccount, error: sendAccountError } = await supabase
464467
.from('send_accounts')
465-
.update({ main_tag_id: tagId })
466-
.select()
468+
.select('id')
469+
.eq('user_id', profile.user.id)
467470
.single()
468471

469-
if (error) {
470-
// Handle specific database errors with meaningful messages
471-
if (error.code === 'PGRST116') {
472-
throw new TRPCError({
473-
code: 'NOT_FOUND',
474-
message: 'Send account not found',
475-
})
476-
}
472+
if (sendAccountError || !sendAccount) {
473+
throw new TRPCError({
474+
code: 'NOT_FOUND',
475+
message: 'Send account not found',
476+
})
477+
}
477478

478-
if (
479-
error.message?.includes('foreign key constraint') ||
480-
error.message?.includes('main_tag')
481-
) {
482-
throw new TRPCError({
483-
code: 'BAD_REQUEST',
484-
message: 'Tag not found or not confirmed for this account',
485-
})
486-
}
479+
// Validate tag exists and belongs to user
480+
const { data: tagOwnership, error: tagError } = await supabase
481+
.from('send_account_tags')
482+
.select(`
483+
send_account_tags!inner(*),
484+
tags!inner(id, status)
485+
`)
486+
.eq('send_account_id', sendAccount.id)
487+
.eq('tag_id', tagId)
488+
.eq('tags.status', 'confirmed') // Must be confirmed
489+
.single()
490+
491+
if (tagError || !tagOwnership) {
492+
throw new TRPCError({
493+
code: 'BAD_REQUEST',
494+
message: 'Tag not found or not confirmed for this send account',
495+
})
496+
}
497+
498+
// Update main tag
499+
const { data: result, error: updateError } = await supabase
500+
.from('send_accounts')
501+
.update({ main_tag_id: tagId })
502+
.eq('id', sendAccount.id)
503+
.select()
504+
.single()
487505

488-
console.error('Error updating main tag:', error)
506+
if (updateError) {
507+
console.error('Error updating main tag:', updateError)
489508
throw new TRPCError({
490509
code: 'INTERNAL_SERVER_ERROR',
491-
message: error.message,
510+
message: updateError.message,
492511
})
493512
}
494513

0 commit comments

Comments
 (0)