77 updateAccountSchema ,
88 updateAccountOrderSchema ,
99} from '../middleware/validation.js' ;
10+ import { sensitiveRateLimiter } from '../middleware/rate-limit.js' ;
1011
1112const router = Router ( ) ;
1213
@@ -315,37 +316,42 @@ router.post('/', validate(createAccountSchema), (req, res) => {
315316 * 400:
316317 * description: Invalid request data
317318 */
318- router . patch ( '/order' , validate ( updateAccountOrderSchema ) , ( req , res ) => {
319- try {
320- const { accountIds } = req . body ;
321- const profileId = getEffectiveProfileId ( req ) ;
322-
323- // Verify all accounts belong to this profile before updating
324- for ( const accountId of accountIds ) {
325- if ( ! verifyAccountProfile ( accountId , profileId ) ) {
326- return res . status ( 403 ) . json ( {
327- success : false ,
328- error : 'Access denied: account does not belong to this profile' ,
329- } ) ;
319+ router . patch (
320+ '/order' ,
321+ sensitiveRateLimiter ,
322+ validate ( updateAccountOrderSchema ) ,
323+ ( req , res ) => {
324+ try {
325+ const { accountIds } = req . body ;
326+ const profileId = getEffectiveProfileId ( req ) ;
327+
328+ // Verify all accounts belong to this profile before updating
329+ for ( const accountId of accountIds ) {
330+ if ( ! verifyAccountProfile ( accountId , profileId ) ) {
331+ return res . status ( 403 ) . json ( {
332+ success : false ,
333+ error : 'Access denied: account does not belong to this profile' ,
334+ } ) ;
335+ }
330336 }
331- }
332337
333- // Update order_index for each account
334- accountIds . forEach ( ( accountId : number , index : number ) => {
335- run (
336- 'UPDATE accounts SET order_index = ? WHERE id = ? AND profile_id = ?' ,
337- [ index , accountId , profileId ]
338- ) ;
339- } ) ;
338+ // Update order_index for each account
339+ accountIds . forEach ( ( accountId : number , index : number ) => {
340+ run (
341+ 'UPDATE accounts SET order_index = ? WHERE id = ? AND profile_id = ?' ,
342+ [ index , accountId , profileId ]
343+ ) ;
344+ } ) ;
340345
341- res . json ( { success : true } ) ;
342- } catch ( error ) {
343- console . error ( 'Error updating account order:' , error ) ;
344- res
345- . status ( 500 )
346- . json ( { success : false , error : 'Failed to update account order' } ) ;
346+ res . json ( { success : true } ) ;
347+ } catch ( error ) {
348+ console . error ( 'Error updating account order:' , error ) ;
349+ res
350+ . status ( 500 )
351+ . json ( { success : false , error : 'Failed to update account order' } ) ;
352+ }
347353 }
348- } ) ;
354+ ) ;
349355
350356/**
351357 * @swagger
@@ -382,52 +388,59 @@ router.patch('/order', validate(updateAccountOrderSchema), (req, res) => {
382388 * 403:
383389 * description: Access denied
384390 */
385- router . patch ( '/:id' , validate ( updateAccountSchema ) , ( req , res ) => {
386- try {
387- const id = parseInt ( req . params . id ) ;
388- const profileId = getEffectiveProfileId ( req ) ;
389- const { name, type, currentBalance } = req . body ;
390-
391- // Verify account belongs to this profile
392- if ( ! verifyAccountProfile ( id , profileId ) ) {
393- return res . status ( 403 ) . json ( {
394- success : false ,
395- error : 'Access denied: account does not belong to this profile' ,
396- } ) ;
397- }
391+ router . patch (
392+ '/:id' ,
393+ sensitiveRateLimiter ,
394+ validate ( updateAccountSchema ) ,
395+ ( req , res ) => {
396+ try {
397+ const id = parseInt ( req . params . id ) ;
398+ const profileId = getEffectiveProfileId ( req ) ;
399+ const { name, type, currentBalance } = req . body ;
400+
401+ // Verify account belongs to this profile
402+ if ( ! verifyAccountProfile ( id , profileId ) ) {
403+ return res . status ( 403 ) . json ( {
404+ success : false ,
405+ error : 'Access denied: account does not belong to this profile' ,
406+ } ) ;
407+ }
398408
399- const updates : string [ ] = [ ] ;
400- const params : unknown [ ] = [ ] ;
409+ const updates : string [ ] = [ ] ;
410+ const params : unknown [ ] = [ ] ;
401411
402- if ( name !== undefined ) {
403- updates . push ( 'name = ?' ) ;
404- params . push ( name ) ;
405- }
412+ if ( name !== undefined ) {
413+ updates . push ( 'name = ?' ) ;
414+ params . push ( name ) ;
415+ }
406416
407- if ( type !== undefined ) {
408- updates . push ( 'type = ?' ) ;
409- params . push ( type ) ;
410- }
417+ if ( type !== undefined ) {
418+ updates . push ( 'type = ?' ) ;
419+ params . push ( type ) ;
420+ }
411421
412- if ( currentBalance !== undefined ) {
413- updates . push ( 'current_balance = ?' ) ;
414- params . push ( currentBalance ) ;
415- }
422+ if ( currentBalance !== undefined ) {
423+ updates . push ( 'current_balance = ?' ) ;
424+ params . push ( currentBalance ) ;
425+ }
416426
417- // Schema ensures at least one field is present
418- params . push ( id ) ;
419- params . push ( profileId ) ;
420- run (
421- `UPDATE accounts SET ${ updates . join ( ', ' ) } WHERE id = ? AND profile_id = ?` ,
422- params
423- ) ;
427+ // Schema ensures at least one field is present
428+ params . push ( id ) ;
429+ params . push ( profileId ) ;
430+ run (
431+ `UPDATE accounts SET ${ updates . join ( ', ' ) } WHERE id = ? AND profile_id = ?` ,
432+ params
433+ ) ;
424434
425- res . json ( { success : true } ) ;
426- } catch ( error ) {
427- console . error ( 'Error updating account:' , error ) ;
428- res . status ( 500 ) . json ( { success : false , error : 'Failed to update account' } ) ;
435+ res . json ( { success : true } ) ;
436+ } catch ( error ) {
437+ console . error ( 'Error updating account:' , error ) ;
438+ res
439+ . status ( 500 )
440+ . json ( { success : false , error : 'Failed to update account' } ) ;
441+ }
429442 }
430- } ) ;
443+ ) ;
431444
432445/**
433446 * @swagger
@@ -452,7 +465,7 @@ router.patch('/:id', validate(updateAccountSchema), (req, res) => {
452465 * 403:
453466 * description: Access denied
454467 */
455- router . delete ( '/:id' , ( req , res ) => {
468+ router . delete ( '/:id' , sensitiveRateLimiter , ( req , res ) => {
456469 try {
457470 const id = parseInt ( req . params . id ) ;
458471 const profileId = getEffectiveProfileId ( req ) ;
@@ -521,7 +534,7 @@ router.delete('/:id', (req, res) => {
521534 * 404:
522535 * description: Account not found
523536 */
524- router . post ( '/:id/recalculate-balance' , ( req , res ) => {
537+ router . post ( '/:id/recalculate-balance' , sensitiveRateLimiter , ( req , res ) => {
525538 try {
526539 const id = parseInt ( req . params . id ) ;
527540 const profileId = getEffectiveProfileId ( req ) ;
0 commit comments