From 4ee009a730c80d94eb05992315e9427f288374cf Mon Sep 17 00:00:00 2001 From: OpenClaw Date: Fri, 6 Mar 2026 17:44:32 +0000 Subject: [PATCH] auto(agent): Improved error handling and input validation in addresses.js --- backend/src/routes/addresses.js | 189 ++++++++++++++++++++------------ 1 file changed, 116 insertions(+), 73 deletions(-) diff --git a/backend/src/routes/addresses.js b/backend/src/routes/addresses.js index ff5c8ee..5be09fa 100644 --- a/backend/src/routes/addresses.js +++ b/backend/src/routes/addresses.js @@ -9,100 +9,143 @@ const router = Router(); const hashCode = (code) => createHash('sha256').update(code).digest('hex'); +// Schema for change request validation +const changeRequestSchema = z.object({ + newAddress: z.string().min(10).max(500) +}); + +// Schema for verification request validation +const verifyRequestSchema = z.object({ + requestId: z.number().int().positive(), + code: z.string().regex(/^\d{6}$/) +}); + router.post('/change-request', requireAuth, async (req, res) => { - const parsed = z.object({ newAddress: z.string().min(10).max(500) }).safeParse(req.body); - if (!parsed.success) return res.status(400).json({ error: parsed.error.flatten() }); - - // Check if user already has an address try { - const [existingRows] = await pool.query( - `SELECT id FROM addresses WHERE user_id = ? LIMIT 1`, - [req.user.userId] - ); + const parsed = changeRequestSchema.safeParse(req.body); + if (!parsed.success) { + return res.status(400).json({ + error: 'Invalid input data', + details: parsed.error.flatten() + }); + } - if (existingRows.length === 0) { - return res.status(400).json({ error: 'User must have an existing address to request a change' }); + // Check if user already has an address + try { + const [existingRows] = await pool.query( + `SELECT id FROM addresses WHERE user_id = ? LIMIT 1`, + [req.user.userId] + ); + + if (existingRows.length === 0) { + return res.status(400).json({ + error: 'User must have an existing address to request a change' + }); + } + } catch (err) { + console.error('Error checking existing address:', err); + return res.status(500).json({ + error: 'Internal server error while checking existing address' + }); + } + + const verificationCode = String(randomInt(100000, 999999)); + const verificationCodeHash = hashCode(verificationCode); + + try { + const [result] = await pool.query( + `INSERT INTO address_change_requests (user_id, new_address_encrypted, verification_code_hash) + VALUES (?, ?, ?)`, + [req.user.userId, encryptText(parsed.data.newAddress), verificationCodeHash] + ); + + res.status(201).json({ + requestId: result.insertId, + postalDispatch: 'pending_letter', + note: 'Verification code generated for postal letter dispatch.', + verificationCode + }); + } catch (err) { + console.error('Error in address change request:', err); + return res.status(500).json({ + error: 'Internal server error while processing address change request' + }); } } catch (err) { - console.error('Error checking existing address:', err); - return res.status(500).json({ error: 'Internal server error' }); - } - - const verificationCode = String(randomInt(100000, 999999)); - const verificationCodeHash = hashCode(verificationCode); - - try { - const [result] = await pool.query( - `INSERT INTO address_change_requests (user_id, new_address_encrypted, verification_code_hash) - VALUES (?, ?, ?)`, - [req.user.userId, encryptText(parsed.data.newAddress), verificationCodeHash] - ); - - res.status(201).json({ - requestId: result.insertId, - postalDispatch: 'pending_letter', - note: 'Verification code generated for postal letter dispatch.', - verificationCode + console.error('Unexpected error in change-request route:', err); + return res.status(500).json({ + error: 'Unexpected internal server error' }); - } catch (err) { - console.error('Error in address change request:', err); - return res.status(500).json({ error: 'Internal server error' }); } }); router.post('/verify', requireAuth, async (req, res) => { - const parsed = z.object({ requestId: z.number().int().positive(), code: z.string().regex(/^\d{6}$/) }).safeParse(req.body); - if (!parsed.success) return res.status(400).json({ error: parsed.error.flatten() }); - - const { requestId, code } = parsed.data; - try { - const [rows] = await pool.query( - `SELECT id, user_id, new_address_encrypted, verification_code_hash, status - FROM address_change_requests - WHERE id = ? LIMIT 1`, - [requestId] - ); - - const request = rows[0]; - if (!request) return res.status(404).json({ error: 'Request not found' }); - if (request.user_id !== req.user.userId) return res.status(403).json({ error: 'Forbidden' }); - if (request.status !== 'pending_letter') return res.status(409).json({ error: 'Request not pending' }); - - if (hashCode(code) !== request.verification_code_hash) { - return res.status(400).json({ error: 'Invalid verification code' }); + const parsed = verifyRequestSchema.safeParse(req.body); + if (!parsed.success) { + return res.status(400).json({ + error: 'Invalid input data', + details: parsed.error.flatten() + }); } - const conn = await pool.getConnection(); - try { - await conn.beginTransaction(); + const { requestId, code } = parsed.data; - await conn.query( - `UPDATE address_change_requests - SET status = 'verified', verified_at = CURRENT_TIMESTAMP - WHERE id = ?`, + try { + const [rows] = await pool.query( + `SELECT id, user_id, new_address_encrypted, verification_code_hash, status + FROM address_change_requests + WHERE id = ? LIMIT 1`, [requestId] ); - await conn.query( - `INSERT INTO addresses (user_id, address_encrypted, postal_verified_at) - VALUES (?, ?, CURRENT_TIMESTAMP)`, - [req.user.userId, request.new_address_encrypted] - ); + const request = rows[0]; + if (!request) return res.status(404).json({ error: 'Request not found' }); + if (request.user_id !== req.user.userId) return res.status(403).json({ error: 'Forbidden' }); + if (request.status !== 'pending_letter') return res.status(409).json({ error: 'Request not pending' }); - await conn.commit(); + if (hashCode(code) !== request.verification_code_hash) { + return res.status(400).json({ error: 'Invalid verification code' }); + } + + const conn = await pool.getConnection(); + try { + await conn.beginTransaction(); + + await conn.query( + `UPDATE address_change_requests + SET status = 'verified', verified_at = CURRENT_TIMESTAMP + WHERE id = ?`, + [requestId] + ); + + await conn.query( + `INSERT INTO addresses (user_id, address_encrypted, postal_verified_at) + VALUES (?, ?, CURRENT_TIMESTAMP)`, + [req.user.userId, request.new_address_encrypted] + ); + + await conn.commit(); + } catch (err) { + await conn.rollback(); + console.error('Error in address verification transaction:', err); + throw err; + } finally { + conn.release(); + } + + res.json({ status: 'verified' }); } catch (err) { - await conn.rollback(); - console.error('Error in address verification transaction:', err); - throw err; - } finally { - conn.release(); + console.error('Error in address verification:', err); + return res.status(500).json({ + error: 'Internal server error while verifying address' + }); } - - res.json({ status: 'verified' }); } catch (err) { - console.error('Error in address verification:', err); - return res.status(500).json({ error: 'Internal server error' }); + console.error('Unexpected error in verify route:', err); + return res.status(500).json({ + error: 'Unexpected internal server error' + }); } });